Annotation concepts in Java - java

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).

Related

Where are the rules for annotation classes written for java

I am trying to understand how the annotation understands what to do when we use the annotation. I am not talking about the behaviors like when to execute
that is covered by Retention, values etc. I want to understand how annotations understand the rules for that annotation. For example how does #Override annotation knows how to check if the function overrides a method in super class and so on. I tried digging a lot and I reached here but I don't get where the rules for the annotations are written. It feels like magic to me.
As already commented, processors (e.g. the compiler) must interpret the annotations, but the running program can also read/use the annotations (e.g by reflection).
For example the #Override annotation is used by the compiler, see it's documentation:
Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type compilers are required to generate an error message unless at least one of the following conditions hold:
The method does override or implement a method declared in a supertype.
The method has a signature that is override-equivalent to that of any public method declared in Object.
The #Override annotation is part of the standard API, other annotations may be part of some framework (e.g .JUnit #Test) or additional annotation processors, see Annotation Processing in javac. The developer can also declare annotations, see Annotation Interfaces.
In other words:
an Annotation is just that, an annotation. It is like a tag or mark that can be added to some elements (e.g. to a method, class, ...). There is no rule or anything similar directly attached to it. But some tools, like the compiler, or even normal Java code (some framework/library or written by you) can read and handle that annotation as desired.
There are a couple of annotations in the Java Language Specification (JLS) which compilers are required to handle. The action for the #Override (as example) is coded in the compiler, to do as specified in the JLS. Same for #Deprecated.

How to use the java debug flag to look up parameters during compilation

I'm a noob and I was reading the spring reference documentation, specifically the section: constructor argument resolution
The documentation has a snippet in regards to dependency injection and defining your constructor-arg bean name:
package examples;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private int years;
// The Answer to Life, the Universe, and Everything
private String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
Keep in mind that to make this work out of the box your code must be compiled with the debug flag enabled so that Spring can look up the parameter name from the constructor. If you can’t compile your code with debug flag (or don’t want to) you can use #ConstructorProperties JDK annotation to explicitly name your constructor arguments.
I'm trying to understand how the compiler actually works and maybe a simple explanation. For example:
How do the parameters become available during compile time if debug mode is enabled? Does the compiler like put parameters in a special place in memory that spring can then access, or how does the process of obtaining parameters actually work?
Presumably debug mode enables this mechanism to obtain parameters based on ConstructorProperties.html i.e. Since parameter names are not in general available at runtime
But since they say "in general" makes me think sometimes they are available? Just looking for someone to explain this in a way that I might understand.
Parameters names are not useful at runtime, unless you need them for some kind of reflection based binding (like spring does), but are useful during debugging, because you possibly want to inspect variables by name.
So, adding debugging information add those metadata to the class file. How springs achieve that is beyond my knowledge, but I think it might be based on bytecode tools (like ASM).
Spring uses bytecode manipulation tool to do some special injections.
Saying that in general this is so means that it depends on both the compiler and the runtime used. Since java 8 there is the -parameters flag to add params names to the class metadata.
I can also imagine that different compilers or pre/post compile processor could in fact add such information to the class files, but since the compiler spec do not require to do so they are in general not available.

Does Reflections library ignore the RetentionPolicy

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.

What is the purpose of annotations in Java?

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 {
}

Why should the value for an annotation attribute be a constant expression?

I am having the following piece of code
#UIUnitTimeout(8*60*1000) // works
#UIUnitTimeout(TimeUnit.MINUTES.toMillis(8)) // does not work
I know that according to the JLS only constant expressions are allowed as values to annotation attributes. But why? Why it isn't sufficient if the data types match? Is there anything that could possibly go wrong if the expressions were to be evaluated at runtime? Does every specification have a logical reasoning behind?
An annotation is like a type extension or metadata about the type.
Because java is a statically typed language (meaning that types are known at compile time), it seems reasonable that annotation attribute data (metadata) be known at compile time too - you're defining/declaring data about the annotation (extension).
And as a purely practical point, for annotation processing, which is a compile-time (optional) step, attribute data must be known at compile time - you haven't yet reached a runtime environment, yet you need the attribute data.
Annotation preprocessing requires knowning the value of the annotation before executing the annotated code. In addition, Annotation definitions are themselves anotated with #Retention, which has a value of RetentionPolicy (if not specified, it defaults to CLASS).
Therefore there are 3 different "kinds" of annotations, and only those annotations declared as RUNTIME will be available when the program is executed. (But their value must be constant, so that they remain defined without executing the associated code.)
CLASS Annotations are to be recorded in the class file by the compiler
but need not be retained by the VM at run time.
RUNTIME Annotations are to be recorded in the class file by the compiler and retained by
the VM at run time, so they may be read reflectively.
SOURCE Annotations are to be discarded by the compiler.
.

Categories

Resources