I am trying to declare custom annotation in following way:
Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface InnerAnnotation {
}
Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface OuterAnnotation {
public String default "";
public InnerAnnotation innerAnnotation(); //here I wanted to do "public InnerAnnotation innerAnnotation() default {some default value}"
}
I wanted to use it in a way:
class first{
#OuterAnnotation(value = "new") //wanted to declare something like this without need to define innerAnnotation
public void func(){
}
}
I wanted to assign some default value to inner annotation usage(so that I don't have to provide any mandatory value while using it), but some how I am not able to do that as compiler asks for compile time constant for this.Can any please suggest how to use inner annotation with any default value ?
The syntax for what you what is as follows:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface OuterAnnotation {
public String default "";
public InnerAnnotation innerAnnotation() default #InnerAnnotation(); //this does the trick;
}
Related
I am new to Java annotation. I have used the following annotation in my Spring boot application as follows:
Original annotation definition:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation {
EntityType entityType();
ActionType actionType();
Resource resourceType();
}
Now I would like to move actionType() and resourceType() to a different annotation say MySubAnnotation and use it in the original above annotation MyAnnotation as follows:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation {
EntityType entityType();
MySubAnnotation mySubAnnotation();
}
But I am facing an issue with using this as follows:
#MyAnnotation(entityType = EntityType.MY_ENTITY,
mySubAnnotation = <???>) <---HERE I CANNOT UNDERSTAND WHAT TO SPECIFY
#MySubAnnotation(actionType=ActionType.UPDATE,
resourceType=Resource.MY_RESOURCE)
public void myMethod() {
...
}
As mentioned above, I cannot understand what to specify for sub annotation. Could anyone please help here? Thanks.
You didn’t include the declaration of your MySubAnnotation. Besides that, the syntax for the actual annotation values is not different for nested annotations. You just have to place it after the =:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation {
EntityType entityType();
MySubAnnotation mySubAnnotation();
}
#Retention(RetentionPolicy.RUNTIME)
#Target({})
public #interface MySubAnnotation {
ActionType actionType();
Resource resourceType();
}
#MyAnnotation(
entityType = EntityType.MY_ENTITY,
mySubAnnotation = #MySubAnnotation(
actionType = ActionType.UPDATE,
resourceType = Resource.MY_RESOURCE
)
)
public void myMethod() {
}
Note that in this example, MySubAnnotation has an empty list of targets, i.e. #Target({}) which permits it only as a value within other annotations. Of course, you could add other permitted targets. That would not affect its use as “sub annotation”, as that’s always allowed.
But there’s not much advantage in designing annotation parts as sub annotation here. All you’ve achieved, is requiring more typing. One imaginable possibility, is to provided a default here, e.g.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyAnnotation {
EntityType entityType();
MySubAnnotation mySubAnnotation() default
#MySubAnnotation(actionType=ActionType.UPDATE, resourceType=Resource.MY_RESOURCE);
}
The difference to just specifying defaults for actionType and resourceType is that now, the developer may use the default for MySubAnnotation, i.e. both values, or has to specify explicit values for both, they can not override only one of them.
I have a custom annotation which is declared as below and have some implementation for this.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface SampleTestCase {
public int caseID() default -1;
public int suiteId() default -1;
}
Now, I am trying to use this annotation and trying to send runtime parameters to it.
ConfigHelper config = new ConfigHelper();
int caseId = config.getTestCaseID();
#SampleTestCase(caseID=caseId,suiteId="Test")
public void testCaseOne(){
Assert.assertTrue(true);
}
Getting an error as "The value for annotation attribute TivoTestCase.caseID must be a constant expression".
Is there any way to pass dynamic parameters to an annotation other than this way??
my custom annotation is:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface CacheClear {
long versionId() default 0;
}
I want to achieve something like this, in which I can pass the method param "versionTo" to my custom annotation.
#CacheClear(versionId = {versionTo})
public int importByVersionId(Long versionTo){
......
}
What should I do?
That's not possible.
Annotations require constant values and a method parameter is dynamic.
You cannot pass the value, but you can pass the path of that variable in Spring Expression and use AOP's JoinPoint and Reflection to get and use it. Refer below:
Your Annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface CacheClear {
String pathToVersionId() default 0;
}
Annotation Usage:
#CacheClear(pathToVersionId = "[0]")
public int importByVersionId(Long versionTo){
......
}
Aspect Class:
#Component
#Aspect
public class YourAspect {
#Before ("#annotation(cacheClear)")
public void preAuthorize(JoinPoint joinPoint, CacheClear cacheClear) {
Object[] args = joinPoint.getArgs();
ExpressionParser elParser = new SpelExpressionParser();
Expression expression = elParser.parseExpression(cacheClear.pathToVersionId());
Long versionId = (Long) expression.getValue(args);
// Do whatever you want to do with versionId
}
}
Hope this helps someone who wants to do something similar.
Is there a way by which I can set the id inside annotated method...
Annotation class:
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public
#interface MyAnnotation {
int id();
}
//Set id at runtime
public class A {
#MyAnnotation(id = ? )
public void method1() {
// I want to set the id here for my annotation...
}
}
Yes, but it's a bit unintuitive. You'll have to edit its bytecode using a tool like JavaAssist.
Here is an article describing what you're after.
I defined my own custom annotation
#Target(value={ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyCustomAnnotation {
Class<?> myType();
}
how, if at all, can I make the attribute optional
You can provide a default value for the attribute:
#Target(value={ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyCustomAnnotation {
Class<?> myType() default Object.class;
}
Found it. It can't be optional, but a default can be declared like this:
#Target(value={ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyCustomAnnotation {
Class<?> myType() default String.class;
}
If no default can make sense as "empty" value then that is a problem.
For Optional attribute you need to provide default value for that attribute you can provide default value using "default" keyword.
Note : For only one attribute you can use attribute name as value.
If you use your attribute name as value you can directly pass value like this #MyCustomAnnotation(true) instead of #MyCustomAnnotation(myType = true).
See this example for more details