Is annotation processing still an active part of Java 6+, or is it something that has been deprecated/discouraged/obsolesced. If obsolesced, why (why is it no longer needed/useful)? And if it's still extremely useful and "active" (a new Java project developing against the Java 6+ JDK would still benefit from it), please confirm/correct my understanding of how annotation processors are used:
You create your own annotation class, say #MyAnnotation
You mark certain classes, methods, fields, etc. with #MyAnnotation
During the build process, you invoke your custom MyAnnotationProcessor (how?)
The processor scans your classpath for instances of #MyAnnotation
Typically, an annotation processor does dynamic bytecode injection, modifying/enhancing your compiled classes on-the-fly
Correct.
Correct.
Correct. Typically you will extend AbstractProcessor. You specify your MyAnnotationProcessor class using the ServiceLoader pattern - this makes it discoverable to the compiler. The Processor Javadoc contains some information on creating this class.
Correct.
This part is not correct. The annotation processor framework does not give you the ability to modify classes. You will need to use some post-compile process to do this as part of your build. What it does allow you to do is create new files. These may be simple resources, new Java source files (that will subsequently be required and eligible to the annotation processor during the same compile), or Java class files. You may also perform custom checks on source code and write errors to the log (causing the compile to fail).
I hope that addresses your understanding questions.
Related
I may be just looking in the wrong direction but I find the JSE documentation on annotation processing very ... sparse. I want to write an annotation processor which processes annotated String fields and local variables to substitute them with a computed String expression. This should not be too complicated but I'm pretty lost in the Javadoc for javax.annotation.processing.
EDIT: I need to process annotations at compile time because I want to modify the generated code. It should replace annotated constant String expressions with a computed String expression.
This can not be done with a compile time annotation processor. Compile time time annotation processors can only generate new files (and classes) they can not modify existing classes. You can do reflection at runtime but strictly speaking you that is not called annotation processing. Also you won't have access to local variables.
If you're looking on how to write a compile time annotation processor check out https://github.com/pellaton/spring-configuration-validation-processor
Two tools that do this are Project Lombok and DuctileJ. Both of these tools existed at the time the question was originally asked; additional tools now surely exist.
The key idea is to write an annotation processor that traverses and modifies the program's AST (abstract syntax tree) during compilation, before code generation. The compiler won't change the source code on disk, but the generated .class file will reflect the changes that your annotation processor makes.
You may be able to adapt one of these tools to suit your needs, or you could implement your own tool inspired by their implementation techniques.
Compile-time processing has two advantages over class-file processing. One is that the compiler usually has more information than is available from compiled code. Another is that everything happens in one step, during compilation, rather than requiring the developer to run a separate tool to rewrite the .class files after compilation.
Check
Javassist http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
ASM http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
Byteman (for runtime) http://www.jboss.org/byteman/
Can I use java common Annotation like javax.annotation.Resource, javax.annotation.PreDestroy, javax.annotation.security.RolesAllowed in a Servlet class?
Technically, nothing stops you from doing so. You can use that (well, pretty much every other) annotation in any class you want. Of course if the annotation can be applied on that type of Java element (method, field, class). The annotations themselves do not bring any logic or magic in your code. Check the source yourself: you'll see that most of them are nothing but data holders.
Annotations are nothing without processors. The processing can occur at compile time or in a runtime.
Compile time annotation processing can change the source code (simplifying things here) before it is compiled. It can introduce extra behavior, (like null checks) or generate methods (like Lombok's #Getter / #Setter. Compile time annotation are usually removed after processing, they are not present on a runtime.
The annotations you've asked about are different kind - runtime annotations. Obviously, resource injection or role checks cannot be done at compile time. So, they need a processor to take effect too, but that processor must be present on a class-path of a running app. Usually, such processors are provided by an environment you run your application in. In your case, these are Java EE annotation and they require Java EE compatible application server to work. I.e. the magic will happen only if you run your class inside a configured application server, like Glassfish or WebSpere. If you run you application in Tomcat or Jetty (they are web servers) - the annotation won't work, they will be "omitted" because no processors exist to process them.
If a java class loaded at runtime as a bytecode (e.g. via ASM library or other mechanism), is it on a classpath of java? I don't see it.
How to scan all annotations of classes loaded this way, if it's not on the java classpath?
I use google reflections and a custom classloader of a 3-rd party library.
Scanning for classes works as follows:
Reflections reflections = new Reflections(ClasspathHelper.forPackage("com.mypackage",
MyCustomClassLoader),
new SubTypesScanner(), new TypeAnnotationsScanner());
Set<Class<?>> myClasses = reflections.getTypesAnnotatedWith(MyAnnotation.class);
MyAnnotation - is marked as #Retention(RetentionPolicy.RUNTIME).
The above (in a class) is loaded dynamically at runtime by JVM.
As can be seen, behind the scenes, Reflections tries to get all URLs to be scanned using 2 classloaders by default static and context.
Reflection.scan()
Update: I have found an answer Can you find all classes in a package using reflection? saying that "If there are classes that get generated, or delivered remotely, you will not be able to discover those classes." But there is no proof, however.
Can please anybody give more details on this and confirm?
Dynamically instantiating classes at run time does not change the classpath that your JVM is using. What happens is that some ClassLoader class fetches bytecode from somewhere; and makes it "available" to you. But that does in no way change the "search order" for loading classes (and that is basically what the classpath is about: it only tells the JVM where and in which order to look for classes to load).
Meaning: any "loading" of a class results in some object of class java.lang.Class.
If you want to query the structure of any loaded class; you "just" need to get to the corresponding Class object. Class provides methods like getAnnotation(). It also provides methods to retrieve other objects that represent the methods and fields of the specific Class; and those objects can be queried for annotations in similar ways.
Update, regarding the updates in the question: there are situations where you don't have access to the file system where classes are coming from. You can load classes, when you know their name, but you have no way looking into the "place" where these classes live. And that basically breaks your ability to use reflection as intended.
There is no need to "prove" that, it is simply a consequence of the fact that Java allows you to load classes when you know there name, but "hides" the exact content of "where" those classes are coming from.
I came cross a article about AOP, there it is mentioned that Aspect weaving can happen during the compile time, class loading time and during runtime.
In java, I could imagine, rather understand, how aspect weaving would actually happens during compile time. Proxy class are generated during class compilation itself(with aspect enabled on project). Generated bytecode would have proxy code.
But I am still wondering what exactly (actually) happen, during class loading time weaving and runtime weaving. Does the proxy class gets generated while loading the class? Does aspect library add any programmatic instruction in .class (while compiling) file for proxy class generation?
Spring AOP actually uses Java Dynamic Proxies for interfaces and, if necessary, cglib for non-interface types. It only works for Spring Beans. Proxies are generated automatically for all methods matched by a so-called pointcut. This is done during wiring.
AspectJ however does not need or even use proxies, it directly generates byte code which is woven into the existing byte code. AspectJ is much more powerful and can do more than just method interception.
For compile-time weaving (CTW) this is done by the AspectJ compiler ajc. Instead of native AspectJ syntax (which is a superset of Java) you can also use a Java annotation style way of defining aspects, often called the #AspectJ syntax. In this case you can compile the aspects with javac and use the aspect weaver in a separate build step. The result is basically the same. In both cases, during runtime you need a small AspectJ runtime library in order for the aspects to work as expected.
The difference between CTW and LTW (load-time weaving) is that the weaving step is deferred until classloading time. In order to make this work you need a Java agent library, called the AspectJ weaver, on the JVM command line. Java agents are started before normal application classes are loaded and can thus influence classloading and instrument the loaded byte code as desired. This approach is also used by profiling tools or similar.
So obviously LTW does not work with source code but class files, i.e. AspectJ can weave its aspect code into any regular Java class file. This can also be done before runtime, i.e. you can weave aspect code into an external library for which you do not have the source code, creating a new, modified version of it in order to save the time for LTW every time the library is loaded. This often is called binary weaving. With some extra knowledge it is even possible to weave aspect code into the JDK, i.e. by creating a modified rt.jar including aspect code. But this is nothing you normally do, I just wanted to mention that it is possible.
Not necessarily at compile time. In Java, through reflection and classloader, you can see and even or modify create methods and classes at runtime, programmatically.
For example,
"hello".getClass().getMethod("substring", Integer.TYPE).invoke("my sharona", 3)
Will return "sharona", extracting the method substring from a String instance and applying it to another object.
Using a custom classloader, you can define how your class is loaded from the system. This way you can define a method which will called to load (or generate!) the bytecode for a class. You can also use the system classloader to load the bytecode of a class and inspect it.
This technique is widely used by Mozilla Rhino, which can use it to load a compiled JavaScript as a Java bytecode for greater efficiency, or JavAssist, which allows you to create classes, methods, fields and anything at runtime.
Also application servers like JBoss or TomCat use reflection to inspect and manipulate the code, especially through annotations.
Not sure what run-time weaving is. In load-time weaving the agent intercepts the class loading and modifies the byte-code before passing it on to the class loader.
To see how this works is quite easy, for example using AspectJ. You could use compile time weaving and disassemble the code to see exactly how it works. AspectJ can also be instructed to save on disk the generated classes during load time weaving.
I may be just looking in the wrong direction but I find the JSE documentation on annotation processing very ... sparse. I want to write an annotation processor which processes annotated String fields and local variables to substitute them with a computed String expression. This should not be too complicated but I'm pretty lost in the Javadoc for javax.annotation.processing.
EDIT: I need to process annotations at compile time because I want to modify the generated code. It should replace annotated constant String expressions with a computed String expression.
This can not be done with a compile time annotation processor. Compile time time annotation processors can only generate new files (and classes) they can not modify existing classes. You can do reflection at runtime but strictly speaking you that is not called annotation processing. Also you won't have access to local variables.
If you're looking on how to write a compile time annotation processor check out https://github.com/pellaton/spring-configuration-validation-processor
Two tools that do this are Project Lombok and DuctileJ. Both of these tools existed at the time the question was originally asked; additional tools now surely exist.
The key idea is to write an annotation processor that traverses and modifies the program's AST (abstract syntax tree) during compilation, before code generation. The compiler won't change the source code on disk, but the generated .class file will reflect the changes that your annotation processor makes.
You may be able to adapt one of these tools to suit your needs, or you could implement your own tool inspired by their implementation techniques.
Compile-time processing has two advantages over class-file processing. One is that the compiler usually has more information than is available from compiled code. Another is that everything happens in one step, during compilation, rather than requiring the developer to run a separate tool to rewrite the .class files after compilation.
Check
Javassist http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
ASM http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
Byteman (for runtime) http://www.jboss.org/byteman/