I know this #interface element is used to define annotations in Java.
I know annotations were introduced in Java 5.
My questions:
1) how is that element called (formally), and since when
is it recognized by the compiler i.e. when was it introduced?
Is it an annotation or a meta-annotation itself?
2) before Java 8 (e.g. in Java 5 or 6) was there some other element/way
used for defining annotations or had they always been defined that
way ever since their advent in the language?
how is that element called (formally), and since when is it recognized by the compiler i.e. when was it introduced?
An annotation type declaration. This was added in Java 5.
Is it an annotation or a meta-annotation itself?
No, #interface is not an annotation by itself, it's just the keyword interface preceded by an #. It's not a meta-annotation. A meta-annotation is an annotation that can be used on annotation type declarations. The JDK itself has a number of these (for example #RetentionPolicy).
before Java 8 (e.g. in Java 5 or 6) was there some other element/way used for defining annotations
No.
or they had they always been defined that way ever since their advent in the language?
Yes.
Annotations have been added in Java 5 and #interface was always the way to create annotations; there has not been any other mechanism in the past to create annotations.
Why #interface and not a new keyword such as annotation: This was done for backward compatibility. Adding a new keyword means you immediately create a backward compatibility issue, because programs written for the older version might have used the name of the keyword for example as a variable name. Such programs wouldn't compile anymore on the new version. So, when they want to add a new feature to Java, Oracle prefers re-using an existing keyword instead of creating a new one.
That said, new keywords have been added in the course of the evolution of Java, such as enum and assert (which were added in Java 1.4).
Related
Came across this #Deprecated() today. Curious to know #Deprecated vs #Deprecated() but both are resolving to the same interface Deprecated by the compiler.
Are they both different or are they same? Is there some practice to use one over another?
They both mean the same thing. #Deprecated is simply shorthand for #Deprecated(). See §9.7.2. Marker Annotations of the Java Language Specification:
A marker annotation is a shorthand designed for use with marker annotation types (§9.6.1).
MarkerAnnotation:
# TypeName
It is shorthand for the normal annotation:
#TypeName()
It is legal to use marker annotations for annotation types with elements, so long as all the elements have default values (§9.6.2).
Example 9.7.2-1. Marker Annotations
Here is an example using the Preliminary marker annotation type from §9.6.1:
#Preliminary public class TimeTravel { ... }
As of Java 8 the #Deprecated annotation had no elements, so it could only ever be a marker annotation. Since Java 9, however, it now has two elements: since and forRemoval. But since those elements have default values the annotation can still be used as a marker annotation.
It's not an interface, it is an annotation. #Deprecated and #Deprecated() are the same
Are there such things as Java annotations that aren't tied to any class, method, field, etc.?
Like just writing
#MyAnnotation(someParameter=value, ...)
by itself, and it generates code.
It seems like ExecutableType might define what kinds of "elements" an annotation can annotate, but I'm not sure. If that's true, then ExecutableType derives from TypeMirror, one of whose members are NoType. So maybe it's possible? But I cannot find an example of this.
You cannot have a stand-alone annotation in Java.
Annotations can be applied to different things, for example: types, methods, fields, local variables, packages, method parameters and also on annotation definitions.
One annotation that is meant to be used on annotation definitions (therefore it's called a "meta-annotation") is #Target, which you use to indicate on what things the annotation you are defining is allowed to be used. You do this by specifying one or more element types as an argument to the #Target annotation - see the API docs of java.lang.annotation.ElementType.
The Java Language Specification paragraph 9.6.4.1 explains what annotations can be used on in more detail.
Consider the following code:
A.java:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
#interface A{}
C.java:
import java.util.*;
#A public class C {
public static void main(String[] args){
System.out.println(Arrays.toString(C.class.getAnnotations()));
}
}
Compiling and running works as expected:
$ javac *.java
$ java -cp . C
[#A()]
But then consider this:
$ rm A.class
$ java -cp . C
[]
I would've expected it to throw a ClassNotFoundException, since #A is missing. But instead, it silently drops the annotation.
Is this behaviour documented in the JLS somewhere, or is it a quirk of Sun's JVM? What's the rationale for it?
It seems convenient for things like javax.annotation.Nonnull (which seems like it should've been #Retention(CLASS) anyway), but for many other annotations it seems like it could cause various bad things to happen at runtime.
In the earlier public drafts for JSR-175 (annotations), it was discussed if the compiler and runtime should ignore unknown annotations, to provide a looser coupling between the usage and declaration of annotations. A specific example was the use of applications server specific annotations on an EJB to control the deployment configuration. If the same bean should be deployed on a different application server, it would have been convenient if the runtime simply ignored the unknown annotations instead of raising a NoClassDefFoundError.
Even if the wording is a little bit vague, I assume that the behaviour you are seeing is specified in JLS 13.5.7: "... removing annotations has no effect on the correct linkage of the binary representations of programs in the Java programming language." I interpret this as if annotations are removed (not available at runtime), the program should still link and run and that this implies that the unknown annotations are simply ignored when accessed through reflection.
The first release of Sun's JDK 5 did not implement this correctly, but it was fixed in 1.5.0_06. You can find the relevant bug 6322301 in the bug database, but it does not point to any specifications except claiming that "according to the JSR-175 spec lead, unknown annotations must be ignored by getAnnotations".
Quoting the JLS:
9.6.1.2 Retention Annotations may be present only in the source code, or
they may be present in the binary form
of a class or interface. An annotation
that is present in the binary may or
may not be available at run-time via
the reflective libraries of the Java
platform.
The annotation type
annotation.Retention is used to choose
among the above possibilities. If an
annotation a corresponds to a type T,
and T has a (meta-)annotation m that
corresponds to annotation.Retention,
then:
If m has an element whose value is annotation.RetentionPolicy.SOURCE,
then a Java compiler must ensure that
a is not present in the binary
representation of the class or
interface in which a appears.
If m has an element whose value is annotation.RetentionPolicy.CLASS, or
annotation.RetentionPolicy.RUNTIME a
Java compiler must ensure that a is
represented in the binary
representation of the class or
interface in which a appears, unless m
annotates a local variable
declaration. An annotation on a local
variable declaration is never retained
in the binary representation.
If T does not have a (meta-)annotation
m that corresponds to
annotation.Retention, then a Java
compiler must treat T as if it does
have such a meta-annotation m with an
element whose value is
annotation.RetentionPolicy.CLASS.
So RetentionPolicy.RUNTIME ensures that the annotation is compiled into the binary but an annotation present in the binary doesn't have to be available at runtime
if you actually have code that reads #A and does something with it, the code has a dependency on class A, and it will throw ClassNotFoundException.
if not, i.e. no code cares specificly about #A, then it's arguable that #A doesn't really matter.
Section 4.7.16 of the JVM specification includes a description of "RuntimeVisibleAnnotations". I am wondering what can cause an attribute to be included in this attributes table, is this only by applying #Retention(RetentionPolicy.RUNTIME) on an attribute? Conversely, for "RuntimeInvisibleAnnotations" (see further in 4.7.17) is this #Retention(RetentionPolicy.CLASS) only or is it also #Retention(RetentionPolicy.SOURCE) ?
Compiling information from the JVM and JLS specifications gives us the following picture:
Annotations meta-annotated with the #Retention whose value is RetentionPolicy.SOURCE must not be present in the binary representation of the class or interface in which they appear, i.e. they are not to be recorded in the class file at all.
Annotations with the RetentionPolicy.CLASS must be represented in the binary representation of the class or interface in which they appear, unless they annotate a local variable declaration. An annotation on a local variable declaration is never retained in the binary representation.
So this is what the RuntimeInvisibleAnnotations attribute is designed for.
They need not be retained by the VM at run time, unless the Java Virtual Machine has been instructed to retain these annotations via some implementation-specific mechanism such as a command line flag.
Annotations with the RetentionPolicy.RUNTIME are to be recorded in the class file by the compiler and must be available at run time via reflection libraries. This is for the RuntimeVisibleAnnotations attribute.
I'm using java 6 annotation processing api. I have followed the following excellent tutorial for creating an annotation processor that displays a message at build-time:
http://kerebus.com/2011/02/using-java-6-processors-in-eclipse/
However, in my case, I have a simple class as such:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(value = ElementType.METHOD)
public #interface Criteria {
String id();
double width();
double height();
}
As you can see, the aforementioned annotation is made available to the JVM at runtime using the meta-annotation 'Retention'. I use this 'Criteria' annotation in the source code of another class to annotate a method, like so:
#Criteria(id = "fooBar",
width = 22,
height = 10
)
public void fooStream() {
System.out.println("foo stream method");
}
At runtime, I want to include the 'fooStream' method in another class, ONLY if variables that are passed in match the values of the elements in the #Criteria annotation, namely 'width' and 'height'. My question is, how could I take the method 'fooStream' and inject this into another class at run-time? Is this even possible? I'm not looking for any code examples, just answers to the two aforementioned questions. Also, in the link at the top, there is an example of generating a code using 'JavaFileObject' and 'Writer' instances, where the generated code is passed as a string.
I don't believe Java supports runtime type mutation, meaning to modify the members on a given class you'd have to drop back to a compile time preprocessor or to a bytecode modification scheme.
I'd be able to point you in a better direction if I understood the "why" behind this question, but in the mean time, dynamic proxy classes might get you to where you want to be (JavaWorld article).
From the documentation:
A dynamic proxy class is a class that
implements a list of interfaces
specified at runtime such that a
method invocation through one of the
interfaces on an instance of the class
will be encoded and dispatched to
another object through a uniform
interface. Thus, a dynamic proxy class
can be used to create a type-safe
proxy object for a list of interfaces
without requiring pre-generation of
the proxy class, such as with
compile-time tools. Method invocations
on an instance of a dynamic proxy
class are dispatched to a single
method in the instance's invocation
handler, and they are encoded with a
java.lang.reflect.Method object
identifying the method that was
invoked and an array of type Object
containing the arguments.
Here's a decent tutorial on using Spring to inject dynamic proxies based on custom annotations. I think this is probably closest to the behavior you're after.
If you want runtime modification of you classes, you can use your own classloader and intercept loading of classes, introspect what you want and generate new bytecode using asm library instead of original classes. It is not very tricky, but you must be sure you need exactly that.