For understanding of the Java annotations I tried some hands on and got few doubts, even though looking at execution I am still confused. Here is what I am doing.
Define a Annotation
#Retention(RetentionPolicy.CLASS)
#Target(value=ElementType.TYPE)
public #interface Command {
}
Now I initialize the commands
Reflections reflections = new Reflections(CMDS_PACKAGE);
Set<Class<?>> allClasses = reflections.getTypesAnnotatedWith(Command.class); // line 2
for (Class clazz : allClasses) {
MYCommand cmd = (MYCommand) clazz.newInstance();
System.out.println(cmd.getClass().getAnnotation(Command.class));// line 6
log.info("loading Command [ {} ]", clazz.getCanonicalName());
}
when I run the program line 6 displays null.
When the policy is RetentionPolicy.RUNTIME line 6 displays the correct Command.
During this process the line 2 is still giving me correct Annotated class irrespective of policy. So does it mean that the Reflection Library is ignoring the RetentionPolicy
I am really confused even though reading most of tutorials.
The question for me actually is that , why is this different behaviour? When annotated with RetentionPolicy.CLASS policy It should not have given me at runtime. Is my understanding wrong or can anyone please share there valuable inputs on the understanding of these both.
Yes, the Reflections library (not Reflection, but Reflection*s*) does ignore the visibility of annotations by default.
This can be changed using the org.reflections.adapters.JavassistAdapter#includeInvisibleTag flag. Something like:
JavassistAdapter mdAdapter = new JavassistAdapter();
mdAdapter.includeInvisibleTag = false;
new Reflections(new ConfigurationBuilder()
...
.setMetadataAdapter(mdAdapter)
...
Another option would be to use the JavaReflectionAdapter instead.
HTH
In the first place, the RetentionPolicy dictates what a conforming compiler has to do. Annotations with RetentionPolicy.SOURCE do not make it into the class file while the other two, RetentionPolicy.CLASS and RetentionPolicy.RUNTIME, are stored within the class file but using different attributes to allow to make a distinction between them when reading the class file.
The documentation of RetentionPolicy.CLASS says:
Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. This is the default behavior.
Here, the responsibility is clearly documented, the VM shall not retain them and the Reflection API built into the JRE conforms to it. Though “need not be retained” does not sound like a strong requirement.
But 3rd party libraries like the Reflection Library you are using are free to implement whatever they want when parsing a class file. Since the documentation for the method you have called simply says: “get types annotated with a given annotation”, the behavior isn’t wrong as the type has that annotation.
And you are able to find out the RetentionPolicy of that Annotation even before invoking that method by analyzing the Annotations of the Annotation. So it makes no sense invoking the method when you already know that the annotation has the RetentionPolicy.CLASS and then bother because the method does something instead of nothing.
But, of course, it would be better if that behavior was documented completely. So you might ask the author of that 3rd party library to improve the documentation.
Related
This question already has answers here:
Can a Java class add a method to itself at runtime?
(11 answers)
Closed 2 years ago.
There is a much better question (linked below). My question encouraged bad coding practices without outlining the risks of those practices.
Can a Java class add a method to itself at runtime?
The original question was the following:
Is there a way to add a method to a class definition at runtime?
For example, lets say I had the following interface
public interface Singleton<T> {
#StaticContract
T getInstanceStatic();
}
At runtime, I would scan all classes for methods with the annotation "StaticContract" and add a static version of the implemented method to the class definition. However, I have no idea how I would go about doing this or if this is even possible.
In my current implemention, if runtime reflection doesn't find a static method for a method during initialization, I throw a NoSuchMethodError. The big problem is that the developer might not know that they are supposed to create a static method if they aren't familiar with the interface. Non-static getInstanceStatic() doesn't really make sense with Singletons. It just serves as a reminder to create the static method.
Combined with the ability to recover the erased type using reflection, this would allow me to use generics for far more than they were intended. For example, you would no longer have to define and pass a factory object. You could just define the method in the class that the factory produces.
Also, if there isn't a way to do this during runtime, is there a way to do it during compile time?
What you want is possible!
But not like this. The answer to your actual question is a simple, flat out 'No'. But you don't want what you describe in your question.
Let me elaborate.
Let's first say that you could add methods at runtime. You can't*, but let's say you could.
That would accomplish nothing whatsoever; given:
public class Example implements Singleton<Example> {
#StaticContract Example getInstanceStatic() { return new Example(); }
}
We can already see issues here (this method is.. public. It has to be, that's the rule of interfaces. But given that you want this to be a singleton, that'd be very bad news).
But let's carry on for a moment. The idea is that you want to be able to write, in other code:
Example.instance();
but - how? The compiler won't LET YOU do that, because the method isn't there, and if we go with your plan (of adding the method at runtime), then at compile time it'll never be there, and javac will refuse to compile this. If somehow it DID compile this, then at runtime, where you pull your magic trick and somehow add this method, all would be well, but that's a moot point - short of hacking together a class file with a bytecode editor, there's no way to obtain a class file with the compiled version of Example.instance().
You don't want to add this at runtime.
But maybe you want to add it at compile time.
And THAT? That you can do!
Strategy #1: Lombok
Project Lombok lets you write #UtilityClass which makes it act singleton-esque. Lombok intentionally does not have #Singleton because as a concept, singletons are so universally deriled as bad code style. I guess you could fork lombok and add it if you must have this.
Strategy #2: Annotation Processors
Other than lombok, annotation processors cannot add things to existing source files. But they can make new ones! Given as actual real bytes on disk source file:
#SingletonizeMe
public class Example {
Example() {} // without lombok you're going to have to write this yourself to ensure nobody outside of the package can instantiate this...
}
then you can write an annotation processor which means that javac will automatically produce this file:
// generated code
package same.pkg.as.your.example;
public class ExampleUtil {
public static final Example EXAMPLE_INSTANCE = new Example();
}
and compile it as part of the build, and any code that contains ExampleUtil.EXAMPLE_INSTANCE will just be compiled right along, without any complaints. Annotation Processors solve the problem of 'okay, maybe at runtime this would work but how do I explain to javac to just do what I want without it refusing to compile code that it thinks stands no chance of working at runtime?'.
Strategy #3: Dependency injection systems
From dagger to spring to guice, there are tons of libraries out there that do 'dependency injection', and pretty much all of them have an option to inject things singleton style. Give those 3 libraries a quick look, it should be fairly obvious how that works once you follow their get-started-quick tutorials.
*) You'd think the answer is yes, what with instrumention and the ability to use agent technology to reload a class file. But is that 'adding a method to a class'? No, it is not - it is reloading a class, which does not normally work if you try to add any new members; the hot code replace tech built into VMs doesn't let you change (or add, or remove) any signatures.
I understand that annotations serve a purpose to modify code without actually BEING code, such as:
#Author(
name = "Benjamin Franklin",
date = "3/27/2003"
)
But I don't understand how using the annotation is any better/ clearer/ more concise than just saying name = "Benjamin Franklin" ? How does the addition of annotations strengthen the code?
EDIT: Sorry for another questoin, but I know that #Override can help prevent/ track spelling mistakes when calling methods or classes, but how does it do that? Does it help the actual program at all?
Annotations are just metadata. On their own they serve little to no purpose. There must be an annotation processor, either at the compiler or run time level that uses them for something.
With an annotation like
#Author(
name = "Benjamin Franklin",
date = "3/27/2003"
)
for example, some annotation processor might read it with reflection at run time and create some log file that this author wrote whatever it's annotating on that date.
Annotations are metadata.
#Override annotation is used to make sure that you are overriding method of a superclass and not just making a method with the same name. Common mistakes here consist of:
spelling the method's name wrong
equal(Object o) instead of equals(Object o)
putting different set of arguments
MyString extends String { public boolean equals(MyString str) {} }
equals(MyString str) is not overriding the method equals(Object o) and therefore will not be used by standard Java comparators (which is used in some standard functions, such as List.contains() and this is prone to error situation).
This annotation helps compiler to ensure that you code everything correctly and in this way it helps program.
#Deprecated annotation doesn't make program not to compile but it makes developers think about using the code that can and/or will be removed in a future releases. So they (developers) would think about moving onto another (updated) set of functions. And if you compile your program with the flag -Xlint compilation process will return with an error unless you remove all usages of deprecated code or explicitly mark them with annotation #SuppressWarnings("deprecation").
#SuppressWarnings is used to suppress warnings (yes, I know it's Captain Obvious style :)). There is a deprecation suppression with #SuppressWarnings("deprecation"), unsafe type casting with #SuppressWarnings("unchecked") and some others. This is helpfull when your project compiler have a compilation flag -Xlint and you cannot (or don't want to) change that.
There are also annotation processors that you integrate into your program build process to ensure that program code meets some sort of criteria. For example with IntelliJ Idea IDE annotation processor you can use #Nullable and #NotNull annotations. They show other programmers when they use your code so that can transfer null as a certain parameter to a method or not. If they transfer null it will cause exception during compilation or before executing a single line method's code.
So annotations are quite helpful if you use them to their full potential.
Annotations are most likely used by other programs. Examples include:
#Override
IDE (compiler?) ensures that the signatures match
#Deprecated
IDE marks occurences, compiler warning
#FXML
JavaFX can use these annotations initialize variables in a controller class when an .fxml File is inflated (see http://docs.oracle.com/javafx/2/get_started/fxml_tutorial.htm). They are also used by JavaFX Scene Builder.
Annotations works as a way to marking up the code. Several frameworks uses it, and some others make a great use of it producing your own.
Besides, is important to understand that annotations are the equivalent to meta-data, but is much more than that, since it works as a tag language for the code.
Java #Annotation
#Annotation(from Java 5) adds a metadata which are used for instruction in compile, deployment and run time. It is defined by RetentionPolicy
RetentionPolicy defines a lifetime
RetentionPolicy.SOURCE: It is visible only in compile time(#Override, #SuppressWarnings, #StringDef). For example it can be used by apt to generate some code
RetentionPolicy.CLASS: It is visible in compile and deployment time(.class). For example it can be used by ASM or Java AOP paradigm like AspectJ
RetentionPolicy.RUNTIME: It is visible in deployment and run time. For example it can be used java reflection using getAnnotations(). Dagger 2 uses #Scope annotation
Create a custom Annotation
#Retention(<retention_policy>) //optional
#Target(<element_type>) //optional to specify Java element like, field, method...
#Inherited // optional will be visible by subclass
#Documented // optional will be visible by JavaDoc
#interface MyAnnotation {
//attributes:
String someName();
}
using
#MyAnnotation(someName = "Alex")
public class SomeClass {
}
Suppose I have this annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Name
{
String value();
}
This is going to be used as follows
#Name("name1")
public static Foo foo = new Foo();
I have multiples of these across my project source files. Is there an fairly simple way to search and collect all those "foo"s that're preceded by #Name?
In other words, I'd like to write a method that would return a Set<Foo> containing these.
Thanks!!!
I am not really familiar with the classpath scanners that others are suggesting. They seem like a robust - if not ideal - solution.
If you have control over the source, then you could use annotation processing.
Create an annotation processor that will create a class - MapClass with a static member Map<String,Foo>. Every time the annotation processor encounters the #Name annotation, it adds that to the source code of MapClass. When it finishes processing the annotations, it will have the same effect as if you hard coded the map.
Annotation processing happens during compile time. If some of the classes in your project are not compiled by you. For example, if someone else compiles some classes and gives a jar to you, then it won't work as easily. But if all the classes are compiled by you then it should not be a problem.
To create an annotation processor, extend AbstractProcessor. You will want to annotate your class with a # SupportedAnnotationTypes ( "Name" ) annotation (make sure name is the fully qualified name of your annotation.
Override the process method. process has two parameters: annotations and roundEnv. annotations is just the set of annotations that this particular processor supports - in your case it should be (Name). roundEnv is a useful utility class.
Iterate through the one annotation in annotations. Use roundEnv to getElementsAnnotatedWith. This should give you the set of all elements that carry the #Name annotation.
AbstractProcessor has another utility member - processingEnv. Use its getFiler method to createSourceFile.
Then you have to modify your compilation a little bit. You must compile your processor separately and before the other classes. After the processor is compiled and you are compiling the other classes you must tell the compiler about your processor. If you are using the command line you would add -processorpath /path/to/processor/class[es] and -processor qualified.name.of.processor.
The advantages of this approach over the class path scanner is that everything happens at compile time. So for example, if you accidentally add a #Name annotation to a Bar element, then you can have the processor throw a compile time error (if you wish the processor can ignore it). Then you can fix it before the product ships. With a class path scanner, any error thrown is a run time error - which the user will see.
The disadvantage of this approach is also that everything happens at compile time. This makes it harder to dynamically add classes to the project.
What you need is a Classpath scanner. I have used Metapossum Scanner (it won out because it is in the mvn repo) to scan for annotated Classes, but I do not think it would scan for annotated Fields.
The other option I looked into was Reflections. I have not used Reflections, only researched it. The documentation has a getFieldsAnnotatedWith query that seems like what you need.
Be forewarned, the Classpath scanners are slooow and get slooower the more you have in your Classpath.
No not really (not from code).
A solution would be to put them all in a class, and then iterate on the Fields (getFields()) of the class and check for Annotations (getAnnotation())
You may want to have a look at Scannotation! It may solve your problem!!!
Scannotation is a Java library that creates an annotation database from a set of .class files. This database is really just a set of maps that index what annotations are used and what classes are using them.
PS.: VRaptor framework uses it internally!
I'd like to implement annotation processor that will generate new class based on existing "prototype" class.
import java.util.List
#MyAnnotation
class MySuperClassPrototype {
static MySuperClassPrototype createInstance() {
return new MySuperClassPrototype();
}
}
As a result of code below. The following new source file (compilation unit) will be generated:
import java.util.List
class MySuperClass {
static MySuperClass createInstance() {
return new MySuperClass();
}
public void specialAddedMethod() {
/*...*/
}
}
I'd like to copy all top-level import statements and static members and not static members of prototype-class. I've moved pretty far with Compiler Tree API (com.sun.source.tree). I can print out Tree data-type while substituting new class name for old. But there are problems that seems pretty hard.
If I get Tree.Kind.IDENTIFIER in the tree, how can I find what actual class it references. I need to replace all occurrences of MySuperClassPrototype identifier with MySuperClass identifier, and than print out whole tree.
Is it feasible?
Similarly I need to filter out #MyAnnotation annotation, and again it is represented with Tree.Kind.IDENTIFIER or Tree.Kind.MEMBER_SELECT.
How can I find out actual annotation class that is referenced by this identifier?
And another problem is printing out tree. If I use toString method I got decent result, but constructors are printed as methods with "<init>" name instead of methods with the same name as it's class, so I need to manually print every kind of Tree node.
You can see code I've come with here
Yes, it is possible and I know at least 2 ways.
First, "traditional" way is to write ant task/maven plugin/just command line java utility that scans given file path and calls for each class something like Class.forName(className).getAnnotations(MyAnnotation.class). If this is not null discover class using reflection and do what you need.
Other way is a little bit more difficult but more powerful.
You can implement your own Processor (that implements javax.annotation.processing.Processor or even better extends javax.annotation.processing.AbstractProcessor.
Your processor will just have to be placed to the compiler classpath and it will run automatically when compiler runs. You can even configure your IDE (e.g. Eclipse) to run your processor. It is a kind of extension to java compiler. So, every time eclipse builds your project it runs the processor and creates all new classes according to new annotations you have added.
Please take a look on this project as a reference.
8 Years and not yet answered. Because of that, i will try to answer it, to your satisfaction.
I fill furthermore concentrate on the static part of the question.
TL;DR:
You will not find copy and paste code in this answer.
Is it feasible?
Yes, absolutely.
How can I find out actual annotation class that is referenced by this identifier?
You will have to use the RoundEnvironment within an Annotation Processor to get the TypeElement.
Static Metaprogramming
Static metaprogramming (which you asked for) is metaprogramming done at compile time. By Kontrast: Dynamic metaprogramming is metaprogramming done at run time. And metaprogramming it self is the design of programs, that handle other programs as data.
Pfeh, a lot to take in. If you are interested in this topic, a more or less good source for that is wikipedia.
Your target would be, to generate a class at compile time. For run time, this would be done with something like cglib. But, since you choose static (and for all the right reasons), i will not explain this.
The concept you are looking for is the annotation processor. The link is a link to Baeldung, where they do exactly, what you are looking for, only with the builder pattern in mind. You will love to hear, that this scenario is highly encouraged and easy to do with the annotation processor API. It even allows you, to generate code, which again is passed to the same or another annotation processor, without you doing anything.
Before jumping right in, try to google yourself about "Java Annotation Processing". There are a lot of good sources out there, which will help you. To much, to list here. Just note, that coding in an annotation processor is different than coding normally. Not a huge difference, but the classes you are working on are not yet created. So keep this in mind and don't get discouraged!
Using the Annotation Processor
Your basic annotation processor would look something like this:
#SupportedAnnotationTypes("package.of.MyAnnotation")
#SupportedSourceVersion(SourceVersion.RELEASE_8)
#AutoService(Processor.class)
public class BuilderProcessor extends AbstractProcessor {
#Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// First let's find all annotated elements
Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(MyAnnotation.class);
// Handle all the annotated classes
return false;
}
}
The AutoService Annotation is used, to dynamically register your annotation processor. It comes from an external source, just so you don't wonder, why this code won't compile.
In the handle all annotated classes part, you have the annotated Elements (which are the annotated classes). You now would have to verify, that they are classes and not interfaces or other annotations. This is because #Target(ElementType.Type) aims at any type, which includes interfaces and annotations. Furthermore, you would want to verify, that anything you require is present, or print an error to the compiler using the Messager.
If you print an error here (for example), you will stop compiling and the error will be seen in most modern IDEs. It can be reached by calling roundEnv.getMessager()
Afterwards you can generate a new class and write it to the input of the compiler, as a .java file. This can be done by using the Filer.
An answer in StackOverflow really does no justice to this topic. I highly recommend looking at the Baeldung example and trying to uncover things from there. This API is as old as Java 6, but still not that greatly used. I encourage you, the reader, to try it out for yourself :)
take a look at https://github.com/rzwitserloot/lombok/, It add methods as you described.
such as
#Getter add getter methods based on fields
#Setter
#ToString add toString() methods base on the fields
To quote this link :
Some developers think that the Java compiler understands the tag and
work accordingly. This is not right. The tags actually have no meaning
to the Java compiler or runtime itself. There are tools that can
interpret these tags
.
If the information contained in the annotation is only metadata, why wont my code compile if I annotate wrongly ? That particular annotation should be simply ignored right ?
Edit :
Just to provide an example... A simple JAX-RS web service on Jersey uses an annotation like :
#Path("mypath")
Now, if I change this to :
#Paths("mypath")
OR
#Path(123)
it should NOT stop me from compiling the code according to the above link...
The article is wrong for at least some annotations. Thinks like #SuppressWarnings and #Override the compiler does have very specific knowledge. In fact, the article points this out itself:
Metadata is used by the compiler to perform some basic compile-time checking. For example there is a override annotation that lets you specify that a method overrides another method from a superclass.
Quite how it can be used by the compiler if "the tags actually have no meaning to the Java compiler", I don't know...
Additionally, even for annotations that the compiler doesn't attach any semantic meaning to, it will still verify that when you try to specify particular arguments etc, that those arguments have sensible names and types for the annotation you're using.
Annotations are basically a special form of interface, so the compiler has to be able to load the annotation definition in order to encode the information so it can be included in the class file. Once it's in the class file, the class loader will load it as part of the class, so that annotation-processing tools can access the information. The compiler will verify that only defined arguments are used, as well as supplying default values for attributes that aren't specified (and have defaults defined).