Is it possible to create a Java annotation with reverse / inverse / negation logic.
For e.g., I created a filter in Javax:
#Provider
#AuthBinding
public class AuthServerFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {...}
And created AuthBinding annotation as:
#NameBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface AuthBinding {
}
So , the above filter will be triggered for only the rest resources with the annotation #AuthBinding.
Is it possible to create an annotation, so that above filter is applied on all the rest resources except the ones which have annotation.
Such frameworks work by explicitly marking "things". The framework scans classes, objects, methods for annotations, and then runs the corresponding code.
There is no notion of "if an annotation X isn't given, then do this or that, depending on X".
And not it is not only technology here. It is a bad design idea! Especially in such a REST resource context, your readers expect that looking at the resource tells them all they need to know about it.
Well, one option exists: you can of of course configure your own filters or interceptors. And those could check if a selected resource does have or not have a specific annotation on it before doing this or that.
Related
i've tried in various ways to replicate the #PreAuthorize behaviour, so spel expression with a Method Invocation context:
-I started with configuring httpSecurity in my WebSecurityConfigurerAdapter extending class with an access string written in spel, only to figure out the context was on Filter Invocation , so I had no access on the request body(which i need);
-implementing and adding a custom HandlerInterceptor to the InterceptorRegistry, but again the endpoint arguments were not accessible;
-extending ConfigGlobalMethodSecurity to create a custom expressionHandler, but I seems it is only triggered by Method-level annotations;
Can someone explain me if what i've trying to do is simply impossible or is there a way?
I'd like to have the same evaluationContext as #PreAuthorize, so having access the method arguments(I mean the value they assume) using spel expressions and be able to configure it without having to annotate every single class or method.
EDIT
for reference these are the two annotations i'm using(and they work fine) the use i'm tring to replicate not by annotations but by configuration:
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasAnyRole(#privilegeManager.privilegedRoles) or (#privilegeManager.verify(#id, this.getType()))")
public #interface PathVariableRestriction {
}
#Target({ ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasAnyRole(#privilegeManager.privilegedRoles) or #dto.getOwnerId() == #myService.getCurrentId()")
public #interface RequestBodyRestriction {
}
i'd like to authorize request not based on roles but on ids: the id of the object being subject to the crud operation provided either as #PathVariable or #RequestBody(depends on if it is a get, post, put or delete) and the id of the current user retrieved through his Authentication
This is one common use case for #PostAuthorize.
For example if you do:
#PostAuthorize("returnObject.username == authentication.name")
#GetMapping("/resource/{id}")
public MyResource getResource(String id) {
// look up
return myResource;
}
This will only return resources that belong to the currently authenticated user.
This is the recommended route.
able to configure it without having to annotate every single class or method
Alternatively, you can build your own custom authorization method security from scratch using Spring Security's underlying components.
Method Security is built on top of Spring AOP. This means that you can define your own pointcut instead of using Spring Security's annotation-based one. For example, you can do:
#EnableMethodSecurity
class SecurityConfiguration {
#Bean
#Role(BeanDefinition.ROLE_INFRASTRUCTURE)
Advisor myMethodSecurityAdvisor() {
Pointcut pointcut = myCustomPointcut();
AuthorizationManager<MethodInvocationResult> rules = myRules();
AuthorizationManagerAfterMethodInterceptor interceptor =
new AuthorizationManagerAfterMethodInterceptor(
pointcut, rules);
interceptor.setOrder(AuthorizationInterceptorsOrder.
POST_AUTHORIZE.getOrder() + 1);
return interceptor;
}
}
I have created my custom annotation:
#Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface Condition {
String value();
}
I want to use this annotation to determine whether or not to run advice, my try:
#Condition("some.config")
#Around("execution(public * someMethod())")
Object doSomething(ProceedingJoinPoint joinPoint) throws Throwable {
// some logic here
}
#Around("#annotation(condition)")
Object checkCondition(ProceedingJoinPoint joinPoint, Condition condition) throws Throwable {
String property = (String) configuration.getProperty(condition.value());
if (Boolean.valueOf(property)){
return joinPoint.proceed();
} else {
return null;
}
}
It works when I use #Condition on some other methods, i.e. the checkCondition is applied and then the method is executed or not based on config value. For advice doSomething it doesn't get applied though.
You said your aspect works for other components, just not the aspect itself. From this statement I gather that
your aspect is wired correctly (e.g. annotated with #Component and detected by component scan or wired manually via XML config) and
you use proxy-based Spring AOP.
In (2) is the source of your problem. According to the Spring manual aspects themselves are exempt from being aspect targets themselves:
Advising aspects with other aspects?
In Spring AOP, it is not possible to have aspects themselves be the target of advice from other aspects. The #Aspect annotation on a class marks it as an aspect, and hence excludes it from auto-proxying.
So M. Prokhorov is somewhat wrong when saying that aspects are not (or cannot be) Spring components, but he is right insofar as by design you cannot self-advise an aspect or advise other aspects. His assumption that it may work with AspectJ is also correct. It does work with AspectJ, so if you need it to you can configure Spring to use AspectJ via LTW instead of Spring AOP for this case.
I am writing a library/sdk which can intercept any methods which are annotated with a custom annotation #Monitor.
The code works somewhat like this
#Monitor
public void methodA(String test)
And the aspect which intercepts this has this pointcut expression
#After("execution(#com.packageA.Monitor * *(..))")
public void intercept(final JoinPoint joinPoint){
...}
This code works fine when I describe the aspect in the same package as the methodA. However if I create a separate library and define the aspect in that its not able to intercept the methodA . Any help?
EDIT
In response to #Bond's comment
#Component
#Target(value = {ElementType.METHOD, ElementType.TYPE})
#Retention(value = RetentionPolicy.RUNTIME)
public #interface Monitor {
}
Spring versions:
spring-context - 4.1.7.Release
aspectj - 1.6.5
The crux of the problem is that the annotation wont be used in the same project. After compilation it will be used in a different project all together.
EDIT2
The 2nd project i.e the one from which this aspect should be intercepting is compiled using aspectj maven plugin
You need to update the pointcut to #annotation(com.x.y.z.Monitor). (correct the package name accordingly)
Thus your aspect should look something like below
#After("#annotation(com.x.y.z.Monitor)")
public void intercept(final JoinPoint joinPoint){
...
}
Have a look at examples for reference about various pointcut expressions available. Also read this in case advise accepts argument(s)
I have seen few examples where customized annotations were used. example
#SimpleAnnotation
class SampleBean {
#SimpleAnnotation
public String getName() {
return "AAA";
}
public void setName(String name) {
}
public int getHeight() {
return 201;
}
}
#Target( { ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#interface SimpleAnnotation {
}
Can anyone tell why we use this?
Spring supports for many Annotation the concept of "meta-annotation". (I am not sure if it is for all.)
This mean that you can build your own annotation and annotate the annotation with one of springs "core" annotations.
For example:
#Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Service
public #interface MyService {
}
Then you can use this annotation instead of #Service. (Btw: #Service, #Repository, #Controller use the same technique to "inherit" from #Component)
One example that make heavy use of this is "inherit" from #Qualifier.
For an example and some explanation have a look at Spring Reference Chapter: 3.9.3 Fine-tuning annotation-based autowiring with qualifiers (The Example with #Genre is at the end of the chapter.)
One very usefull construct that can be done with that technique is, that it enables you to combine several Annotations to a (in your use case) more meaning full. So instead of writing at every class of some type allways the same two annotations, for example: #Service and #Qualifiyer("someting") (the org.springframework.beans.factory.annotation.Qualifier). You can create your custom annotation that is annotated with this two annotations, and then use in your beans only this one custom annotation. (#See Avoid Spring Annotation Code Smell Use Spring 3 Custom Annotations)
If you want to see how powerfull this technique can be use, you can have a look at Context and Dependency Injection Framework.
Question from the comment:
The #interface also has some variables defined inside it, what does that signify?
The Annotations (defined by #Interface) work a bit like beans. This Fields are the properties that can/must be define if you use the annotations. The values can be later on be read via reflection API.
For example the #Controller Annotation in Spring:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Controller {
String value() default "";
}
The field with name value is that field that can be used without explicit name it: (#Controller("myUrl") is the same #Controller(value="myUrl"))
You can create your own meta-annotations that collect several other Spring annotations to reduce meta-boilerplate in your code:
#Service
#Scope(value = "prototype")
#Transactional(readOnly = true, rollbackFor = RuntimeException.class)
public #interface ReadOnlyService {}
And then you can simply write:
#ReadOnlyService
public class RoleService {
}
Spring will find the #ReadOnlyService and semantically replace it with:
#Service
#Scope(value = "prototype")
#Transactional(readOnly = true, rollbackFor = RuntimeException.class)
public class RoleService {
}
Of course having custom annotations pays of when you have tons of services annotated with the same set of Spring annotations that can be replaced with one, well named annotation.
Examples taken from: Avoid Spring Annotation Code Smell: Use Spring 3 Custom Annotations
Custom annotations do not do anything on their own. They are simple markers in code. Their real power comes from tools that look for specific annotations. Like some of the other answers mention, Spring has several uses for annotations and now mechanisms for defining your own component types. Pretty neat. Another example, a few weeks ago I used AOP and a few custom annotations to provide simple method level result caching. Now that I have the caching engine in place, and the appropriate AOP hooks defined, if I want to cache a method, I simply add that annotation. Some people simply use the annotations as fancy metadata to improve readability.
At the end of the day, they are a fairly simple tool that you can use for a great number of things.
The best part of using custom annotations is that you don't have to make any configuration, Spring will auto detect that these beans are service components and everything will work fine. Custom Annotations are a very small feature added in Spring but are very useful.For details take a look at this
http://java.dzone.com/articles/avoid-spring-annotation-code-smell-use-spring3-custom-annotations
Two options:
you need the #Component annotation on your custom annotation. That way you can use your custom annotation to mark classes as beans. In addition, you can add a default scope and other meta-information
qualifiers - you can use qualifier annotations (annotated with the #Qualifier meta-annotation) to distinguish between implementations of the same interface.
A common pattern is also to use annotations in AOP pointcuts. Not specifically Spring, but often employed when making use of Spring AOP.
First of all: I want to use Java EE not Spring!
I have some self defined annotations which are acting as interceptor bindings. I use the annotations on my methods like this:
#Logged
#Secured
#RequestParsed
#ResultHandled
public void doSomething() {
// ...
}
For some methods I want to use a single of these annotations but most methods I want to use like this:
#FunctionMethod
public void doSomething() {
// ...
}
Can I bundle these set of annotations to a single one? I cannot write the code in a single interceptor because for some methods I want to use them seperately too.
I know that there is a #Stereotype definition possible, but as far as I know, this is used to define a whole class not a single method.
With help of some well-known search engine I found the solution in the documentation of JBoss Weld (Chapter 9.6 Interceptor binding with inheritance)
I can use an interceptor binding interface which is inherited from other interceptor bindings. It will look like this:
#InterceptorBinding
#Target({ ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Logged
#Secured
#RequestParsed
#ResultHandled
public #interface FunctionMethod {
// clean and empty
}
Now I can use the new interceptor binding on the bean method and all of the interceptors will be called:
#FunctionMethod
public void doSomething() {
// ...
}
I would say, that you are on the right pass with a stereotype.
It's right, that the examples one finds and also the official Java EE 6 Tutorial only uses it on a class as an example (e.g. #Model), but you may as well declare #TYPE(MEHOD) in your custom annotation and then I assume that it works.