How to combine multiple annotations to single one? - java

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

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.

How annotation is processed if my custom annotation is itself annotated?

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?

can I use any annotation on custom annotation

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.

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

#Documented annotation in java

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

Categories