-processorpath & META-INF/services/javax.annotation.processing.Processor

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

-processorpath & META-INF/services/javax.annotation.processing.Processor

Jesse Glick
I have not seen any mention of how Jigsaw will load 269-compliant annotation processors.

First of all, if the processor is bundled with the annotation(s) it processes, which is common, and registered in ServiceLoader fashion, then you would expect that just
requiring that module would suffice to run the processor on your code. This in fact works today in JDK 6 and 7 if you use javac. Frustratingly, the Processor Javadoc is
evasive on the subject, claiming that it is up to the "tool", and Eclipse's compiler does not honor this convention. [1] It would be nice if 269 + Jigsaw could say
definitively that if module A provides javax.annotation.processing.Processor with some processor impl, then compilation of a module requiring A will run that processor if
there are matching annotations (*).

Second, for cases where it is undesirable or impossible to collocate the processor with its supported annotations, there needs to be some way for a module using the
annotations to explicitly request that this processor be run. -processorpath works in older JDKs, but this is contrary to the style of modulepath. I would expect some
module-info.java declaration such as

  requires processor proc.module.name @ 1.0;

which would produce no runtime dep compiled into module-info.class, and (like -processorpath) would not expose any public types from proc.module.name, but would check
proc.module.name for provided Processor's.

Less commonly, you might need a syntax for invoking particular processors by class name and/or passing processor arguments. Of course you can add -processor/-A to the
javac command line, but this is most suitable when running the processor for some one-off purpose like static analysis. If the processor is needed by the module sources
(for error checking on annotations, generating resources, and/or generating classes) then it would be more appropriate for this configuration to be permanently declared
in module-info.java.


(*) Unlike some service locator frameworks, ServiceLoader is incapable of lazily loading services matching some declarative pattern, which can affect client application
startup time - and in the case of Processor, compilation time. In the NetBeans source base we have around 37 processors registered in SL style, and a single module's
classpath might well contain a dozen or more. Each of these classes must be loaded (possibly triggering loading of related classes) just to call
getSupportedAnnotationTypes, even though this metadata is almost always static and most available processors will not be needed.


[1] https://bugs.eclipse.org/bugs/show_bug.cgi?id=280542
Reply | Threaded
Open this post in threaded view
|

Re: -processorpath & META-INF/services/javax.annotation.processing.Processor

Jesse Glick
A couple of other points on this topic I just thought of.


On 01/24/2012 06:02 AM, Jesse Glick wrote:
> It would be nice if [...when] module A provides javax.annotation.processing.Processor with some processor impl, then compilation of a module requiring A will run that
> processor if there are matching annotations

A longstanding irritation in 269 is that if as a library designer you do supply both an annotation and a matching processor, you have to choose between

1. Include the processor in the same module/JAR/etc. as the annotation (registered in ServiceLoader style). Ensures that everyone using the library (*) runs the processor
automatically. But makes the library a bit larger, and may introduce additional dependencies not used at runtime.

2. Place the processor in a different module. Keeps the library slimmer, but means that users will not have the processor run by default - they would need to check the
documentation of each library they use which defines any annotations and manually configure a processor path, which is unmaintainable when more than a couple of such
libraries are involved.

It would be a valuable improvement to let a library module declare that it has an associated processor module to be used only during compilation. Specifically, any module
requiring that library (incl. indirectly via "requires public") should include the processor module in its processorpath or equivalent. For example:

module lib {
   exports lib;
   requires processor service lib.proc; // syntax??
}
package lib;
public @interface Anno {}

module lib.proc {
   requires lib;
   provides service javax.annotation.processing.Processor with lib.proc.Proc;
}
package lib.proc;
@javax.annotation.processing.SupportedAnnotationTypes("lib.Anno")
public class Proc extends javax.annotation.processing.AbstractProcessor {...}

module user {
   requires lib;
   // "requires processor lib.proc" is implied
}
package user;
// lib.proc.Proc will be run on this:
@lib.Anno class C {}

(There probably needs to be some way of overriding processor discovery, like -proc:none or -processor only.This in current versions of javac.)


Another 269-related consideration is how processors will actually be run in JDK 8 javac. Currently the contents of -processorpath (defaulting to -classpath) are dumped
into a URLClassLoader and then ServiceLoader or the equivalent is used for discovery if -processor is not given. In a modular environment, you would expect each
ProcessingEnvironment to be associated with a transient LoaderPool (?) so that the semantics of the module system - especially dependencies and exported types - are used
for loading processors and their associated classes.

(The Javadoc of ProcessingEnvironment currently says "from the perspective of the running annotation processors, at least the chosen subset of helper classes are viewed
as being loaded by the same class loader"; this would need to be updated to refer to modules.)

TBD how modular javac should behave w.r.t. processors when run on an older JDK, as is the case for bootstrapping the JDK itself. If it knew how to resolve module
dependencies, it could fall back to computing the transitive closure of dependencies of all processor modules and creating a URLClassLoader. But if the JDK does not use
269 internally - or only in higher-level modules that can be built after javac has been bootstrapped - then this may not be an issue.


(*) Except Eclipse users in certain setups, as mentioned in the previous post.