Said in Javadoc:
If a type is annotated with this annotation type, compilers are
required to generate an error message unless ...
Why isn't SOURCE or CLASS enough, like for #Override.
The #FunctionalInterface annotation serves two purposes. Regarding the compiler and the error it has to generate it would be indeed enough to have a SOURCE RetentionPolicy as in this regard it only affects the very class annotated with #FunctionalInterface.
However, it has a second purpose, documenting the fact that using this interface as a functional interface is indeed intended and the possibility to use it this way not just a coincidence like with, e.g. Comparable which is not intended to be used that way.
Therefore it is annotated with #Documented and has the maximum RetentionPolicy to fulfill the second purpose.
"Source" would not be enough, since if for example you create an API and provide your class as a pre-compiled jar, the information would not be available for the compiler anymore.
I believe "class" would also not be enough if you want to support those kind of compilers that "compile" against a class at runtime, like scripting engines that use reflection to find out about those annotations and should show a warning, too.
#FunctionalInterface is for runtime reflection, compile check, and java runtime process probably.
javap is used to de-compile and compare two interfaces, one with #FunctionalInterface, the other none.
Just extra two lines byte code in #FunctionalInterface tagged interface:
Constant pool:
#7 = ... RuntimeVisibleAnnotations
#8 = ... Ljava/lang/FunctionalInterface;
And both implementation/lambda express are same at byte code level.
Except for interface reflection:
X.class.getAnnotation(FunctionalInterface.class) == null?;
Related
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.
Java 14 introduces a new annotation #Serial in the java.io package. Its brief description in the API docs:
Indicates that an annotated field or method is part of the serialization mechanism defined by the Java Object Serialization Specification.
As far as I understand the annotation is used for the compile-time validation (similarly to #Override) to check whether the serialization mechanism methods and fields are used correctly. What I don't understand, does the annotation affect the de/serialization itself as long as it is a part of the serialization mechanism? Or is it a first step to improve the de/serialization feature design in the way suggested with this comment?
So if it should be the whole picture, add them all: #Serializable, #NotSerializable, #Transient and make Serializable deprecated…
I am confused of its use and I haven't found any code using it. Would you provide a sample code highlighting the issues when the annotation is not used but should be?
What I don't understand, does the annotation affect the
de/serialization itself
No. Its retention is 'source', so it's discarded after compilation. The bytecode will contain no trace of it. It has no way to influence runtime behaviour (besides possibly compile-time code generation, which does not happen).
Like #Override, it is optional and is supposed to give some compile-time assurance for problems which might otherwise not be caught until runtime.
For example, misspelling serialVersionUID:
#Serial
private static final long seralVersionUID = 123L; // compile-time error, should be 'serialVersionUID'
Or the wrong access modifier
// compile-time error, must be private
#Serial
public void writeObject(java.io.ObjectOutputStream out) throws IOException
Basically, something annotated with this must exactly match the descriptions of the 7 applicable elements mentioned in the JavaDoc (5 methods, 2 fields). If the signature of a method does not match, or the modifiers are wrong, you will catch the problem before serialization fails at runtime.
This annotation exists purely to engage better compile-time type checking. It is analogous in this way to the #Override annotation, which exists purely to capture design intent, so that humans and tools have more information to work with. The #Override annotation does not make a method declaration an override of another -- that is handled by the language based on comparing names, signatures, and accessibility between the method and methods in the supertype(s). What #Override does is assert that "I think this is an override, if I am mistaken, please tell me in the form of a compilation error." And it serves as notice to readers of the code that this method is not new with this class.
Because serialization uses "magic" method and field names (methods like readObject are not part of any interface, they are just magically given significance by serialization), and the determination of whether the magic works is tricky (methods must not only have the right name and arguments, but the right accessibility and static-ness), it is easy to declare a method that you think is meant to be used by serialization, but for which serialization doesn't agree.
The #Serial annotation lets you make a similar kind of assertion: that you intend that this is one of those magic serialization members (fields and methods), and if it does not match the profile, the compiler should alert you with an error. And it provides a similar hint to readers that this member is going to be used by serialization.
Most developers probably won't bother with this for application and domain code. But library authors may find it useful as a way to engage stronger type checking and better capture design intent.
Said in Javadoc:
If a type is annotated with this annotation type, compilers are
required to generate an error message unless ...
Why isn't SOURCE or CLASS enough, like for #Override.
The #FunctionalInterface annotation serves two purposes. Regarding the compiler and the error it has to generate it would be indeed enough to have a SOURCE RetentionPolicy as in this regard it only affects the very class annotated with #FunctionalInterface.
However, it has a second purpose, documenting the fact that using this interface as a functional interface is indeed intended and the possibility to use it this way not just a coincidence like with, e.g. Comparable which is not intended to be used that way.
Therefore it is annotated with #Documented and has the maximum RetentionPolicy to fulfill the second purpose.
"Source" would not be enough, since if for example you create an API and provide your class as a pre-compiled jar, the information would not be available for the compiler anymore.
I believe "class" would also not be enough if you want to support those kind of compilers that "compile" against a class at runtime, like scripting engines that use reflection to find out about those annotations and should show a warning, too.
#FunctionalInterface is for runtime reflection, compile check, and java runtime process probably.
javap is used to de-compile and compare two interfaces, one with #FunctionalInterface, the other none.
Just extra two lines byte code in #FunctionalInterface tagged interface:
Constant pool:
#7 = ... RuntimeVisibleAnnotations
#8 = ... Ljava/lang/FunctionalInterface;
And both implementation/lambda express are same at byte code level.
Except for interface reflection:
X.class.getAnnotation(FunctionalInterface.class) == null?;
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 {
}
I have some questions about working of annotations in java.
If annotations cannot be converted to bytecode then where does this information go?
where does the meta-data goes?
How Java Reflection uses this information?
How compiler deals with annotations?
When we say,
#Override
public void doSomething(){
}
What does a java compiler do with it?
I know that it checks the method signature so that the method should be a perfectly overridden method, but how?
There are three types of annotations see http://download.oracle.com/javase/6/docs/api/java/lang/annotation/RetentionPolicy.html
#Override is a special case as the compiler does additional checks.
#Override is a source type annotation - used to check if a particular method follows the contract of an overriden method - hence it isn't available at runtime (and therefore logically doesn't exist in the compiled bytecode).
I know that it checks the method signature so that the method should be a perfectly overridden method, but how
In the process of reading the source files and converting them to bytecode, e.g., not using reflection at all. See The Java Programming Language Compiler - javac for additional compiler information.
Annotations have a RetentionPolicy, which specifies if the annotation will be stored in the class file (RetentionPolicy.CLASS, RetentionPolicy.RUNTIME) or will be discarded by the compiler (RetentionPolicy.SOURCE).
The #Override method has a RetentionPolicy of RetentionPolicy.SOURCE (meaning it is discarded by the compiler and not available at runtime via Reflection) and a target of ElementType.METHOD (meaning that this method can only be annotated on method declarations only).
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.SOURCE)
public #interface Override {
}
Only annotations with a RetentionPolicy of RetentionPolicy.RUNTIME can be read by Reflection.
At first, there were 2 kinds of annotations: Runtime accessible (2 kinds) and not runtime accessible. The behavior of annotation is done by retention policy through annotation of annotation declaration :-). Example:
#Retention(RetentionPolicy.RUNTIME) // effectively visible to JVM Runtime
public #interface MethodInfo {
String author() default "unspecified";
String lastModification() default "unspecified"; // Format: yyyy-mm-dd
ImplementationStatus implementationStatus();
}
JVM runtime visible annotations can be accessed through reflection during annotated code execution (or when it is loaded by the JVM). You utilize those annotations as metadata holders. Metadata can be processed by other code to do various things eg. to check annotated method implementation status before a given method is executed.
But someone must write code to use the annotation matedata through reflection! The best example is an application server (AS) that loads classes on demand from JAR files placed is some particular directory. AS can contain code that checks each loaded class for static methods annotated by the #Initialization annotation and executes those methods right away. This annotation type is defined by AS and those who create JARs and classes for AS use it during development.
Annotations that are not available during runtime are used and worked out during compilation. #Override is good example. Custom source only annotations can be used by compiler plugins or if code is compiled by other code on demand.
This one is simple. Compiler just checks the super class for method with same name and same number of parameters, their order and types. If method has #Override annotation and such method hasn't been found an error is generated.
More interesting question is how compiler deals with annotations which has mean at runtime. I assume they are added in byte-code but in some special section with meta information. So, in runtime jvm has access to the meta section. As a prove, you can always call getAnnotations() on any class object.
Compiled annotations (which are ultimately constant data) live the class file and can be accesses with the appropriate methods getAnnotations() and friends.