Reputation: 3255
In my project I use pre-defined annotation @With
:
@With(Secure.class)
public class Test { //....
The source code of @With
:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface With {
Class<?>[] value() default {};
}
I want to write custom annotation @Secure
, which will have the same effect as @With(Secure.class)
. How to do that?
What if I do like this? Will it work?
@With(Secure.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Secure {
}
Upvotes: 75
Views: 104646
Reputation: 51
If you need to set some field you can use @AliasFor. Example.
Instead of using this verbose annotations:
@Test
@Sql(
config = SqlConfig(
dataSource = "myDataSource",
transactionManager = "myTransactionManager",
),
scripts = ["/myScript.sql"],
)
test()
I can create my own annotation that will container those that I want to customize. Note that I had to use the @aliasFor annotation to keep my ability to customize some fields:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Sql(config = @SqlConfig(
dataSource = "mnDataSource",
transactionManager = "myTransactionManager"
))
public @interface SqlMyDB {
@AliasFor(annotation = Sql.class, attribute = "scripts")
String[] scripts() default {};
}
Now I can simply do:
@Test
@SqlMyDB(scripts = ["/myScript.sql"])
test()
Note that @AliasFor is a Spring annotation and will only work if:
Upvotes: 4
Reputation: 1109
So the provided answer from Eric Jiang is 100% working in my situation and she is: I need JMSListener ,but i want to hide the destination name:
@GetPlayerDataByUUIDListener
public void getPlayerDataByUUID(Object message) {
System.out.println("Im Here");
}
`
@JmsListener(destination = PlayerStatisticsJMSConstants.GET_PLAYER_DATA_BY_UUID)
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface GetPlayerDataByUUIDListener {
}
So this is working perfectly ,and it is the same as:
@JmsListener(destination = "example")
@GetPlayerDataByUUIDListener
public void getPlayerDataByUUID(Object message) {
System.out.println("Im Here");
}
Upvotes: 1
Reputation: 41
You can use annotation for annotation like this:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@WithSecurityContext(factory = WithCustomUserSecurityContextFactory.class)
public @interface WithCustomUser {
String username() default "[email protected]";
String password() default "demo";
String[] authorities() default {Authority.USER};
}
And define exact state in its "child"
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@WithCustomUser(username = "[email protected]",
password = "admin",
authorities = {Authority.USER, Authority.ADMINISTRATOR})
public @interface WithAdminUser {
}
In this case you have a some kind of "state" and access to the parent annotation fields via reflection/aspect.
Upvotes: 1
Reputation: 583
To expand on Muhammad Abdurrahman's answer--
@With(Secure.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Secure {
}
This does not work by default but you can use it in conjunction with Spring's AnnotationUtils.
See this SO answer for an example.
Upvotes: 14
Reputation: 164
@With(Secure.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Secure {
}
This will work.
Upvotes: 10
Reputation: 709
As piotrek pointed out, you cannot extend Annotations in the sense of inheritance. Still, you can create Annotations that aggregate others:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SuperAnnotation {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SubAnnotation {
SuperAnnotation superAnnotation();
String subValue();
}
Usage:
@SubAnnotation(subValue = "...", superAnnotation = @SuperAnnotation(value = "superValue"))
class someClass { ... }
Upvotes: 38
Reputation: 14530
From Java language specification, Chapter 9.6 Annotation Types:
No extends clause is permitted. (Annotation types implicitly extend
annotation.Annotation
.)
So, you can not extend an Annotation. you need to use some other mechanism or create a code that recognize and process your own annotation. Spring allows you to group other Spring's annotation in your own custom annotations. but still, no extending.
Upvotes: 30