I'm a newbie with Java programming. While i'm learning Java Annotation, I digged a little big deeper into the declaration of #Target in JDK and i got this
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.ANNOTATION_TYPE)
public #interface Target {
ElementType[] value();
}
What confuses me here is that #Target Annotation declares Target Annotation.
Where comes the very first #Target annotation ?
Where comes the very first #Target annotation ?
During compilation, the compiler finds (and defines/registers) the annotation type Target. It will then scan the type for annotations and find #Target which was already defined, so no issue.
Related
Given this Java annotation
#Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
#JacksonAnnotation
public #interface JsonProperty
and this Kotlin data class
#JsonIgnoreProperties(ignoreUnknown = true)
data class LossDocument(#JsonProperty("id") val id: String)
I would expect to find the annotation either here
LossDocument::class.java.declaredFields[0].annotations
or here
LossDocument::class.java.declaredMethods.first { it.name == "getId" }
but both have zero annotations. Is this a bug? Per 53843771, my impression is this should work. I'm using Kotlin 1.4.0.
When I declare the annotation explicitly as #field:JsonProperty("id") I can find it without problem using LossDocument::class.java.declaredFields[1].annotations.
When you're annotating a property or a primary constructor parameter, there are multiple Java elements which are generated from the corresponding Kotlin element, and therefore multiple possible locations for the annotation in the generated Java bytecode.
If you don't specify a use-site target, the target is chosen according to the #Target annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following list is used:
param, property, field. -- Annotation Use-site Targets
In your case the annotation is placed on the constructor parameter.
I am trying to write my first custom annotation.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.Type)
#PreAuthorize("hasAnyRole(#exp)")
public #interface CustomPreAutorize{
String exp();
}
The above does not compile as I do not know how can I supply exp value to hasAnyRole method in PreAuthorize.
I have following questions:
Can I use SpEL (Spring expression language) over annotation?
If I put #CustomPreAutorize on my method will that also call
#PreAuthorize with exp value with out explicit annotation processor?
What is right way to use one annotation with another?
As, I know we can apply annotation like #Target, #Retention, #Documented on custom annotation.
But recently I saw #Constraint applied on custom annotation.
Can We use any annotation on custom annotation? how it works?
Each annotation can only be written in certain places. Those places are determined by the #Target meta-annotation on the annotation's definition. For example, if an annotation is declared as
#Target(ElementType.ANNOTATION_TYPE)
public #interface MyAnnotation {
...
}
then #MyAnnotation may only be written on annotation declarations. You cannot write #MyAnnotation on a field or class declaration, or on a type use. An annotation that may be written on annotation declarations is called a meta-annotation.
You can learn more about annotations from the Java annotations tutorial.
I have two annotations from a framework. Often I use those two annotations both on the same field. Thus I'm trying to create a "combined" annotation that contains that both two.
But I don't know if it is possible at all:
The existing annotations (that I have no control of):
#Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface ApiParam {
String name() default "";
}
#Target({ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface ApiModelProperty {
String name() default "";
}
My Custom annotation that I'm trying to create:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.ANNOTATION_TYPE)
#ApiParam
#ApiModelProperty
public #interface SwaggerParam {
String name() default "";
}
Result: the annotations are not applicable to annotation type.
Question: Is there any chance?
Unfortunately you can't do this since it is not possible to extend annotations.
Is there something like Annotation Inheritance in java?
When I first answered this I was initially confused by the Spring framework approach to this shortcoming whereby they use meta level annotations (such as #Component as a meta annotation for #Controller/#Configuration etc.) as a sort of workaround.
See: https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-annotation-config
Composing annotations like you did can only be done if your framework supports scanning for meta-annotations. Thus the framework not only has to scan for direct annotations but also for an annotation's meta-annotations recursively.
Multiple frameworks support this, some of which are:
junit: https://junit.org/junit5/docs/current/user-guide/#writing-tests-meta-annotations
Spring: https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/meta-annotation.html
Swagger: https://stackoverflow.com/a/53266819/1235217
What's the purpose of #Documented annotation in java?
I saw the documentation, but could not get much from it. Can someone point out with the help of an clear example
#Documented is a meta-annotation. You apply #Documented when defining an annotation, to ensure that classes using your annotation show this in their generated JavaDoc. I've not seen much use of it, but there is an example here. An earlier question suggests that it doesn't work automatically in Eclipse, but I've tested in Eclipse 3.6, and my annotations appear in the JavaDoc popups whether or not I attach the #Documented annotation to them.
Here's an example from Spring, which ensures that transactional methods are marked as such in the JavaDoc:
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Inherited
#Documented
public #interface Transactional {
If some our annotation (for example, #InWork) is #Documented, then for every class having that #InWork annotation the text generated by javadoc will contain #InWork text, as a reference to the annotation.
Annotation:
#Documented
#Inherited // for descenders of the annotation to have the #Documented feature automatically
#Retention(RetentionPolicy.RUNTIME) // must be there
public #interface InWork {
String value();
}
Annotated target:
/**
* Annotated class.
*/
#InWork(value = "")
public class MainApp {...}
The javadoc text:
So, you have to decide, if the annotation should be shown in the javadoc text, and if yes, set #Documented to it.
The information above is taken from Oracle documentation.
Please, notice, that in Eclipse you'll see in javadoc generated text ALL annotations, are they #Documented, or not.
It is still correct for 4.3 version.
I found a useful page in the Java Tutorials which gives examples and more explanation for a number of standard annotations, including one use of #Documented. Specifically, look at the Note block at the bottom for the Preamble example (section Documentation).