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.
Related
I am using the openapi-generator-maven-plugin to generate model sources.
Is there a way to generate them only with fields and without any access methods?
I want the access methods to be generated via lombok with the additionalModelTypeAnnotations configOption in the maven configuration of the openapi-generator-maven-plugin
You can implement those customizations by changing the Mustache templates
Fetch the templates of the Java framework (ie spring-boot) you want to use (ie openapi-generator-cli author template -g spring --additional-properties=library=spring-boot -o tmp/mytemplates
Modify the local model.mustache file to import the packages you want (lombok) and pojo.mustache to remove the getters/setters. There might other customisations necessary (each framework templates are different) but this the recommended approach.
As #beppe suggested in their answer, this can easily be done by modifying the mustache template. However, I highly advice against it. In doing so, you discard many of the the features included with the model objects created by the generator. Some of the features you lose are:
Bean Validation
Jackson Serialization Library Support
Support for vendor extensions
By adding the Lombok annotation to the generated files, you are basically ignoring the main point of the generator, which is to generate files that support each other. You are instead using a generator to call a generator.
Finally, the amount of customization necessary to make the lombok library work with the mustache files is much more than is really worth it. Sure, you can add #Data or #Jacksonized to your model, but what about #JsonIgnore? Do you want to use parameters in your Lombok calls? Because you can't set the builder classname via #Builder(builderClassName = "EmployeeBuilder"). That would be hardcoded. Instead, you'd have to use mustache parameters, such as #Builder(builderClassName = {{$builderClassName}}), which you'd then have to define elsewhere. What about #Builder vs #SuperBuilder? Which one do you use in which situation? How do you define and template it?
At this point, you might as well rewrite the entire pojo.mustache to be able to use the lombok annotations. But, what if you need the old pojo.mustache functionality elsewhere? Now you need to write a custom generator to determine which mustache to use in which situations.
It is best to just build the domain models as the openapi-generator intends and use them as they are. You can add annotations if you need to via vendor extensions such as x-field-extra-annotation and x-class-extra-annotation if you really feel the need to.
I am having difficulties to differentiate between all these annotations tools and their use cases.
My guess, although the literature is confusing, is:
Custom Annotations are meant to be used in runtime retention policy as markers to be interpreted by means of Reflection API
Annotation Processing is meant to be used in class (for static checking at compile time) and source (for source generation) retention policies
AOP is meant to modify the code at runtime
So, do Custom Annotations and AOP make sense out of Runtime Retention Policy? Do Annotation Processing make sense out of Class/Source Retention Policies? Is the difference between AOP and Custom Annotations the sole fact that the laters are passive (you need to receive the annotated object as a param in order to do something)? Why is a framework like Checker needed at all?
Annotations are just a Java syntactic means to add information to classes, methods, fields or method parameters. There are three retention types specifying where the annotations are available:
SOURCE means that the annotations are only in the source code and being discarded during compilation.
CLASS means that the annotations are in the class file and available for bytecode processing steps after compilation. This is the default value.
RUNTIME means that you can read the annotations during runtime via reflection.
Annotation processing enables you to read annotations from your source code (i.e. even those with SOURCE retention) and use that information in order to generate more source code which can later be compiled. It is a kind of pre-processing step helping you to create boiler-plate code automatically instead of typing it manually.
AOP (Aspect-Oriented Programming) is an unrelated concept, please read Wikipedia or so in order to learn more. It is not meant to modify your code but its behaviour by weaving cross-cutting concerns into your main application logic. There are several ways to implement and apply AOP, e.g.
during runtime via dynamic proxies and delegation as Spring AOP does it or
via compile-time, binary or load-time weaving, all three of which are supported by AspectJ.
Incidentally, AOP tools like Spring AOP or AspectJ can access RUNTIME annotations. It does not mean you need to use annotations in order to apply aspects to your code, they are just one of several ways to mark and identify joinpoints in your application logic where aspects should be applied.
Besides, the AspectJ compiler also supports an annotation processing step, i.e. you can for example write an annotation processor creating new aspects or application classes from your source code annotations before compilation.
In order to explain all of this in more detail I would need to write a series of articles or a book, so please take it from here by yourself and learn about these concepts by reading other websites or books.
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.
I want to define a few annotations that will allow extra warnings/errors to be reported during compilation (similar in concept to the #Nullable and #NotNull annotations in IntelliJ).
I would like to be able to write some compiler hooks that will also add my compilation logic based on those attributes.
I want a generic hook if possible, however since we are using Eclipse - it would also be a benefit if we had that ability.
I'd like to know:
Is it possible? (any of the options above)
Where do I start?
I had little experience with annotations so far, so if I'm going about this the wrong way - I'd like to know that and if possible get a better direction to go with.
Thanks.
You can use the Java Annotation Processor (see JSR 269: Pluggable Annotation Processing API) for that. From Annotation checking at compile time with Java Annotation Processor:
The JSR 269 states that you can
implement a plug-in for the compiler
which can handle the annotations. This
plug-in can be given as parameter at
compile time, so your code will be
called when one of your annotation
appears in source code.
The mentioned link provides an example that will get you started.
See also:
Annotation Processing Tool (apt)
I understand the purpose of class annotations, thanks to How and where are Annotations used in Java?. What is the purpose of package annotations, as described in this blog post and ยง7.4.1 of the Java Language Specification?
Why would you want to associate metadata with a package? What kinds of things could you do?
bnd tool (and maven-bundle-plugin) makes use of package annotations. Putting #Version and #Export annotation in package-info.java allows it to generate OSGi metadata.
javadoc uses package annotations.
JAXB uses package-level annotations, for example, to specify mapping of a Java type to XML Schema type package-wide. Package annotations are also used in JBoss's xml binding.
Struts 2 Convention plugin uses an annotation to specify a default interceptor for all actions in a package.
There are some package-level Hibernate Annotations. An example of those annotations' usage can be found here.
I suppose #Deprecated would make sense. And maybe something like #Generated if the whole package was generated by some tool from non-Java source. Or #Internal if this package is not part of a public API.
Maybe OSGi tools (where you need to declare the versions of your packages, and the packages you depend on) could make use of this, too.
Has anyone seen those in the wild?
Two reasons that I can think of:
Annotating special packages to let some aspects (for example using AspectJ) to weave the classes in them for specific functionality.
Annotating some packages that are to be read by some tools, for example for source, meta-data or other kinds of resource generation.
JAXB for example allows most annotations that are normally used on a type to be equally well applied to a package. The meaning in that case would be to specify the default for all classes in that package.
For example, if you want all properties of all classes in a package that are exposed via getter/setters to be mapped in XML you could specify #XmlAccessorType(XMLAccessType.PROPERTY) on each class or simply specify it on the package.
This is not the real purpose, but I'm using them as a workaround to avoid recompilation of the package-info.java files.
The problem is that javac (and the Ant task <javac>) creates no class file for the package-info.java if there is only documentation (the reason for their existence) and the package bla; statement, and that the ant task recompiles every file for which there is no (or an older) corresponding .class file.
Adding a dummy annotation there (like SuppressWarnings) had the effect that a package-info.class is produced and thus the file is not recompiled until changed again.
(Ant 1.8.0 solved this by creating an empty package-info.class, even if there was no annotation, but I'm using an older ant here.)
Test metadata -- that is metadata around test packages (unit tests or otherwise). You can ascribe various pieces of test metadata that are appropriate at the package level, such as: features, owners, versions, bugs/issues, etc. These could be refined at the class or method level, but having package-level definitions or defaults could be handy for brevity. I've utilized a variant of this approach (before the benefit of annotations).
A similar argument could be made for generalized code metadata around the same sorts of things: features, ownership, defects, historical information, etc.