use of custom annotations - java

I found several related (not duplicate) question to this, but they didn't satisfy me.
I am unable to understand where and why to use custom annotations?
I read an example of custom annotation in a book, but it was not explained thoroughly.
#interface MyAnno
{
String str();
int val();
}
class MyClass
{
#MyAnno(str = "Annotation example", val = 100)
public static void myMeth()
{
System.out.println("Inside myMeth()");
}
}
class CustomAnno
{
public static void main(String args[])
{
MyClass.myMeth();
}
}
The output is as expected Inside myMeth().
I am having few questions regarding this example.
1- How can I use String str() and int val() in this program? OR
What is the use of any abstract method of an custom annotation?
2- Why custom annotations. I mean that what effect they are having on any code.
3- How can I create an annotation which is having effects like #override is having?(I mean any kind of effect which can be noticed)
If this example is useless for you, then please give me a suitable small example in which a custom annotation is used.

Three main reasons to use custom annotations are:
To reduce the effort of writing code (a compile-time annotation processor generates code for you). Here is a tutorial: part 1, part 2.
To provide additional correctness guarantees (a compile-time annotation processor warns you about errors). One nice tool for this is the Checker Framework, which prevents null pointer dereferences, concurrency errors, and more.
To customize behavior (at run time, your code checks for the annotation using reflection and behaves differently depending on whether the annotation is present). Frameworks such as Hibernate use annotations this way; also see an Oracle article.
In each case, use of annotations reduces the likelihood of errors in your code, compared to other non-annotation approaches.

Here is a minimal example. The following code demonstrates use of custom annotation.
It is about Employees and Benefits. If we have a requirement such that BasicBenefits has to be applied to all types of employess then we can come up with custom annotation such as BasicBenefits, and annotate all types of Employee implementations (e.g. CorporateEmployee, ContractEmployee, ManagerEmployee etc. etc.) with the BasicBenefits.
Custom Annotation Class(interface)
import java.lang.annotation.*;
#Inherited
#Documented
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#interface BasicBenefits {
String bId() default "B-101";
String bName() default "General Class A Employee";
}
Class using the custom annotation(no need of any imports):
#BasicBenefits(bId="B-400", bName="General Plus Class A Employee")
public class Employee {
String eId;
String eName;
public Employee(String eId, String eName){
this.eId = eId;
this.eName = eName;
}
public void getEmployeeDetails(){
System.out.println("Employee ID: "+eId);
System.out.println("Employee Name: "+eName);
}
}
Driver class to test out the above.
import java.lang.annotation.Annotation;
public class TestCustomAnnotationBasicBenefits {
public static void main(String[] args) throws Exception{
Employee emp = new Employee("E-100", "user3320018");
emp.getEmployeeDetails();
Class reflectedClass = emp.getClass();
Annotation hopeBenefitAnn = reflectedClass.getAnnotation(BasicBenefits.class);
BasicBenefits bBenefits = (BasicBenefits)hopeBenefitAnn;
System.out.println("Benefit ID: "+bBenefits.bId());
System.out.println("Benefit Name: "+bBenefits.bName());
}
}
Your code look almost there, just two things need to be included in the main method.
1.) Need reference to MyClass
2.) Need to get the annotation using reflection from MyClass.
Here is a bit modified code from what you have:
#Inherited
#Documented
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#interface MyAnno
{
String str();
int val();
}
//using above custom annotation on class level
//can also use method level
//just need to change t #Target(ElementType.METHOD)
#MyAnno(str = "Annotation example", val = 100)
class MyClass
{
public static void myMeth()
{
System.out.println("Inside myMeth()");
}
}
import java.lang.annotation.Annotation;
class CustomAnno
{
public static void main(String args[])
{
//1. getting reference to the class where the custom annotation is applied.
//2. then getting the annotation to get the values
MyClass myClass = new MyClass();
Class cls = myClass.getClass();
Annotation getMyAnno = cls.getAnnotation(MyAnno.class);
MyAnno myAnno = (MyAnno)getMyAnno;
MyClass.myMeth(); //left this as is.
System.out.println("myAnno.str(): "+ myAnno.str());
System.out.println("myAnno.str(): "+ myAnno.val());
}
}

The abstract methods of the annotation define the values you can pass to it (in your case str = "Annotation example", val = 100). You can access them using reflection (Method.<T>getAnnotation(Class<T>)). Custom annotations don’t have direct impact. They are only useful if you evaluate them.
Note that you have to annotate your custom annotation with #Retention(value=RUNTIME) to be able to read it via reflection.

To be of any use, annotations must be parsed first. The built-in annotations (such as #Override or #FunctionalInterface, to name the most obvious ones) are parsed by the compiler itself. As for custom annotations, these guys are commonly parsed by third-party frameworks, although we can also use the reflection mechanism to demonstrate this technique in standalone code.
By way of an example, the code below changes its behaviour at run time depending on the value of the field declared in the custom annotation named #SwitchingAnnotation:
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#interface SwitchingAnnotation{
boolean flag();
}
public class Worker{
void doThis(){ System.out.println("Doing this"); }
void doThat(){ System.out.println("Doing that"); }
#SwitchingAnnotation(
flag = false
)
public void work(boolean flag) {
if (flag) doThis();
else doThat();
}
}
class Test{
public static void main(String[] args) {
try{
SwitchingAnnotation sw = Worker.class.getMethod("work", boolean.class)
.getAnnotation(SwitchingAnnotation.class);
new Worker().work(sw.flag()); // prints Doing that
}
catch(NoSuchMethodException nsme){
System.out.println(nsme);
}
}
}

Related

How to force annotations to have an "id" field?

I have the following annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface IdentifiableMethod {
String id() default "";
}
I will have to loop through a list of annotations and for each of them, perform a annotation.id().
Hence, I would have liked to use this "base" annotation to make it extended by other annotations:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface SpecificMethod extends IdentifiableMethod{
//invalid: annotation cannot have extends list
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface OtherSpecificMethod extends IdentifiableMethod{
//invalid: annotation cannot have extends list
}
... and then generically access the .id() method in a loop by getting in parameter a List<A extends IdentifiableMethod>, so that the compiler always makes me access that method.
However, I've just found out that in the Java specification, all Java annotations extend natively the interface Annotation and they cannot have an extends list [Source: this Stack Overflow question and its answers].
Is there any way to reach something similar?
Just to clarify the need, I need to get all the methods of all the classes within my package by reflection and scan for these annotations. They may be different (they may have more or less properties, different usages etc.), but they all need to have a String id field:
List<Class<?>> classes = getClasses(packageName);
for (Class<?> clazz : classes) {
for (Method method : clazz.getMethods()) {
for (Class<A> annotation : annotations) { //<-- annotations is a Collection<Class<A extends Annotation>>
if (method.isAnnotationPresent(annotation)) {
A targetAnnotation = method.getAnnotation(annotation);
String id = targetAnnotation.id(); //<-- this is not valid because A extends Annotation, not IdentifiableMethod
//rest of code (not relevant)
}
}
}
}
P.s. I already did this but I was looking for something cleaner:
String id = targetAnnotation.getClass().getMethod("id").invoke(targetAnnotation).toString();

aspect is not invoked

I've got a simple aspect that supposed to set the value of class fied, that has annotation #GuiceInject.
Originally I have this
#GuiceInject(module=RepositoryModule.class)
private IRacesRepository repository;
And I expect to get similar to this
private IRacesRepository repository = GuiceInject.getInstance(IRacesRepository.class);
And here is my aspect
public aspect InjectionAspect {
Object around(): get(#GuiceInject * *) {
System.out.println(thisJoinPointStaticPart);
// instantiate object as it supposed to be null originally
return GuiceInjector.getInstance(thisJoinPoint.getTarget().getClass());
}
}
As far as I understand - I am new to AOP - it supposed to replace get invokations of the field with the code in aspect.
It compiles fine, but when I run the application - nothing happens. I get NullPointerException for readRaces method as it stays null so aspect did not work.
My main class looks like this
public class Example {
#GuiceInject(module=RepositoryModule.class)
private IRacesRepository racesRepository;
private void execute() {
System.out.println("List of races: " + racesRepository.readRaces());
}
public static void main(String[] args) {
new Example().execute();
}
}
What is the problem? Annotation has this definition
#Target(ElementType.FIELD)
// make annotation visible in runtime for AspectJ
#Retention(RetentionPolicy.RUNTIME)
public #interface GuiceInject {
Class<? extends AbstractModule> module();
}
Please try to redefine pointcut syntax as
Object around(): get(#package.subpackage.GuiceInject * *.*)
Correct field signature must specify the type of the field, the declaring type, and name. If your annotation is in different package, it should be fully qualified.

Get the class on which the annotation is applied

I am building a custom annotation inside which there is a field of Class type. How do I set a value in it while using the annotation?
Code is given below :
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SpringCache {
String putIt();
String getIt();
Class c();
}
This is my custom annotation. Now while I use it how do I give class to variable "c"?
#SpringCache(putIt="I'm put", getIt="I'm get", c=<??>)
public class TestSpringCache {
public static void main(String[] args) {
System.out.println();
}
}
As in this case I want c=TestSpringCache.class.
You just write the class you want:
#SpringCache(putIt="I'm put", getIt="I'm get", c=TestSpringCache.class)
public class TestSpringCache {
public static void main(String[] args) {
System.out.println();
}
}
You might have to add an import statement, if it is not in the same package.
You have to optain all class instances from ApplicationContext (you can inject it), ctx.getBean(). There you can check if an annotation is present.
Actually I didn't find the solution for this. As said by many it does not seem to be possible. Though I have found a work around this.
I removed the class type and kept only String and Boolean type variable there, and to get the annotated classes I took the path from the user to the package containing classes with the defined annotation. And then for each class in the package I checked for the annotation. If annotation was present I did what I wanted to, else did nothing.
Thanks to everyone for giving your time to this.

How to ensure annotations execution order in java?

i have 2 custom annotations, but one should always executed before the other. How do i ensure this? Is there some kind of ordering or do it with additional method definitions?
You can ensure the order of your custom annotations with #Order annotation.
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/Order.html
Example:
First annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface CustomAnnotation {
}
#Aspect
#Component
#Order(value = 1)
public class CustomAnnotationInterceptor {
#Before("#annotation(customAnnotation )")
public void intercept(JoinPoint method, CustomAnnotation customAnnotation ) {
//Code here
}
}
Second annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface CustomAnnotationTwo {
}
#Aspect
#Component
#Order(value = 2)
public class CustomAnnotationInterceptorTwo {
#Before("#annotation(customAnnotationTwo )")
public void intercept(JoinPoint method, CustomAnnotationTwo customAnnotationTwo ) {
//Code here
}
Using them:
#CustomAnnotationTwo
#CustomAnnotation
public void someMethod(){
}
In this example, CustomAnnotationInterceptor will execute first.
From http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/aop.html#aop-ataspectj-advice-ordering
Spring AOP follows the same precedence rules as AspectJ to determine the order of advice execution. The highest precedence advice runs first "on the way in" (so given two pieces of before advice, the one with highest precedence runs first). "On the way out" from a join point, the highest precedence advice runs last (so given two pieces of after advice, the one with the highest precedence will run second).
When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise the order of execution is undefined. You can control the order of execution by specifying precedence. This is done in the normal Spring way by either implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with the Order annotation. Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.
When two pieces of advice defined in the same aspect both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the declaration order via reflection for javac-compiled classes). Consider collapsing such advice methods into one advice method per join point in each aspect class, or refactor the pieces of advice into separate aspect classes - which can be ordered at the aspect level.
I know this is very old question, but I just wanted to document my findings. Can anyone please confirm if these are correct?
It is already mentioned in this page that Spring documentation says that execution of annotations is undefined unless #Order annotation is used.
I tried to rename the Aspect classes, and tested many times, and found that Aspect classes are executed in alphabetical order of their names and found that the result is consistent.
Below is my sample code:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface A {}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface B {}
#Aspect
public class A_Aspect {
#Around("#annotation(mypackage.A)")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("A_Aspect");
joinPoint.proceed();
}
}
#Aspect
public class B_Aspect {
#Around("#annotation(mypackage.B)")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("B_Aspect");
joinPoint.proceed();
}
}
class AdvisedClass{
#B
#A
public void advisedMethod(){}
}
When I tried to execute advisedMethod(), following are the logs I received:
A_Aspect
B_Aspect
I changed annotation declaration sequence:
#A
#B
public void advisedMethod(){}
Following are the logs:
A_Aspect
B_Aspect
I renamed Annotation #A to #C, Following are the logs:
A_Aspect
B_Aspect
But, when I tried to rename Aspect class A_Aspect to C_Aspect, Following are the logs:
B_Aspect
C_Aspect
As I said, I want someone to confirm this as I could not find any documentation for this
Checkout https://stackoverflow.com/a/30222541/810109: At least in Java 8 you can retrieve annotations in a guaranteed order, so you just have to declare them in the right order.
First annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface FirstAnnotation {
String value() default "";
}
Second annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface SecondAnnotation {
String value() default "";
}
Usage example:
public class Test {
#SecondAnnotation("second annotation")
#FirstAnnotation("first annotation")
private String annotatedField1 = "value of field 1";
#SecondAnnotation("second annotation")
#FirstAnnotation("first annotation")
private String annotatedField2 = "value of field 2";
#SecondAnnotation("second annotation")
private String annotatedField3 = "value of field 3";
#FirstAnnotation("first annotation")
private String annotatedField4 = "value of field 4";
// Sample
public static void processAnnotatedFields( final Object obj ) throws IllegalArgumentException, IllegalAccessException {
for ( final Field field : getFieldsFornAnotation( obj, FirstAnnotation.class ) ) {
// Do something with fields that are annotated with #FirstAnnotation
final FirstAnnotation an = field.getAnnotation( FirstAnnotation.class );
System.out.print( "#" +an.annotationType().getSimpleName()+ "(" +an.value()+ "): " );
System.out.println( field.getName()+ " = '" +field.get(obj)+ "'" );
}
System.out.println();
for ( final Field field : getFieldsFornAnotation( obj, SecondAnnotation.class ) ) {
// Do something with fields that are annotated with #SecondAnnotation
final SecondAnnotation an = field.getAnnotation( SecondAnnotation.class );
System.out.print( "#" +an.annotationType().getSimpleName()+ "(" +an.value()+ "): " );
System.out.println( field.getName()+ " = '" +field.get(obj)+ "'" );
}
}
/**
* Collect object fields annotated with "annotationClass"
* This can be saved in static map to increase performance.
*/
private static final Set<Field> getFieldsFornAnotation( final Object o, final Class<? extends Annotation> annotationClass ) {
final Set<Field> fields = new LinkedHashSet<Field>();
if ( o == null || annotationClass == null )
return fields;
for (final Field field : o.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(annotationClass)) {
field.setAccessible( true );
fields.add( field );
}
}
return fields;
}
public static void main(final String[] args) throws IllegalArgumentException, IllegalAccessException {
processAnnotatedFields( new Test() );
}
}
Result/output:
#FirstAnnotation(first annotation): annotatedField1 = 'value of field 1'
#FirstAnnotation(first annotation): annotatedField2 = 'value of field 2'
#FirstAnnotation(first annotation): annotatedField4 = 'value of field 4'
#SecondAnnotation(second annotation): annotatedField1 = 'value of field 1'
#SecondAnnotation(second annotation): annotatedField2 = 'value of field 2'
#SecondAnnotation(second annotation): annotatedField3 = 'value of field 3'
You can do it by using EJB interceptors.
you can simply add interceptors via #Interceptors( { MyInterceptor.class } ) and then add for second one #MyInterceptorConfiguration(value=something).
As bkail says in their answer here:
This is only possible with CDI stereotype
annotations (see the interceptor
bindings page for examples) in EE 6 (EJB 3.1).
Yes I think Annotation itself provide annotation for that like #First, and #Second etc. so you can try that

Java Annotations not working

I'm trying to use Java annotations, but can't seem to get my code to recognize that one exists.
What am I doing wrong?
import java.lang.reflect.*;
import java.lang.annotation.*;
#interface MyAnnotation{}
public class FooTest
{
#MyAnnotation
public void doFoo()
{
}
public static void main(String[] args) throws Exception
{
Method method = FooTest.class.getMethod( "doFoo" );
Annotation[] annotations = method.getAnnotations();
for( Annotation annotation : method.getAnnotations() )
System.out.println( "Annotation: " + annotation );
}
}
You need to specify the annotation as being a Runtime annotation using the #Retention annotation on the annotation interface.
i.e.
#Retention(RetentionPolicy.RUNTIME)
#interface MyAnnotation{}
Short answer: you need to add #Retention(RetentionPolicy.RUNTIME) to your annotation definition.
Explanation:
Annotations are by default not kept by the compiler. They simply don't exist at runtime. This may sound silly at first, but there are lots of annotations that are only used by the compiler (#Override) or various source code analyzers (#Documentation, etc).
If you want to actually USE the annotation via reflection like in your example, you'll need to let Java know that you want it to make a note of that annotation in the class file itself. That note looks like this:
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation{}
For more information, check out the official docs1 and especially note the bit about RetentionPolicy.
Use #Retention(RetentionPolicy.RUNTIME)
Check the below code. It is working for me:
import java.lang.reflect.*;
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
#interface MyAnnotation1{}
#Retention(RetentionPolicy.RUNTIME)
#interface MyAnnotation2{}
public class FooTest {
#MyAnnotation1
public void doFoo() {
}
#MyAnnotation2
public void doFooo() {
}
public static void main(String[] args) throws Exception {
Method method = FooTest.class.getMethod( "doFoo" );
for( Annotation annotation : method.getAnnotations() )
System.out.println( "Annotation: " + annotation );
method = FooTest.class.getMethod( "doFooo" );
for( Annotation annotation : method.getAnnotations() )
System.out.println( "Annotation: " + annotation );
}
}

Categories

Resources