custom annotation parametrized inherit other annotation - java

I have one parametrized annotation (#MiTag1 in this case). And I want to create a new annotation (#MiTag2), that extends #MiTag1 and other annotation, and I want that the value of #MiTag1 "be extended" by the value of #MiTag2
With my code example, #MiTag2("bla") have to be the same as #MiTag1("bla"), but without hardcode "bla" inside #MiTag2.
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MiTag1 {
/**
* The resource key.
*
* #see Resources
*/
String value();
}
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#MiTag1(value = THIS.VALUE)
public #interface MiTag2 {
/**
* The resource key.
*
* #see Resources
*/
String value();
}

Java does not permit you to extend from another annotation. This is by design, as it would introduce a fairly complex type system. This question has been answer in detail here, but the important parts are:
Why don’t you support annotation subtyping (where one annotation type
extends another)?
It complicates the annotation type system, and makes it much more
difficult to write “Specific Tools”.
…
“Specific Tools” — Programs that query known annotation types of
arbitrary external programs. Stub generators, for example, fall into
this category. These programs will read annotated classes without
loading them into the virtual machine, but will load annotation
interfaces.
(original answer from pedromarce)
To bypass this problem, you can either annotate your target type with both annotations
#MiTag1 #MiTag2 and set the default value of the should inheriting annotation to the value of the parent annotation.
Also, you can use composition over inheritence and add an annotation of type #MiTag2 to #MiTag2.

Related

How to make custom request mapping annotation with spring to add prefixes?

Using spring boot 2 on java 11, I want to make a custom annotation for each REST API version (eg: "/api/v1/") that can be joined with subsequent URI components as below:
#APIv1("/users/") // this annotation should prepend "/api/v1/{argument}"
public class UserController {
#GetMapping("/info")
public String info() {return "This should be returned at /api/v1/users/info/";}
/* More methods with mappings */
}
The problem is I don't know how to define that #APIv1 annotation.
From what I've searched, I referenced https://stackoverflow.com/a/51182494/ to write the following:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#RestController
#RequestMapping("/api/v1")
#interface APIv1 {
#AliasFor(annotation = RestController.class)
String value() default "";
}
But this cannot handle arguments. Doing the same as above will route to /api/v1/info/ whether the argument is given or not. It's better than nothing since I can switch the method annotation to #GetMapping("/users/info"), but I was wondering if there was a way to combine the constant with an argument to reduce repetition across method annotations within the same controller class.
In #APIv1 you defined:
#RequestMapping("/api/v1")
So it is working as you told it to.

Java annotation cannot be found per reflection on a Kotlin data class

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.

How can I disallow to use my own annotation for all classes instead of classes implementing concrete interface

I have the following code. I need to allow usage of this annotation (CommandName) ONLY for classes-instances of ICommand interface. How can I do it?
#Retention(RetentionPolicy.RUNTIME) // Make this annotation accessible at runtime via reflection.
#Target({ElementType.TYPE}) // This annotation can only be applied to class methods.
public #interface CommandName {
String value();
}
In compile time, you cant do that. In runtime, just check the classes - which is annotated by CommandName annotation - if they are implementing the ICommand interface.

How #Target(ElementType.ANNOTATION_TYPE) works

Java annotations are marked with a #Target annotation to declare possible joinpoints which can be decorated by that annotation. Values TYPE, FIELD, METHOD, etc. of the ElementType enum are clear and simply understandable.
Question
WHY to use #Target(ANNOTATION_TYPE) value? What are the annotated annotations good for? What is their contribution? Give me an explanation of an idea how it works and why I should use it. Some already existing and well-known example of its usage would be great too.
You can use an annotated annotation to create a meta-annotation, for example consider this usage of #Transactional in Spring:
/**
* Shortcut and more descriptive "alias" for {#code #Transactional(propagation = Propagation.MANDATORY)}.
*/
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Transactional(propagation = Propagation.MANDATORY)
public #interface RequiresExistingTransaction {
}
When you enable Spring to process the #Transactional annotation, it will look for classes and methods that carry #Transactional or any meta-annotation of it (an annotation that is annotated with #Transactional).
Anyway this was just one concrete example how one can make use of an annotated annotation. I guess it's mostly frameworks like Spring where it makes sense to use them.
Each annotation annotated by #Target(ElementType.ANNOTATION_TYPE) is called Meta-annotation. That means, you can define your own custom annotations that are an amalgamation of many annotations combined into one annotation to create composed annotations.
A good example from Android world is StringDef
Denotes that the annotated String element, represents a logical type and that its value should be one of the explicitly named constants.
#Retention(SOURCE)
#StringDef({POWER_SERVICE, WINDOW_SERVICE, LAYOUT_INFLATER_SERVICE})
public #interface ServicesName {}
public static final String POWER_SERVICE = "power";
public static final String WINDOW_SERVICE = "window";
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
Code inspector will treat #ServicesName and #WeekDays in the same way as #StringDef.
As a result we can create as much named StringDef's as we need and override set of constants. #Target(ElementType.ANNOTATION_TYPE) it is a tool that allows to extend the use of annotations.
Annotation is defined like a ordinary Java interface, but with an '#' preceding the interface keyword (i.e., #interface ). Annotations are used to provide supplemental information about a program. On the other hand, an interface can be defined as a container that stores the signatures of the methods to be implemented in the code segment.
WHY to use #Target(ANNOTATION_TYPE) value?
When there is need to apply an annotation to an another annotation. If you look at the source codes of the common Java annotations, you see often this code pattern:
#Target(ANNOTATION_TYPE)
public #interface TheAnnotation
{
...
}
For example,
#Documented
#Target({ ANNOTATION_TYPE })
#Retention(RUNTIME)
public #interface Constraint {
public Class<? extends ConstraintValidator<?, ?>>[] validatedBy();
}
What are the annotated annotations good for?
They are good or more precisely necessary if they are used to annotate other annotations.
What is their contribution?
They make possible to apply an annotation directly to an another annotation, that is a different thing than applying an annotation to a standard Java class or to method and so on.
Give me an explanation of an idea how it works and why I should use it.
For example, if you create a data model class and you may want that the program checks data validity. In that case, there might be need to create a new annotation and apply another annotations to this annotation. It is simple to add some data validity checks to this model by adding annotations to the class. For example, to check that some value is not null (#notNull) or email is valid (#ValidEmail) or length of a field is more than x characters (#Size). However, it is possible that there is not built in Java annotations for all purposes. For example, it is so if you liked to check if password and its matchingPassword are same. This is possible by creating the annotation class PasswordMatches:
#Target({TYPE})
#Retention(RUNTIME)
#Constraint(validatedBy = PasswordMatchesValidator.class)
#Documented
public #interface PasswordMatches {
String message() default "Passwords don't match";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Note, there is line
#Constraint(validatedBy = PasswordMatchesValidator.class).
In other words, the annotation class Constraint, like the other annotations in this class also, must have ANNOTATION_TYPE as a value of target annotation.
Now the password equality check is easy to include to data model class simply by adding annotation #PasswordMatches:
#PasswordMatches
public class UserDto {
...
}
The PasswordMatchesValidator class could look like this:
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, Object> {
#Override
public void initialize(final PasswordMatches constraintAnnotation) {}
#Override
public boolean isValid(final Object obj, final ConstraintValidatorContext context) {
final UserDto user = (UserDto) obj;
return user.getPassword().equals(user.getMatchingPassword());
}
}
Some already existing and well-known example of its usage would be great too.
There is quite well-known example in item 4, but another known annotations which are applied frequently to custom annotations are #Retention, #Documented and #Target itself.
For example, if annotation looks like
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface SomeAnnotation {
String description() default "This is example for class annotation";
}
the compiler will complain in this situation
#SomeAnnotation
public class SomeClass {
#SomeAnnotation // here it's complaning
public void someMethod(){}
}
If you change
#Target(ElementType.TYPE)
to
#Target({ElementType.METHOD, ElementType.TYPE})
it won't complain anymore.
Annotation are basically additional metadata (information) that goes along with your code. It can be placed along side types (Classes, Interfaces), methods, and arguments.
It is often useful during compile time and runtime. Many popular APIs such as Java EE 5+, Spring, AspectJ leverage annotation for code clarity and consistency.
Using annotation often allows code to be more readable, more easily understood.
I'd recommend you read through the annotation chapter on Java tutorial
In the past metadata are often given as an xml file, and it's difficult for someone trying to understand the code if they have to lookup a different xml configuration file. The latest Java servlet API allows mapping of servlet simply by using annotation -- as opposed of web.xml mapping:
#WebServlet("/response")
public class ResponseServlet extends HttpServlet {
// servlet code here...
}

Why the JVM omit the Annotation

i am debugging a application using OSGi, i terribly find out that if the Annotation class is missing, the class loader would omit that annotation, if i call the method.getAnnotations(), no exception, but return nothing.
i don't get it, but i do want to know if there is any way to make the JVM throw a Exception.
is there any option for starting the JVM?
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Before
public #interface Secured {
/** Priority **/ public int order() default 0;
/** Mapping **/ public String value() default "profile/validate";
/** Required **/ public boolean required() default true;
public String role() default "L1";
}
Thanks.
is your annotation retained at runtime? that is it have the #Retetntion annotation set to RUNTIME:
#Retention(RUNTIME)
public #interface YourAnnotation
Every annotation has a retention defined to it. Retention basically means, in which contexts should the JVM save the annotation. Different values can be seen here. The default behavior is CLASS retention policy, which means the annotations are in the .class files, but aren't used by the JVM. What you want is RUNTIME, whose meaning is clear I guess. Also, there's a SOURCE policy, for annotations that are only relevant during compile-time.
To set the retention policy, you have to annotate the annotation (meta-meta, anyone?), using #Retention, which you can read more about here.
The Java annotation tutorial has a bit more information about this.

Categories