I use several #PreAuthorize-base annotations for protecting my REST API methods.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasRole('ROLE_A') or hasRole('ROLE_B')")
public #interface ForAorB {
}
and at the same time I have
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasRole('ROLE_A')")
public #interface ForA {
}
and
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasRole('ROLE_B')")
public #interface ForB {
}
My #PreAuthorize expressions are a bit more complex than simple hasRole('ROLE_x) and I would like not to doubling them both in #ForA, #ForB and in #ForAorB.
Whether it possible to create #ForAorB annotation bases on #ForA and #ForB and not expressions doubling in #PreAuthorize("hasRole('ROLE_A') or hasRole('ROLE_B')")?
I tried this but looks like
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#ForA #ForB
public #interface ForAorB {
}
works actually as #ForAandB but not #ForAorB
That won't work, because annotations (at least in this case) are "additive". A single #PreAuthorize annotation will give you OK or NOK, and that determines the whole outcome regardless of any other possible auth annotations.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#ForA #ForB
public #interface ForAorB {
}
is the same as
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasRole('ROLE_A')")
#PreAuthorize("hasRole('ROLE_B')")
public #interface ForAorB {
}
So for AND it works, but you can't get it to work with OR except writing the #PreAuthorize annotation by hand.
Related
I am trying to create an annotation by combining annother's functionality. Let's say as below:
#Documented
#Retention(RUNTIME)
#Target({TYPE, METHOD})
#Around
#io.micronaut.tracing.annotation.NewSpan
public #interface NewSpan {
String value() default "";
}
Now it's seems impossible to pass the value to io.micronaut.tracing.annotation.NewSpan, after searching many other answers and java docs, it seems impossible to me, any help.
So when I use my #NewSpan("val"), it should be passed down to io.micronaut.tracing.annotation.NewSpan's value.
Thanks!
I believe that should be the same as in spring
#Documented
#Retention(RUNTIME)
#Target({TYPE, METHOD})
#Around
#io.micronaut.tracing.annotation.NewSpan
public #interface NewSpan {
#AliasFor(annotation = io.micronaut.tracing.annotation.NewSpan.class, member="value")
String value() default "";
}
So, I have created several custom annotations:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Foo {
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Bar {
}
Those annotations are used in my functions:
public class Worker {
#Foo
public void doTaskOne() {...}
#Bar
public void doTaskX() {...}
...
}
I want to use java reflection to check if certain annotation is declared in one method.
for (Method m : methods) {
if (m.isAnnotationPresent(Foo.class)) {
...
} else if (m.isAnnotationPresent(Bar.class)) {
...
}
}
The problem is that since in Java, custom annotation #interface is not able to be extended. I mean this is illegal:
public #interface Bar extends MyBaseAnnotation{
}
That's I am not able to have a base #interface for all my custom annotation class Foo and Bar. So, if I have a new custom annotation created, I need to add more else if condition in above method checking code, which sucks! Is there anyway to get rid of this problem? What I want to achieve is to generalize my method checking code to :
for (Method m : methods) {
if (m.isAnnotationPresent(MyBaseAnnotation.class)) {
...
}
}
How to achieve it?
You can annotate your custom annotations with a base custom annotation, like composed annotations do.
Instead of:
public #interface Bar extends MyBaseAnnotation{
}
use:
#MyBaseAnnotation
public #interface Bar {
}
Assuming that
#Parent
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface Foo {}
#Parent
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface Bar {}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.ANNOTATION_TYPE)
#interface Parent {}
and there is a method
public static boolean isAnnotationPresent(Method method, Class<? extends Annotation> parentAnnotation) throws NoSuchMethodException {
for (Annotation methodAnnotation : method.getDeclaredAnnotations()) {
if (methodAnnotation.annotationType().isAnnotationPresent(parentAnnotation)) {
return true;
}
}
return false;
}
you can do
isAnnotationPresent(m, Parent.class)
You got it right: there is no inheritance between annotation types in Java. You could make your own rules, though. By saying "if annotation B has annotation A over it, then B extends A", you define the rule that you will follow while using reflection.
I'm creating some annotations, and one of them I trying to enable to annotate twice. I use #Repeatable and created the conteiner. But when I use the annotation twice it appears that it needs to use #Repeatable.
As shown in the image below:
Message error: Duplicate annotation of non-repeatable type #TX2Value. Only annotation types marked #Repeatable can be used multiple times at one target.
#Repeatable(TX2ValueContainer.class)
#Retention(RUNTIME)
#Target({ FIELD, METHOD, ANNOTATION_TYPE, TYPE_USE })
public #interface TX2Value {
String name();
...
}
#Retention(RUNTIME)
#Target({ FIELD, METHOD, ANNOTATION_TYPE, TYPE_USE })
#interface TX2ValueContainer {
TX2Value[] value();
}
public void TestA() {
#TX2Value(name="test01")
#TX2Value(name="test02")
private String value;
}
My question is related to Java: Annotated Annotations (and passing values), but not entirely the same, so I thought I'd ask anyway. Especially since there were so few answers to that question.
Say I have written an annotation like this:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE})
public #interface NestedAnnotation {
public String value();
public Class<?> impl() default Void.class;
}
So if I want to use this, I have to do something like #NestedAnnotation("somevalue"). Now, what if I want to put that annotation inside another one:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#NestedAnnotation("need value here!")
public #interface OuterAnnotation {
public String value();
public Class<?> impl() default Void.class;
}
The NestedAnnotation needs a value, and adding a String (like above) works. But what if I wanted to pass on a value that was received by the OuterAnnotation? Is that possible?
I have written below the Custom Annotation.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
String value();
}
and am using the annotation as below.
#MyAnnotation("someValue")
public void someMethod(){
}
above code is working fine without any issues.
But in the annotation class, value() method name i have to reanme. Can i do as below?
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
String name();
}
I tried doing but eclipse is giving the compilation error.
- The attribute value is undefined for the annotation type
MyAnnotation
- The annotation #MyAnnotation must define the attribute
name
Any reason?
Use it like this :
#MyAnnotation(name="someValue")
public void someMethod(){
}
because by default annotation has value method so if you specify like this
#MyAnnotation("someValue")
public void someMethod(){
}
it will by default take it as value="someValue"