Can we set Annotation id at runtime - java

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.

Related

Using one annotation as a member of another annotation in Java

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.

Is it possible to conditionally apply annotation in an annotation?

I'm trying to do something like the following:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface AnnotationOne {
boolean annotationTwoToggler() default false
{
if (annotationTwoToggler) {
// Apply annotation AnnotationTwo to calling type
}
}
}
An example of how I would use this:
#AnnotationOne(true) // Implies AnnotationTwo
public class MyClass { ... }
AnnotationTwo and its implementations are in the API that I'm using, and cannot be changed. I want to cause all implementations of AnnotationTwo to trigger given a true parameter to AnnotationOne.
How can I do this?

Define custom annotation within another custom annotation with default value

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

How to pass value to custom annotation in java?

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.

How to create custom annotation in java?

I want to create custom annotation in java for DirtyChecking. Like I want to compare two string values using this annotation and after comparing it will return a boolean value.
For instance: I will put #DirtyCheck("newValue","oldValue") over properties.
Suppose I made an interface:
public #interface DirtyCheck {
String newValue();
String oldValue();
}
My Questions are:
Where I make a class to create a method for comparison for two string values? I mean, how this annotation notifies that this method I have to call?
How to retreive returning values of this method ?
First you need to mark if annotation is for class, field or method. Let's say it is for method: so you write this in your annotation definition:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface DirtyCheck {
String newValue();
String oldValue();
}
Next you have to write let's say DirtyChecker class which will use reflection to check if method has annotation and do some job for example say if oldValue and newValue are equal:
final class DirtyChecker {
public boolean process(Object instance) {
Class<?> clazz = instance.getClass();
for (Method m : clazz.getDeclaredMethods()) {
if (m.isAnnotationPresent(DirtyCheck.class)) {
DirtyCheck annotation = m.getAnnotation(DirtyCheck.class);
String newVal = annotation.newValue();
String oldVal = annotation.oldValue();
return newVal.equals(oldVal);
}
}
return false;
}
}
Cheers,
Michal
To answer your second question: your annotation can't return a value. The class which processes your annotation can do something with your object. This is commonly used for logging for example.
I'm not sure if using an annotation for checking if an object is dirty makes sense except you want to throw an exception in this case or inform some kind of DirtyHandler.
For your first question: you could really spent some effort in finding this yourself. There are enough information here on stackoverflow and the web.
CustomAnnotation.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface CustomAnnotation {
int studentAge() default 21;
String studentName();
String stuAddress();
String stuStream() default "CS";
}
How to use the field of Annotation in Java?
TestCustomAnnotation.java
package annotations;
import java.lang.reflect.Method;
public class TestCustomAnnotation {
public static void main(String[] args) {
new TestCustomAnnotation().testAnnotation();
}
#CustomAnnotation(
studentName="Rajesh",
stuAddress="Mathura, India"
)
public void testAnnotation() {
try {
Class<? extends TestCustomAnnotation> cls = this.getClass();
Method method = cls.getMethod("testAnnotation");
CustomAnnotation myAnno = method.getAnnotation(CustomAnnotation.class);
System.out.println("Name: "+myAnno.studentName());
System.out.println("Address: "+myAnno.stuAddress());
System.out.println("Age: "+myAnno.studentAge());
System.out.println("Stream: "+myAnno.stuStream());
} catch (NoSuchMethodException e) {
}
}
}
Output:
Name: Rajesh
Address: Mathura, India
Age: 21
Stream: CS
Reference

Categories