I am generating Java source files for my project using a source generation tool (antlr). However, I am writing most, if not all of my code, in Kotlin.
Kotlin already offers great Java interop, so using the generated sources is not a problem. However, because of how Kotlin brings Java's nullable types into a null-safe system, I lose most of the null-safety that I use Kotlin for. At the very best I have warnings of platform types (make type explicit to avoid subtle bugs); at the worst I have unexpected crashes and subtle bugs.
Kotlin does, however, respect nullability annotations, such as JSR-305, FindBugs, Lombok, Eclipse, and JetBrains's respective forms of #Nullable/#NonNull, bringing those in as the appropriate non-null type or optional.
Because the code is generated and I have access to the source (and understand how it works), I know which functions can/not return null, and want to annotate them as such so they include neatly into my null-safe code. However, I cannot add annotations directly into the code, as it is generated during the build step and would overwrite any manual changes.
Is it possible to / what is the best way to annotate the nullability of generated java sources for the purpose of use in null-safe code?
The best way would be to modify the source code generator so that it includes the annotations that you require.
If you can't modify the generator (e.g. because the generator is proprietary and you don't have its source code) then you can do this using bytecode engineering. For example, this page on the ASM site gives one way to do it:
http://asm.ow2.org/doc/tutorial-annotations.html
Of course, in either case you need some way to tell the tool (the generator, the bytecode rewriter, whatever) which methods should be annotated.
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/
What are the relative merits and demerits of annotation processing respect to bytecode generation (e.g. with ASM)? Apart from implementation difficulty, why would you prefer one over another?
Since a commenter asked, I'm trying to automatically generate implementations for abstract getter/setter methods, but I would like a more general answer. I'm not asking what's the better way to generate getters and setters.
Some bytecode generator libraries contain support for easy creation of getter/setter variables, which simplifies things significantly - you just import the library classes and write Java code. Some frameworks can even automatically generate getters and setters (along with a whole bunch of other things) based upon a simple annotation on a field.
On the other hand, bytecode generation generally has a runtime performance impact as the new classes are compiled, although that can be mitigated by caching the generated class files.
My experience with annotation processing has not been nearly as pleasant. It generally requires you to configure or even modify your build system so that the annotation processor is executed. In addition, coding an annotation processor can become very uncomfortable if you wish to modify a source code file extensively, and apparently there is nowhere near the same framework/library variety as there is for bytecode generation.
My personal favorite, to be honest, is using Java 7 method handles when possible - or just writing the **** getters and setters by hand.
EDIT:
The main problem with the annotation processing API is that (as far as I know) it does not support modifying code at compile-time. The recommended approach seems to be the generation of independent decorator classes. Sure, that is relatively easy if you use e.g. Apache Velocity but the end result is not nearly the same.
There are some hacks where the original source file is processed to add methods and re-compiled, but even getting the path of the source file is almost impossible. There is usually a lot of guesswork involved, with various assumptions about the project structure being made. In addition, the annotation processor essentially maintains a separate source tree for the processed source files.
Project Lombok (which I can't believe I forgot to mention before) uses a lot magic of various colors to leverage the annotation processing API to something more usable. It could very well be what you need...
The best thing to do is to use your IDE's accelerators to generate the getters and setters. That way they are going to be present in the source code. That will make reading the code easier and avoid potential problems with your debugger.
Creating getters and setters is a bit tedious, but it is not worth adding a whole bunch of complexity (and potential gotchas) to avoid it. (And if it is really too tedious for you, persuade your boss that you need a "code monkey" to help you.)
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/
After a bunch of XML config files, I've seen Java moving to Annotation based configurations.
Are annotations playing the role of DSL here?
Is it because the static nature of Java? I'm thinking in Ruby which doesn't have ( afaik ) things like that. Is it because Ruby has good metaprogramming capabilities?
Are there alternatives ( I mean other than using a bunch of .xml files )
Basically annotations are a tool that allows you to process source files at compile-time and do action corresponding to annotations found in the file (possibily deriving a new source).
They are quite useful for many purposes like expliciting constraints while avoiding cluttering the code or enrich the behaviour of some methods.
I wouldn't say that they are so similar to DSLs of Ruby since in this case you annotate code with a particular syntax while in Ruby you can design your own DSL from scratches and use it as you wish.
Java ships a tool called apt (like the one you suspect) that is able also to work with annotations at run-time but they are usually used to give compile-time infos to your sources. This doesn't mean that in certain circumstances you can't easily adapt the annotation mechanism to work out the same things that you would obtain with a DSL but they don't exist for the same purpose.
As already said, annotation can be used to create DSLs quite efficiently, bacause they add some sort of metaprogramming capabilities to the langauge. However for that purpose you could use byte code injector or even any other Java language feature.
However the primary purpose of annotations is to be able to annotate source code elements with metadata.
If you are asking for alternatives for creating internal DSLs in Java, just look at the Fowler's DSL book WIP and choose from different concepts which can be used for implementing internal DSLs, many of them are present in Java. If you are asking for alternatives for metaprogramming, then there are also many: different byte code injectors, aspect oriented programming using AspectJ or Spring or code generation.
Are Java annotations used for adding functionality to Java code besides just adding documentation about what's going on in the code? What's the most advanced/complex functionality you could add to your code through an annotation?
Annotation are basically not more than a tag (with optional additional data) on a class/method/field. Other code (libraries or tools) can discover these tags and execute functionality dependant on the annotations found. I don't see a real limit on the complexity of the functionality possibly added by annotations. This can for example emulate AOP (adding functionality before or after a method with an annotation).
Annotations as such only add information (metadata) to a class.
One can easily build a system that uses that metadata to provide additional functionality, however.
For example you can use apt to generate classes based on the information provided by the annotation.
An annotation needs a tool to react to it. If such a tool does not exist the annotation is merely a notation. The "tool" can be an APT based agent or some piece of code that uses reflection (for instance, JUnit's #Test).
Several annotations are recognized by the Java compiler and thus have pre-defined semantics: #Override, #Deprecated, #Target.
I would understand Annotations as a way to document your code in a machine readable way.
For example in Hibernate you can specify the whole persistence information for your objects as annotations. This is directly readable for you and not in a distant xml file. But is also readable for the tool to generate configurations, database schemes etc.