package com.sebastian_daschner.jaxrs_analyzer.analysis.javadoc; import com.sebastian_daschner.jaxrs_analyzer.LogProvider; import com.sebastian_daschner.jaxrs_analyzer.analysis.classes.ContextClassReader; import com.sebastian_daschner.jaxrs_analyzer.model.methods.MethodIdentifier; import com.sebastian_daschner.jaxrs_analyzer.model.results.ClassResult; import com.sebastian_daschner.jaxrs_analyzer.model.results.MethodResult; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.MethodDoc; import java.io.File; import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @author Sebastian Daschner */ public class JavaDocAnalyzer { private static final Map<MethodIdentifier, MethodDoc> METHOD_DOCS = new ConcurrentHashMap<>(); // TODO use class results for POJO / JAXB enhancement private static final Map<String, ClassDoc> CLASS_DOCS = new ConcurrentHashMap<>(); public void analyze(final Set<ClassResult> classResults, final Set<String> packages, final Set<Path> projectSourcePaths, final Set<Path> classPaths) { try { invokeDoclet(packages, projectSourcePaths, classPaths); combineResults(classResults); } catch (Exception e) { LogProvider.error("could not analyze JavaDoc, reason: " + e.getMessage()); LogProvider.debug(e); } } private void invokeDoclet(final Set<String> packages, final Set<Path> projectSourcePaths, final Set<Path> classPaths) throws Exception { final String docletName = "com.sebastian_daschner.jaxrs_analyzer.analysis.javadoc.JAXRSDoclet"; final Class<?> doclet = ContextClassReader.getClassLoader().loadClass(docletName); final String docletPath = Paths.get(doclet.getProtectionDomain().getCodeSource().getLocation().toURI()).toString(); final String encoding = System.getProperty("project.build.sourceEncoding", Charset.defaultCharset().name()); // TODO only invoke on sources visited in visitSource final String[] args = Stream.concat( Stream.of("-sourcepath", joinPaths(projectSourcePaths), "-classpath", joinPaths(classPaths), "-quiet", "-docletpath", docletPath, "-doclet", docletName, "-encoding", encoding ), packages.stream() ).toArray(String[]::new); final Class<?> javaDocMain = ContextClassReader.getClassLoader().loadClass("com.sun.tools.javadoc.Main"); final int result = (int) javaDocMain.getMethod("execute", String[].class).invoke(null, (Object) args); if (result != 0) LogProvider.error("Error in javadoc analysis"); } private String joinPaths(final Set<Path> projectSourcePaths) { return projectSourcePaths.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator)); } private void combineResults(final Set<ClassResult> classResults) { METHOD_DOCS.entrySet().forEach(e -> classResults.stream() .map(c -> findMethodResult(e.getKey(), c)) .filter(Objects::nonNull) .forEach(m -> m.setMethodDoc(e.getValue()))); } private MethodResult findMethodResult(final MethodIdentifier identifier, final ClassResult classResult) { if (classResult.getOriginalClass().equals(identifier.getContainingClass())) return classResult.getMethods().stream() .filter(methodResult -> methodResult.getOriginalMethodSignature().equals(identifier)) .findAny().orElse(null); return classResult.getMethods().stream() .map(MethodResult::getSubResource) .filter(Objects::nonNull) .map(c -> findMethodResult(identifier, c)) .filter(Objects::nonNull) .findAny().orElse(null); } public static void put(final MethodIdentifier identifier, final MethodDoc methodDoc) { METHOD_DOCS.put(identifier, methodDoc); } public static void put(final String className, final ClassDoc classDoc) { CLASS_DOCS.put(className, classDoc); } public static MethodDoc get(final MethodIdentifier identifier) { return METHOD_DOCS.get(identifier); } public static ClassDoc get(final String className) { return CLASS_DOCS.get(className); } }