Java annotation multiple annotations

Multiple annotations of the same type on one element?

I’m attempting to slap two or more annotations of the same type on a single element, in this case, a method. Here’s the approximate code that I’m working with:

public class Dupe < public @interface Foo < String bar(); >@Foo(bar="one") @Foo(bar="two") public void haha() <> > 
max@upsight:~/work/daybreak$ javac Dupe.java Dupe.java:5: duplicate annotation

Is it simply not possible to repeat annotations like this? Pedantically speaking, aren’t the two instances of @Foo above different due to their contents being different? If the above isn’t possible, what are some potential workarounds? UPDATE: I’ve been asked to describe my use case. Here goes. I’m building a syntax sugarish mechanism to «map» POJOs to document stores such as MongoDB. I want to allow indexes to be specified as annotations on the getters or setters. Here’s a contrived example:

public class Employee < private Listprojects; @Index(expr = "project.client_id") @Index(expr = "project.start_date") public List getProjects() < return projects; >> 

Obviously, I want to be able to quickly find instances of Employee by various properties of Project. I can either specify @Index twice with different expr() values, or take the approach specified in the accepted answer. Even though Hibernate does this and it’s not considered a hack, I think it still makes sense to at least allow having multiple annotations of the same type on a single element.

Источник

Repeating Annotations

There are some situations where you want to apply the same annotation to a declaration or type use. As of the Java SE 8 release, repeating annotations enable you to do this.

For example, you are writing code to use a timer service that enables you to run a method at a given time or on a certain schedule, similar to the UNIX cron service. Now you want to set a timer to run a method, doPeriodicCleanup, on the last day of the month and on every Friday at 11:00 p.m. To set the timer to run, create an @Schedule annotation and apply it twice to the doPeriodicCleanup method. The first use specifies the last day of the month and the second specifies Friday at 11p.m., as shown in the following code example:

@Schedule(dayOfMonth=»last») @Schedule(dayOfWeek=»Fri», hour=»23″) public void doPeriodicCleanup()

The previous example applies an annotation to a method. You can repeat an annotation anywhere that you would use a standard annotation. For example, you have a class for handling unauthorized access exceptions. You annotate the class with one @Alert annotation for managers and another for admins:

@Alert(role=»Manager») @Alert(role=»Administrator») public class UnauthorizedAccessException extends SecurityException

For compatibility reasons, repeating annotations are stored in a container annotation that is automatically generated by the Java compiler. In order for the compiler to do this, two declarations are required in your code.

Читайте также:  Градиентный бустинг классификация python

Step 1: Declare a Repeatable Annotation Type

The annotation type must be marked with the @Repeatable meta-annotation. The following example defines a custom @Schedule repeatable annotation type:

import java.lang.annotation.Repeatable; @Repeatable(Schedules.class) public @interface Schedule

The value of the @Repeatable meta-annotation, in parentheses, is the type of the container annotation that the Java compiler generates to store repeating annotations. In this example, the containing annotation type is Schedules , so repeating @Schedule annotations is stored in an @Schedules annotation.

Applying the same annotation to a declaration without first declaring it to be repeatable results in a compile-time error.

Step 2: Declare the Containing Annotation Type

The containing annotation type must have a value element with an array type. The component type of the array type must be the repeatable annotation type. The declaration for the Schedules containing annotation type is the following:

public @interface Schedules

Retrieving Annotations

There are several methods available in the Reflection API that can be used to retrieve annotations. The behavior of the methods that return a single annotation, such as AnnotatedElement.getAnnotation(Class), are unchanged in that they only return a single annotation if one annotation of the requested type is present. If more than one annotation of the requested type is present, you can obtain them by first getting their container annotation. In this way, legacy code continues to work. Other methods were introduced in Java SE 8 that scan through the container annotation to return multiple annotations at once, such as AnnotatedElement.getAnnotationsByType(Class). See the AnnotatedElement class specification for information on all of the available methods.

Design Considerations

When designing an annotation type, you must consider the cardinality of annotations of that type. It is now possible to use an annotation zero times, once, or, if the annotation’s type is marked as @Repeatable , more than once. It is also possible to restrict where an annotation type can be used by using the @Target meta-annotation. For example, you can create a repeatable annotation type that can only be used on methods and fields. It is important to design your annotation type carefully to ensure that the programmer using the annotation finds it to be as flexible and powerful as possible.

Previous page: Type Annotations and Pluggable Type Systems
Next page: Questions and Exercises: Annotations

Источник

How to Merge Multiple Annotations in JAVA

Hello all, in this article I will demonstrate you how to use a common custom annotation to merge the other annotations in JAVA. If you need to use multiple annotations in your test classes, you can use this technique to merge some annotations. In this way, whenever you need to add or change some annotation for your test classes, you can easy to modify it in your base annotation.

Читайте также:  Python unix socket example

In order to do this, you need to create a custom annotation class. Let’s name it BaseTestAnnotation and lets add @RepeatedIfExceptionsTest(repeats = 3) annotation in this class. In this way, we can make this annotation as global to all of our test classes.

package annotations; import io.github.artsok.RepeatedIfExceptionsTest; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target() @Retention(RetentionPolicy.RUNTIME) @RepeatedIfExceptionsTest(repeats = 3) public @interface BaseTestAnnotation

After that, we can use BaseTestAnnotation class instead of @Test annotation as shown below.

and when we run our test, we will see that our tests will repeat 3 times when they fail.

If you want to change retry count in your tests, you can just change the retry count in BaseTestAnnotation file. If you don’t use this technique and if you put @RepeatedIfExceptionsTest(repeats = 3) annotation on top of your all test methods, then you need to change the repeat count for each test method. It will be a cumbersome process for us. But with common base test annotation, it will be so easy to change repeat count for all test methods.

Note: New JUnit 5 parallel execution feature is not compatible with Repeat feature. If you try to run your tests in parallel, they will run in parallel but they won’t rerun when they will fail. You can see this on below screenshot. Here is the comprehensive JUnit 5 Repeat Test article .

Onur Baskirt is a Software Engineering Leader with international experience in world-class companies. Now, he is a Software Engineering Lead at Emirates Airlines in Dubai.

Источник

Annotation of multiple types of annotation

I want to be able to annotate a class with a list of 2 types of annotations which are related in function, but are completely different in arguments. The order of this list matters though. I have tried looking for this already, but was unable to find any references to this (I was not sure what to call this). Edit: What I want to be able to do in the end:

//place holder for example (Abstract) public @interface A < >@Target(PARAMETER) public @interface B extends A < //Gets stuff Class type(); int key(); >@Target(PARAMETER) public @interface FlaggedListOfA extends A < //List of A A[] set(); >//Goal is to have annotation that does this @Target(METHOD) public @interface ImportantFunc < A[] dataForA() default <>; String[] names(); int property() default 0; //etc. > //End goal: public class SomeImportantClass < @ImportantFunc(dataForA = <@B(. ), @B(. >, . ) public void doStuff() < >//So I can have an end goal of this (Order matters, may contain repeats, //and has unknown length!) @ImportantFunc(dataForA = <@B(. ), @FlaggedListOfA(@B(. ), @B(. ))>, . ) public void doStuffB() < >@ImportantFunc(dataForA = <@FlaggedListOfA(@B(. )), @FlaggedListOfA(@B(. ), @B(. ))>, . ) public void doStuffC() < >@ImportantFunc(dataForA = <@FlaggedListOfA(@B(. ), @FlaggedListOfA(@B(. ), @B(. ))), @B(. )>, . ) public void doStuffD() < >> 

Reflections to get all uses of ImportantFunc (Ex: 100 uses of it) in package and uses this data to choose which function to use. The annotation is to help with the reflection since once it gets the data from @ImportantFunc, it then converts it to input for a library which does the actual choosing of which function to execute (this is internal and can not be modified). This could also be achieved with much longer and more annoying ways, but I was hoping to use annotations to simplify the process of defining all of these functions. Edit: Another way this could be solved is finding a way to group two annotations together. Being able to do this would not be completely ideal, but would definitely make this much more workable:

Источник

Combine multiple annotations into one to avoid repeating them

I’m working on the implementation of various REST services, using Spring MVC. For documentation, I’m using Swagger. This works nice and the documentation looks good and is really functional. The only problem I have is that the annotations for documentation really crowd the controller classes, especially the error code annotations. Example:

@ApiErrors(value = < @ApiError(code = 123, reason = "Reason123"), @ApiError(code = 124, reason = "Reason124"), @ApiError(code = 125, reason = "Reason125"), @ApiError(code = 126, reason = "Reason126"), @ApiError(code = 127, reason = "Reason127") >) public void exampleFunctionImplementation()

In many cases, this leads to large blocks of annotations where the real application code is hidden somewhere in between. In addition, this annotation sets are often repeated, as a lot of methods may return the same set of error codes. Is there any option to shorten this a bit through defining the annotation list somewhere else as a constant in another class file? Or maybe something even more simple I may have overlooked? I tried with defining the array of @ApiError items somewhere, but this won’t compile:

1 Answer 1

Annotation members have only limited types (JLS 9.6).

It is a compile-time error if the return type of a method declared in an annotation type is not one of the following: a primitive type, String, Class, any parameterized invocation of Class, an enum type (§8.9), an annotation type, or an array type (§10) whose element type is one of the preceding types.

Their values must be constant expressions (JLS 9.7). The standard uses the term commensurate.

T is an array type E[] and either:

V is an ElementValueArrayInitializer and each ElementValue (analogous to a VariableInitializer in an array initializer) in V is commensurate with E; or

V is an ElementValue that is commensurate with E.

The type of V is assignment compatible (§5.2) with T, and furthermore:

If T is a primitive type or String, and V is a constant expression (§15.28).

V is not null.

If T is Class, or an invocation of Class, and V is a class literal (§15.8.2).

If T is an enum type, and V is an enum constant.

Your array is not a constant expression, so your code won’t compile. If you anticipate having large annotation lists, perhaps there is another way to do this task. I don’t know Swagger, so you might not be able to avoid this, however.

Источник

Оцените статью