I'm looking for a solution for generating code. I have googled, searched on SO and some blogs but I didn't find a good solution.
I'd like to put an annotation on my class and at compilation time, some methods and properties would be automatically added to the class.
Key points of the solution I'm looking for :
Generated code customizable (MANDATORY)
No external tool like apt have to be called (MANDATORY)
JDK only, no third-party framework (MANDATORY OPTIONAL)
Annotation name customizable (OPTIONAL)
For example :
#Aliasable
public class MyClass {
//Some properties
// Contructor ...
// Some methods
}
My class would look like this after compilation :
public class MyClass {
//Some properties
private String alias;
// Contructor ...
// Some methods
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias=alias;
}
}
EDIT:
Finally, I turned my third requirement from MANDATORY to OPTIONAL and choosed project Lombok (easy integration with Maven and Eclipse, virtually no work to do
for using it).
The annotation processing tool has been integrated in javac since version 1.6 and is part of the JDK. So there is no need for external tools when using the Pluggable Annotation API. You can generate any code by analysing custom annotations or method/parameter/field/class declarations using the Mirror API.
The annotation processor API says you shouldn't change existing classes. Instead you should generate subclasses of existing classes and create extension methods on those subclasses.
It seems to be possible to change classes anyway (e.g. by using bytecode manipulation libraries) though that would in contrast to the specification and could lead to issues with other annotation processors and may not work with all compilers in the same way.
Have a look at Project Lombok. It generates code as you ask when you write:
public class MyClass {
#Getter #Setter private String alias;
}
It also does a lot more if you need it. I know you asked for no external tools, but you would basically be recreating this.
I use XML and XSLT to generate code. It is used for EJB, Logic and the CRUD part of the views. It isnt gerated at runtime but instead on the buildserver. Developers can generate the code manually for well development purposes. This is done with the same command ANT uses on the buildserver.
Because the generation is with XML and XSLT it is highly customizable.
If you google Java code generation with XSLT you will run into alot of examples. Please note that this technique dates from ~2000 and thus probably has been preceded by now by easier solutions.
Related
Is there something special to the #Deprecated annotation that I cannot reproduce?
I need to create an annotation similar to #Deprecated to produce warnings in Eclipse and also at build time. When I mark a method as #Deprecated I get nice warnings. For example, if I have an old method (that I may still keep for compatibility reasons):
#Deprecated
public List<Account> getClientAccounts(final int clientId) {
// Implement search...
}
Then, if I try to use it in Eclipse I can see it strikethrough, and a yellow icon in the left bar:
Also when building I can see the:
[WARNING] app1/src/test/java/com/app1/MyApp.java: app1/src/test/java/com/app1/MyApp.java uses or overrides a deprecated API.
Now, depending on external factors I cannot control (e.g. absence of database indexes) some methods are not optimal, and I would like to clearly mark them as such... with my brand new #NonOptimal annotation. I need to add visibility to the problem. So far I have:
#Retention(RUNTIME)
#Target(METHOD)
// What else here?
public #interface NonOptimal {
}
How can I create this annotation?
I wish I could extend Deprecated, but no can do.
After reading about this quite a bit I ended up with an ugly workaround. It works, though I don't like it.
I decided to mark the bad methods with both the #Deprecated and #NonOptimal annotations. It's conceptually wrong (the methods are not actually deprecated) but it works well out of the box. No need to develop an overkill Eclipse plugin:
The #Deprecated annnotation bugs developers all around the place (in Eclipse and when building), and that's a good thing.
The #NonOptimal annotation provides details on why this is a bad method to use.
Ugly but works. As of now Eclipse does not provide any better option.
Note: to make things worse, the NonOptimal annotation does not work well in Maven when using toolchains: warnings go silent, disappear, nada... Therefore, AnnotationProcessors are kind of useless in the end.
#TheImpaler This is actually not a true answer for your problem, but some time ago I came across the Google Annotations Library (a.k.a. gag) while using Zalando's Problem API.
This library provides a great number of custom annotations that, in some cases, can be used to instrument your actual code by using a ASM and a custom java agent.
Maybe it can give you some ideas regarding your actual issue.
The project is no longer maintained but there is a fork in Github.
I have an annotation that I currently use only for internal build and documentation purposes. It does not offer any value at runtime, which is why I chose #Retention(SOURCE):
#Retention(SOURCE)
public #interface X
However, in order to validate its proper usage, I would like to implement a unit test that navigates the entire API to check whether the annotation is applied everywhere it should be applied to. That unit test would be quite easy to implement by using ordinary Java reflection APIs, but I cannot do that as the tests can't reflect over the annotation, given its #Retention(SOURCE).
In order to use reflection in tests, I would have to change it to #Retention(RUNTIME), which I would like to avoid due to the overhead in byte code at run time.
Workarounds I'm aware of:
There are workarounds as always. I'm aware of these:
We could use an annotation processor that fails the build instead of running unit tests. This is feasible but less optimal, as the tests are quite sophisticated and much more difficult to implement using annotation processors rather than unit tests using both junit APIs and the much more convenient reflection API. I would like to use this workaround as a last resort only.
We could change the #Retention to RUNTIME in our sources, build the sources with these additional tests, then pre-process the API to remove the retention again, and then build the API a second time for production usage. This is an annoying workaround as it would complicate and slow down the build.
Question:
Is there a more convenient way to retain the annotation at runtime only for tests, but not in the actually built jar file, using Maven?
Here's a hybrid approach that might work.
Write an annotation processor that doesn't implement the full testing that you want to do, but instead merely records in a sidecar file where the annotations occurred. If you're annotating classes, methods, and fields, the location can be recorded fairly straightforwardly using the package-qualified class name plus a method or field descriptor. (This may be more difficult, though, if your annotation can appear in more obscure places such as on method parameters or at type use sites.) Then, you can keep the retention policy as SOURCE.
Next, write your junit tests to do whatever reflective analysis you're intending to do. Instead of trying to find the annotations reflectively, though (since they won't be there) read in the sidecar file and look there.
I think you covered the solution space pretty well.
Two more you didn't cover:
Strip the annotation later in a post processing step using a tool like proguard.
Hack your compiler to switch the annotation retention depending on a flag. Pretty sure you can switch some flag in the internal meta data. Maybe injected by another annotation processor triggered by the annotation #DynamicRetention("flag")?
One of other workarounds may include:
Leaving default retention = CLASS.
Using a library which will read bytecode directly.
#interface X {
}
#X
public class Main {
public static void main(String[] args) throws IOException {
ClassPathResource classResource = new ClassPathResource("com/caco3/annotations/Main.class");
try (InputStream is = classResource.getInputStream()) {
ClassReader classReader = new ClassReader(is);
AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(Main.class.getClassLoader());
classReader.accept(visitor, 0);
System.out.println(visitor.getAnnotationTypes());
}
}
}
yields:
[com.caco3.annotations.X]
The library used is ASM:
ASM is an all purpose Java bytecode manipulation and analysis framework
This code uses some classes from Spring Framework:
ClassPathResource - something similar to java.io.File
AnnotationMetadataReadingVisitor (source code) - is a ClassVisitor collecting annotation metadata
However this approach suffers from the same drawback as you described:
overhead in byte code at run time
because (from javadoc):
Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time.
public static void main(String[] args) throws IOException {
X x = AnnotationUtils.findAnnotation(Main.class, X.class);
System.out.println(x);
}
outputs: null
If #Retention(CLASS) is acceptable, then I would recommend to use ArchUnit. The task you describe sounds like it is a good fit. ArchUnit can be used to define and validate rules for your architecture. For example it can be used to restrict access between certain classes/packages, or e.g. to validate class hierarchies, type names - or annotations.
It is usually executed as a unit test by JUnit or any other test framework. It works by analyzing byte code, so there is no need to switch to runtime retention.
The fluent API is nice and in my opinion way more readable than using reflection or annotation processing for this use case. For example to ensure that certain classes should always have a particular Annotation you would write this rule in a unit test:
classes().that().areAssignableTo(MyService.class).should().beAnnotatedWith(MyAnnotation.class)
It's also possible to create custom rules to assert more complex constraints.
I'm trying to create an annotation processor that works on top of realm.io
Sadly to use realm you need an android project, while to create an annotation processor you need a java one (in order to import javax.annotation.processing.*)
Anyone know a way to import AbstractProcessor and all the other needed stuff on an android library? I can't find I way to do this (already switched targetCompatibility and sourceCompatibility to 1.7)
a way to import AbstractProcessor and all the other needed stuff on an android library
The better question is: why do you want that?
If you are under impression that your processor would depend on Realm classes (or any other Android classes), — that's not the case. When you write code, that uses APT Mirror API, you don't have to reference those classes directly, only by names. The resulting code will look like this:
DeclaredType theBinder = lookup("android.os.Binder");
DeclaredType theIInterface = lookup("android.os.IInterface");
DeclaredType theCreator = lookup("android.os.Parcelable.Creator");
...
private DeclaredType lookup(CharSequence name) {
return types.getDeclaredType(elements.getTypeElement(name));
}
You will then proceed to manipulate created TypeMirrors by using methods of Types and Elements utility classes. You can also convert those mirrors to alternative formats, such as Square's JavaPoet TypeName, but you really don't have to, because Mirror API provides most facilities you may ever need.
You definitely don't want to load Realm's classes inside your annotation processor. Firstly, there is simply not need for that. But more importantly, as you pointed out in the question, it is often not possible to share the same setup between annotation processor and it's runtime appliances. This issue isn't unique to Android, — for example, nobody expects to set up full-blown application server to compile a server program, that uses JAXB-aware annotation processor.
If you really want some piece of code from Realm in your processor, and it is not available as separate Java library, the simplest way is to just copy that code to your processor.
I have created an annotation, applied it to a DTO and written a Java 1.6 style annotationProcessor. I can see how to have the annotationProcessor write a new source file, which isn't what I want to do, I cannot see or find out how to have it modify the existing class (ideally just modify the byte code). The modification is actually fairly trivial, all I want the processor to do is to insert a new getter and setter where the name comes from the value of the annotation being processed.
My annotation processor looks like this;
#SupportedSourceVersion(SourceVersion.RELEASE_6)
#SupportedAnnotationTypes({ "com.kn.salog.annotation.AggregateField" })
public class SalogDTOAnnotationProcessor extends AbstractProcessor {
#Override
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
//do some stuff
}
}
You are looking for "Instrumentation", which is what frameworks like AspectJ do. In this case you have to specify a jar in the command line with the "-agent" option, and then have the possibility to filter all loaded classes. During this filter step you can check for annotations, and modify the bytecode before it gets loaded in the virtual machine. Libraries for doing the actual bytecode modification include "asm", and maybe the highlevel wrappers "cglib" and "javassist". You could even precompile your classes to generate a list of classes which have to be instrumented by you, to make filtering in the beginning a bit faster.
See java.lang.instrumentation for more info.
By design, the annotation processing facility does not allow direct modification of the source code being processed. However, one can generate subclasses of the type being processed or the superclass of the type being processed. With some planning, this does allow some of the effect of modifying the type in question. I've written up an example of how this can fit together; see this blog entry for a more detailed explanation and some sample code.
You have to use internal compiler's classes – some inspiration:
AOP or APT for overriding methods from super classes
RomanNumeralProcessor.java
Java Multiline String
But it is brinkmanship. Your program will compile only on Sun/OpenJDK and there can be problems in future versions (internal API can change). Although once compiled, it is standard bytecode and will run everywhere.
BTW: if you want use it in Eclipse, you should add some special support for it because Eclipse uses non-standard compiler. Your design should be more complex and you should add a level of abstraction to your processor – like Lombok does.
You have to extend the javac compiler for this, which means building your program won't be as portable as a regular application. See http://weblogs.java.net/blog/cayhorstmann/archive/2006/06/say_no_to_prope.html for more details on how someone achieved this.
This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
How and where are Annotations used in Java?
Java beans, annotations: What do they do? How do they help me?
Over and over, I read about Java 5's annotations being an 'advanced feature' of the language. Until recently, I haven't much used annotations (other than the usual #Override, &c), but work on a number of webservice-related projects has forced my hand. Since I learned Java pre-5, I never really took the time to sit down and grok the annotation system.
My question- do you guys actually use annotations? How helpful are they to you, day-to-day? How many StackOverflow-ers have had to write a custom annotation?
Perhaps the most useful and used case of Java Annotations is to use POJO + Annotation instead of xml configuration files
I use it a lot since (as you already stated) if you use a web framework (like spring or seam) they usually have plenty of annotations to help you.
I have recently wrote some annotations to build a custom statemachine, validations purpose and annotations of annotations (using the metadata aspect of it). And IMO they help a lot making the code cleaner, easier to understand and manage.
Current project (200KLOC), annotations I use all the time are:
#NotNull / #Nullabe
#Override
#Test
#Ignore
#ThreadSafe
#Immutable
But I haven't written yet my own annotation... Yet!
I have used annotations for:
Hibernate, so I don't need to keep those huge XML files;
XML Serialization, so I describe how the object should be rendered in the object itself;
Warning removal for warnings that I don't want to disable (and for which the particular case cannot be properly solved).
I have created annotations for:
Describe the state required in order for my method to be executed (for example, that a user must be logged in);
Mark my method as executable from a specific platform with additional properties for that platform;
And probably some other similar operations.
The annotations that I have created are read with Reflection when I need to get more information about the object I am working with. It works and it works great.
Annotations are just for frameworks and they do work great in hibernate/jpa. until you write a framework that needs some extra information from passed to it objects you wont write your own annotations.
however there is new and cool junit feature that let you write your own annotations in tests - http://blog.mycila.com/2009/11/writing-your-own-junit-extensions-using.html
I use annotations daily and they are wonderful. I use them with jsf and jpa and find them much easier to manage and work with than the alternative XML configurations.
I use annotations for describing in my state synchronisation system what classes are specialisations of the annotated classes, and the environment in which they should be used (when an object is created, it will work out for its entity lists which are the best entity classes to create for the nodes on the network; i.e., a Player entity for a server node is instead a ServerPlayer entity). Additionally, the attributes inside the classes are described and how they should be synchronised across machines.
We just used annotations to create a simple way to validate our POJO's:
#NotEmpty
#Pattern(regex = "I")
private String value;
Then we run this through the Hibernate validator which will do all our validation for us:
import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;
public void validate(T validateMe) {
ClassValidator<T> validator = new ClassValidator<T>((Class<T>) validateMe.getClass());
InvalidValue[] errors = validator.getInvalidValues(validateMe);
}
Works great. Nice clean code.
We use custom annotations as a part of our integration testing system:
#Artifact: Associates an integration test with an issue ID. Trace matrices are then automatically generated for our testing and regulatory departments.
#Exclude: Ignores an integration test based on the browser platform / version. Keeps the IE 6 bugs from clogging up our nightly test runs :)
#SeleniumSession: Defines test specific selenium settings for each integration test.
They are a very powerful tool, but you gotta use them carefully. Just have a look at those early .NET Enterprise class files to see what a nightmare mandatory annotations can be :)
We have a report builder as part of our webapp. A user can add a large number of widgets that are all small variations on the same set of themes (graphs, tables, etc).
The UI builds itself based on custom annotations in the widget classes. (e.g. an annotation might contain default value and valid values that would render as a dropdown. Or a flag indicating if the field is mandatory).
It has turned out be be a good way to allow devs to crank out widgets without having to touch the UI.