public Collection<? extends Processor> resolveProcessors(boolean onScan) { ClassPath[] pps = validatePaths(); ClassLoader cl; boolean isModule = false; final ClassLoaderRef cache = classLoaderCache; if (cache == null || (cl=cache.get(root)) == null) { ClassPath pp = pps[1]; if (pps[0] != null && !pps[0].entries().isEmpty()) { pp = pps[0]; isModule = true; } if (pp == null) { pp = ClassPath.EMPTY; } cl = CachingArchiveClassLoader.forClassPath( pp, new BypassOpenIDEUtilClassLoader(Context.class.getClassLoader()), usedRoots); classLoaderCache = !DISABLE_CLASSLOADER_CACHE ? new ClassLoaderRef(cl, root, isModule) : null; } else { isModule = cache.isModule; } Collection<Processor> result = lookupProcessors(cl, onScan, isModule); return result; }
private Collection<Processor> lookupProcessors(ClassLoader cl, boolean onScan, boolean isModule) { Iterable<? extends String> processorNames = aptOptions.annotationProcessorsToRun(); if (processorNames == null) { processorNames = getProcessorNames(cl, isModule); } List<Processor> result = new LinkedList<Processor>(); for (String name : processorNames) { try { Class<?> clazz = Class.forName(name, true, cl); Object instance = clazz.newInstance(); if (instance instanceof Processor) { result.add((Processor) instance); } } catch (ThreadDeath td) { throw td; } catch (Throwable t) { LOG.log(Level.FINE, null, t); } } if (!onScan) result.addAll(HARDCODED_PROCESSORS.lookupAll(Processor.class)); return result; }
/** * Check if we should process annotations. * If so, and if no scanner is yet registered, then set up the DocCommentScanner * to catch doc comments, and set keepComments so the parser records them in * the compilation unit. * * @param processors user provided annotation processors to bypass * discovery, {@code null} means that no processors were provided */ public void initProcessAnnotations(Iterable<? extends Processor> processors) { // Process annotations if processing is not disabled and there // is at least one Processor available. if (options.isSet(PROC, "none")) { processAnnotations = false; } else if (procEnvImpl == null) { procEnvImpl = JavacProcessingEnvironment.instance(context); procEnvImpl.setProcessors(processors); processAnnotations = procEnvImpl.atLeastOneProcessor(); if (processAnnotations) { options.put("save-parameter-names", "save-parameter-names"); reader.saveParameterNames = true; keepComments = true; genEndPos = true; if (!taskListener.isEmpty()) taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING)); deferredDiagnosticHandler = new Log.DeferredDiagnosticHandler(log); } else { // free resources procEnvImpl.close(); } } }
@Override public List<PluginInfo<Processor>> getAnnotationProcessors() { return Arrays.asList(new PluginInfo<Processor>() { @Override public String getName() { return "test"; } @Override public Map<String, String> getOptions() { return Collections.singletonMap("testAPKey", "testAPValue"); } @Override public Processor getPlugin() { return new ProcessorImpl(); } }); }
static private boolean compile(Iterable<? extends Processor> processors) { JavaCompiler compiler = new EclipseCompiler(); DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>(); JavaFileManager fileManager = compiler.getStandardFileManager(diagnosticCollector, Locale.getDefault(), UTF_8); JavaCompiler.CompilationTask task = compiler.getTask( null, fileManager, diagnosticCollector, ImmutableSet.<String>of(), ImmutableSet.of(TestTypesEclipse.class.getCanonicalName()), ImmutableSet.<JavaFileObject>of()); task.setProcessors(processors); return task.call(); }
/** Convenient JavaCompiler facade returning a ClassLoader with all compiled units. */ static ClassLoader compile( ClassLoader parent, List<String> options, List<Processor> processors, List<JavaFileObject> units) { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); Objects.requireNonNull(compiler, "no system java compiler available - JDK is required!"); DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); StandardJavaFileManager sjfm = compiler.getStandardFileManager(diagnostics, Locale.getDefault(), StandardCharsets.UTF_8); Manager manager = new Manager(sjfm, parent); CompilationTask task = compiler.getTask(null, manager, diagnostics, options, null, units); if (!processors.isEmpty()) { task.setProcessors(processors); } boolean success = task.call(); if (!success) { throw new RuntimeException("compilation failed! " + diagnostics.getDiagnostics()); } return manager.getClassLoader(StandardLocation.CLASS_PATH); }
/** * Assumes the element is valid. It uses the value specified in the annotation, if it has a package. Otherwise uses * the element's package. * @param element annotated interface, assumed valid * @param types type utility, currently ignored * @return a representation of the generated class. */ @Override protected GeneratedType createGeneratedClass(EnrichedTypeElement element, Class<? extends Processor> processorClass, Types types) { final String specifiedClass = element.getAnnotation(getSupportedAnnotation()).value(); final Pair<String, String> packageAndClassName = extractPackageAndClassName(specifiedClass); String packageName = packageAndClassName.getLeft(); if (packageName == null) { final PackageElement elementPackage = element.getPackage(); packageName = elementPackage.getQualifiedName().toString(); } String className = packageAndClassName.getRight(); if (className == null) { className = element.calculateClassNameWithPrefix(getClassPrefix()); } return new NoopClass(packageName, className, element, processorClass, types); }
/** * Assumes the element is valid. It uses the value specified in the annotation, if it has a package. Otherwise uses * the element's package. * @param element annotated interface, assumed valid * @return a representation of the generated class. */ @Override protected GeneratedType createGeneratedClass(EnrichedTypeElement element, Class<? extends Processor> processorClass, Types types) { final String specifiedClass = element.getAnnotation(getSupportedAnnotation()).value(); final Pair<String, String> packageAndClassName = extractPackageAndClassName(specifiedClass); String packageName = packageAndClassName.getLeft(); if (packageName == null) { final PackageElement elementPackage = element.getPackage(); packageName = elementPackage.getQualifiedName().toString(); } String className = packageAndClassName.getRight(); if (className == null) { className = element.calculateClassNameWithPrefix(getClassPrefix()); } return new DecorClass(packageName, className, element, processorClass, types, element.getAnnotation(getSupportedAnnotation()).mutable()); }
/** * Assumes the element is valid. It uses the value specified in the annotation, if it has a package. Otherwise uses * the element's package. * @param element annotated interface, assumed valid * @param types type utility, currently ignored * @return a representation of the generated class. */ @Override protected GeneratedType createGeneratedClass(EnrichedTypeElement element, Class<? extends Processor> processorClass, Types types) { final String specifiedClass = element.getAnnotation(getSupportedAnnotation()).value(); final Pair<String, String> packageAndClassName = extractPackageAndClassName(specifiedClass); String packageName = packageAndClassName.getLeft(); if (packageName == null) { final PackageElement elementPackage = element.getPackage(); packageName = elementPackage.getQualifiedName().toString(); } String className = packageAndClassName.getRight(); if (className == null) { className = element.calculateClassNameWithSuffix(getClassSuffix()); } return new FactoryInterface(packageName, className, element, processorClass); }
/** * Check if we should process annotations. * If so, and if no scanner is yet registered, then set up the DocCommentScanner * to catch doc comments, and set keepComments so the parser records them in * the compilation unit. * * @param processors user provided annotation processors to bypass * discovery, {@code null} means that no processors were provided */ public void initProcessAnnotations(Iterable<? extends Processor> processors) { // Process annotations if processing is not disabled and there // is at least one Processor available. Options options = Options.instance(context); if (options.get("-proc:none") != null) { processAnnotations = false; } else if (procEnvImpl == null) { procEnvImpl = new JavacProcessingEnvironment(context, processors); processAnnotations = procEnvImpl.atLeastOneProcessor(); if (processAnnotations) { if (context.get(Scanner.Factory.scannerFactoryKey) == null) DocCommentScanner.Factory.preRegister(context); options.put("save-parameter-names", "save-parameter-names"); reader.saveParameterNames = true; keepComments = true; if (taskListener != null) taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING)); } else { // free resources procEnvImpl.close(); } } }
static ClassLoader compile(JavaFile java, ClassLoader parent, List<String> options, List<Processor> processors) { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); assert compiler != null : "no system java compiler available - JDK is required!"; DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); StandardJavaFileManager sjfm = compiler.getStandardFileManager( diagnostics, Locale.getDefault(), StandardCharsets.UTF_8); Manager manager = new Manager(sjfm, parent); CompilationTask task = compiler.getTask( null, // a writer for additional output from the compiler; use System.err if null manager, diagnostics, options, null, // names of classes to be processed by annotation processing, null means no classes Collections.singleton(java.toJavaFileObject())); if (!processors.isEmpty()) task.setProcessors(processors); boolean success = task.call(); if (!success) throw new RuntimeException("compilation failed" + diagnostics.getDiagnostics()); return manager.getClassLoader(null); }
@Override public void setProcessors(Object[] processors) { if (!_isFirstRound) { throw new IllegalStateException("setProcessors() cannot be called after processing has begun"); //$NON-NLS-1$ } // Cast all the processors here, rather than failing later. // But don't call init() until the processor is actually needed. _setProcessors = new ArrayList<Processor>(processors.length); for (Object o : processors) { Processor p = (Processor)o; _setProcessors.add(p); } _setProcessorIter = _setProcessors.iterator(); // processors set this way take precedence over anything on the command line _commandLineProcessors = null; _commandLineProcessorIter = null; }
public Result run( String[] args, JavaFileManager fileManager, List<JavaFileObject> javaFileObjects, Iterable<? extends Processor> processors) { JavaCompiler compiler = new BaseErrorProneJavaCompiler(scannerSupplier); try { CompilationTask task = compiler.getTask( errOutput, fileManager, diagnosticListener, ImmutableList.copyOf(args), null /*classes*/, javaFileObjects); if (processors != null) { task.setProcessors(processors); } return task.call() ? Result.OK : Result.ERROR; } catch (InvalidCommandLineOptionException e) { errOutput.print(e); errOutput.flush(); return Result.CMDERR; } }
/** * Check if we should process annotations. * If so, and if no scanner is yet registered, then set up the DocCommentScanner * to catch doc comments, and set keepComments so the parser records them in * the compilation unit. * * @param processors user provided annotation processors to bypass * discovery, {@code null} means that no processors were provided */ public void initProcessAnnotations(Iterable<? extends Processor> processors) { // Process annotations if processing is not disabled and there // is at least one Processor available. if (options.isSet(PROC, "none")) { processAnnotations = false; } else if (procEnvImpl == null) { procEnvImpl = new JavacProcessingEnvironment(context, processors); processAnnotations = procEnvImpl.atLeastOneProcessor(); if (processAnnotations) { options.put("save-parameter-names", "save-parameter-names"); reader.saveParameterNames = true; keepComments = true; genEndPos = true; if (taskListener != null) taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING)); log.deferDiagnostics = true; } else { // free resources procEnvImpl.close(); } } }
public boolean compile(File... sourceFiles) throws Exception { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fm = compiler.getStandardFileManager(diagnosticListener, null, null); if (classOutput == null) { classOutput = createTempDir(); } if (sourceOutput == null) { sourceOutput = createTempDir(); } fm.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singletonList(classOutput)); fm.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singletonList(sourceOutput)); Iterable<? extends JavaFileObject> fileObjects = fm.getJavaFileObjects(sourceFiles); Writer out = new NullWriter(); JavaCompiler.CompilationTask task = compiler.getTask(out, fm, diagnosticListener, options, null, fileObjects); List<Processor> processors = Collections.<Processor>singletonList(processor); task.setProcessors(processors); try { return task.call(); } catch (RuntimeException e) { if (e.getCause() != null && e.getCause() instanceof RuntimeException) { throw (RuntimeException)e.getCause(); } else { throw e; } } }
/** Sets the compilation's annotation processors. */ private static void setProcessors( OptionsParser optionsParser, StandardJavaFileManager fileManager, CompilationTask task) { ClassLoader processorLoader = fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH); Builder<Processor> processors = ImmutableList.builder(); for (String processor : optionsParser.getProcessorNames()) { try { processors.add( (Processor) processorLoader.loadClass(processor).getConstructor().newInstance()); } catch (ReflectiveOperationException e) { throw new LinkageError(e.getMessage(), e); } } task.setProcessors(processors.build()); }
@Override public ProcessorInfo discoverNextProcessor() { if (processors.hasNext()) { Processor processor = processors.next(); processor.init(_processingEnv); ProcessorInfo procecssorInfo = new ProcessorInfo(processor) { // the goal is to notify incrementalCompiler when annotation processing is taking place // as of jdt.apt 1.3.0 this method is called right before running an annotation processor // which is close enough to what we need @Override public boolean computeSupportedAnnotations(Set<TypeElement> annotations, Set<TypeElement> result) { boolean shouldCall = super.computeSupportedAnnotations(annotations, result); if (shouldCall) { incrementalCompiler.onAnnotationProcessing(); } return shouldCall; } }; _processors.add(procecssorInfo); // TODO this needs to happen in RoundDispatcher.round() return procecssorInfo; } return null; }
private Path compileToJar( SortedSet<Path> classpath, List<Processor> processors, List<String> additionalOptions, DeterministicManifest manifest, String fileName, String source, File outputDir) throws IOException { try (TestCompiler compiler = new TestCompiler()) { compiler.init(); compiler.addCompilerOptions(additionalOptions); if (manifest != null) { compiler.setManifest(manifest); } compiler.addSourceFileContents(fileName, source); compiler.addClasspath(classpath); compiler.setProcessors(processors); compiler.compile(); Path jarPath = outputDir.toPath().resolve("output.jar"); compiler.getClasses().createJar(jarPath, false); return jarPath; } }
/** * Processes the java class specified. This implementation only parses and processes the java classes and does not * fully compile them - i.e. it does not write class files back to the disk. Basically, {@code javac} is called with * {@code -proc:only}. * * @param classToCompile the Java class to compile * @param processor the annotation {@link Processor} to use during compilation * @return a list of {@link Diagnostic} messages emitted during the compilation */ public static List<Diagnostic<? extends JavaFileObject>> compileClass(String classToCompile, Processor processor) throws IOException { DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<JavaFileObject>(); StandardJavaFileManager fileManager = null; try { fileManager = getFileManager(collector); Iterable<? extends JavaFileObject> compilationUnits = getCompilationUnitOfClass(fileManager, classToCompile); CompilationTask task = COMPILER.getTask(null, fileManager, collector, COMPILER_OPTIONS, null, compilationUnits); task.setProcessors(Arrays.asList(processor)); task.call(); return collector.getDiagnostics(); } finally { if (fileManager != null) { fileManager.close(); } } }
@Test public void multipleProcesors() { NoOpProcessor noopProcessor1 = new NoOpProcessor(); NoOpProcessor noopProcessor2 = new NoOpProcessor(); NoOpProcessor noopProcessor3 = new NoOpProcessor(); assertThat(noopProcessor1.invoked).isFalse(); assertThat(noopProcessor2.invoked).isFalse(); assertThat(noopProcessor3.invoked).isFalse(); Processor[] processors = {noopProcessor1, noopProcessor3}; JavaFileObject[] files = {HELLO_WORLD}; Compilation unused = javac() .withProcessors(processors) .withProcessors(noopProcessor1, noopProcessor2) .compile(files); assertThat(noopProcessor1.invoked).isTrue(); assertThat(noopProcessor2.invoked).isTrue(); assertThat(noopProcessor3.invoked).isFalse(); }
public static Processor wrapProcessor(Processor processorToWrap) { if (processorToWrap == null) { throw new IllegalArgumentException("Passed processor must not be null"); } return new AnnotationProcessorWrapper(processorToWrap); }
public static <G extends Processor> Processor wrapProcessor(Class<G> processorTypeToWrap) { if (processorTypeToWrap == null) { throw new IllegalArgumentException("passed type must not be null"); } try { return new AnnotationProcessorWrapper(processorTypeToWrap.newInstance()); } catch (Exception e) { throw new IllegalArgumentException("Cannot instantiate passed Class. Make sure that a NoArg constructor exists and is accessible.", e); } }
private static Processor createClassLoaderDelegate() { try { if (cachedProxyClassLoader == null) { cachedProxyClassLoader = new ProxyClassLoader( ((URLClassLoader) ProxyProcessor.class.getClassLoader()).getURLs(), Thread.currentThread().getContextClassLoader()); } return (Processor) cachedProxyClassLoader.loadClass(DELEGATE_CLASS).newInstance(); } catch (Throwable ex) { throw new RuntimeException(ex); } }
/** * Returns a list of completions for an annotation attribute value suggested by * annotation processors. * * @param info the CompilationInfo used to resolve annotation processors * @param element the element being annotated * @param annotation the (perhaps partial) annotation being applied to the element * @param member the annotation member to return possible completions for * @param userText source code text to be completed * @return suggested completions to the annotation member * * @since 0.57 */ public static List<? extends Completion> getAttributeValueCompletions(CompilationInfo info, Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { List<Completion> completions = new LinkedList<>(); if (info.getPhase().compareTo(Phase.ELEMENTS_RESOLVED) >= 0) { String fqn = ((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName().toString(); Iterable<? extends Processor> processors = JavacParser.ProcessorHolder.instance(info.impl.getJavacTask().getContext()).getProcessors(); if (processors != null) { for (Processor processor : processors) { boolean match = false; for (String sat : processor.getSupportedAnnotationTypes()) { if ("*".equals(sat)) { //NOI18N match = true; break; } else if (sat.endsWith(".*")) { //NOI18N sat = sat.substring(0, sat.length() - 1); if (fqn.startsWith(sat)) { match = true; break; } } else if (fqn.equals(sat)) { match = true; break; } } if (match) { try { for (Completion c : processor.getCompletions(element, annotation, member, userText)) { completions.add(c); } } catch (Exception e) { Logger.getLogger(processor.getClass().getName()).log(Level.INFO, e.getMessage(), e); } } } } } return completions; }
@Test(dataProvider = "processors") public void processorAcceptsAnnotations(Processor p) throws ClassNotFoundException { for (String type : p.getSupportedAnnotationTypes()) { Class<?> clazz = loadType(type); assertTrue(Annotation.class.isAssignableFrom(clazz), "It is annotation: " + clazz); } }
private Processor delegate() { if (delegate == null) { try { delegate = new OptionAnnotationProcessorImpl(); } catch (LinkageError ex) { msg = ex.getMessage(); } } return delegate; }
/** * Programmatic interface for main function. * * @param args The command line parameters. */ public int compile(String[] args, Context context, List<JavaFileObject> fileObjects, Iterable<? extends Processor> processors) { return compile(args, null, context, fileObjects, processors); }
/** * Main method: compile a list of files, return all compiled classes * * @param sourceFileObjects file objects to be compiled * @param classnames class names to process for annotations * @param processors user provided annotation processors to bypass * discovery, {@code null} means that no processors were provided */ public void compile(List<JavaFileObject> sourceFileObjects, List<String> classnames, Iterable<? extends Processor> processors) { if (processors != null && processors.iterator().hasNext()) explicitAnnotationProcessingRequested = true; // as a JavaCompiler can only be used once, throw an exception if // it has been used before. if (hasBeenUsed) throw new AssertionError("attempt to reuse JavaCompiler"); hasBeenUsed = true; // forcibly set the equivalent of -Xlint:-options, so that no further // warnings about command line options are generated from this point on options.put(XLINT_CUSTOM + "-" + LintCategory.OPTIONS.option, "true"); options.remove(XLINT_CUSTOM + LintCategory.OPTIONS.option); start_msec = now(); try { initProcessAnnotations(processors); // These method calls must be chained to avoid memory leaks delegateCompiler = processAnnotations( enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))), classnames); delegateCompiler.compile2(); delegateCompiler.close(); elapsed_msec = delegateCompiler.elapsed_msec; } catch (Abort ex) { if (devVerbose) ex.printStackTrace(System.err); } finally { if (procEnvImpl != null) procEnvImpl.close(); } }