Is it possible to cut into protected method inside abstract class using Spring AOP? - spring

I am trying to execute some code after one protected method inside abstract class gets called. It looks something like this.
abstract class SomeAbstractClass : ServiceOne, ServiceTwo {
protected fun doSomething(p1: String, p2: Int): SomeEntity {
// some business logic
return SomeEntity()
}
}
I want to create annotation class like the one below and annotate method (above) with it and I want it to execute after class method returns value. I tried this and many other variations but nothing worked for me.
#Target(AnnotationTarget.FUNCTION)
#Retention(AnnotationRetention.RUNTIME)
annotation class EntityCreated {
#Aspect
#Component
class EntityAspect {
#AfterReturning("#annotation(EntityCreated)")
fun afterSuccessfulCreate(jp: JoinPoint) {
// Created, execute something here
}
}
}

While protected methods are off limits for JDK proxies when proxying interfaces, the CGLIB proxies used by Spring to extend classes can intercept protected methods. But in order to proxy a Kotlin class, you have to open it, so it is not final and can be proxied.
Please note, however, that if you override a protected method in Java, that overridden method will not "inherit" the super method's annotations. This is a Java limitation and unrelated to AOP. Annotation inheritance only works from parent to sub classes, if the annotation bears the #Inherited meta annotation. There is a way to emulate annotation inheritance using an advanced form of a technique called ITD (inter-type definition) in native AspectJ, but not in simple Spring AOP.
The exact answer to your question depends on your exact use case, your sample code is too fragmentary to answer in more detail.

Related

How can I reference annotation arguments in a custom Spring annotation?

I have an abstract class with methods requiring certain permissions. I would like the implementing classes to be able to require additional permissions, while still requiring those from the abstract class. Simply adding another #PreAuthorize annotation seems to override whatever was required in the abstract class, so my idea was to implement an annotation of my own.
My question is: how do I reference arguments in the #PreAuthorize annotation?
This code:
// Custom annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasRole('BASE_PERMISSION') and hasRole('#role')")
public #interface MyCustomPreAuthorize {
String role() default "";
}
// Implementing class
#MyCustomPreAuthorize(role = "ANOTHER_ROLE")
does not seem to work.

resilience4j annotations not working on chlid class

I am using resilience4j with SpringBoot. I see that the resilience4j annotations work only if they are placed in the class which throws the exception. If the class is extended by another class & the parent class has the annotation then the retries do not work.
Resilience4j Config
resilience4j.retry:
instances:
service:
maxRetryAttempts: 5
waitDuration: 1000
retryException:
- com.common.exception.RetriableException
Parent Class
#Retry(name = "service")
#Component
public class httpClient extends client{
// This method is invoked from outside
public HttpResponse<T> getResponse(
String url, Class<T> responseType) {
return super.getResponse(url, requestEntity, responseType);
}
}
Child Class
#Retry(name = "service") // Without this line, the retries don't work, even though it is present in the parent class
#Component
public class client{
public HttpResponse<T> getResponse(
String url, Class<T> responseType) {
//Impl which throws RetriableException
}
}
Is this the expected behaviour ? Can you let me know if I am missing something
I never used Resilience4j before, but what I can tell you about Java annotations in general is:
An overridden method in a subclass never inherits annotations from the original parent class method.
In a class implementing an interface an implementing method never inherits annotations from the corresponding interface method.
A classes implementing an interface never inherits annotations from the interface itself.
An interface extending another interface also never inherits any type or method level annotations.
By default not even a subclass inherits annotations from its parent class.
There is a single exception to this "annotations are never inherited" rule: A type level annotation (something like #Foo class Base, can also be abstract) can be inherited by a subclass (something like class Sub extends Base) if and only if the annotation class itself carries the meta annotation #Inherited.
Having said that and looking at the #Retry annotation, you will notice that there is no #Inherited annotation there, so it also cannot work in your case.
If there is another way (e.g. via reflection) to get this done in Resilience4j, I do not know because, as I said, I never used it before.

Spring AOP: #within behavior when extending classes

I have an annotation which will be used on extended placeholder classes. Basically, our service will have an implementation, and we will have an explicit extension which will be annotated. I am not sure what the problem is, but #within is not invoking the code whereas #target is.
Here is a sample code - https://github.com/sahil-ag/Spring-AOP-Sample
#Component
public BaseClass { public void getData() {return "";}}
#SampleAnnotation
#Component
public DerivedClass extends BaseClass {}
Here if we now use a #within(SampleAnnotation) pointcut, we will not be able to intercept the getData() when called from a derived class bean.
The #within Annotation is used when you want to define a class where the pointcuts are located in. So make sure that your within-clause looks like:
#within(#MyAnnotation *)
The '*' is used to say any class. This is the part you are missing in your example.
Another approach would be to use the #annotation pointcut:
#Annotation(#MyAnnotation)
Official documentation:
https://www.eclipse.org/aspectj/doc/next/adk15notebook/annotations-pointcuts-and-advice.html

What is the use of RequiredAnnotationBeanPostProcessor in Spring framework?

I am a beginner in Spring framework. I have started learning Spring framework a couple of weeks. I did not get any proper explanation of RequiredAnnotationBeanPostProcessor. Please, someone, help me by giving some example of RequiredAnnotationBeanPostProcessor and where to use this. Thanks in advance.
RequiredAnnotationBeanPostProcessor is a not common used annotation in applications that use Spring.
The #Autowired annotation that provides both the autowiring and the requiring (by default enabled) behaviors is often preferred to.
RequiredAnnotationBeanPostProcessor is a BeanPostProcessor implementation.
The BeanPostProcessor interface defines callback methods that you can implement to provide your own (or override the container’s default) instantiation logic, dependency-resolution logic, and so forth.
In the case of RequiredAnnotationBeanPostProcessor, it enforces required JavaBean properties to have been configured.
Required bean properties are detected through a Java 5 annotation: by default, the Spring's Required annotation.
To be short, it allows to ensure that a bean that declares 'required' properties has actually been configured with values. Note that the value may be null.
For example suppose this model class :
public class Foo {
private Bar bar;
#Required
public void setBar(Bar bar) {
this.bar = bar;
}
}
If setBar() is never invoked during the initialization of the bean, a org.springframework.beans.factory.BeanInitializationException is thrown.
For example this bean configuration will trigger the exception throwing :
#Configuration
public class MyConfig {
#Bean
public Foo getFoo() {
return new Foo();
}
}
Of course if you add #Autowired to setBar() with a resolvable dependency, it will be fine :
public class Foo {
private Bar bar;
#Autowired
#Required
public void setBar(Bar bar) {
this.bar = bar;
}
}
So we could consider that a good use case for RequiredAnnotationBeanPostProcessor is a case where you don't want/cannot specify the autowiring in the class of the bean.
Note also that RequiredAnnotationBeanPostProcessor provides also an additional feature that is according to the javadoc its primary goal :
The motivation for the existence of this BeanPostProcessor is to allow
developers to annotate the setter properties of their own classes with
an arbitrary JDK 1.5 annotation to indicate that the container must
check for the configuration of a dependency injected value.
It means that you may specify another annotation that #Required to indicate the required constraint.
RequiredAnnotationBeanPostProcessor defines indeed a setRequiredAnnotationType() method that you can override to set the annotation to use.
As you can see, the use of RequiredAnnotationBeanPostProcessor is related to very specific corner cases. That's why you probably don't find many examples about it.

Best practice: Spring Autowired, concrete class, and Builder

We have an interface:
public interface NotifyService {
public void send();
And a class that implements it
public class EmailNotifyService implements NotifyService {
private EmailBuilder _builder;
#Autowired
PersonRepository _personRepository;
... other Autowired Repositories ...
public EmailNotifyService(EmailBuilder builder) {
this._builder = builder;
}
public void send() {
// send mail using _builder.getRecipient().getEmailAddress(), etc.
}
We used to instantiate EmailNotifyService with a builder:
public class EmailBuilder {
private Person _recipient;
private EmailType _type;
private Event _event;
public EmailNotifyService build() {
return new EmailNotifyService(this);
}
public EmailBuilder recipient(Person recipient) {
this._recipient = recipient;
return this;
}
... and so on. But now, instead of using build() to create a new EmailNotifyService, we are trying to use Autowire with Spring instead. The problem is that everywhere else in our app, we are Autowiring interfaces, not classes. And from what I've read it's a good idea in general. In fact, I've tried rewriting the NotifyService to be an Abstract class, and then have EmailNotifyService just extend it. But Spring isn't Autowiring it correctly, it doesn't create a Proxy like it does for interfaces, and all of my Autowired fields are null.
So it would seem we're stuck with Autowiring the NotifyService interface. Fine. What I can't get my head around is - how can I get the data I used to assign with the builder -- the Person, EmailType and Event -- into a Spring Autowired interface?
I suppose I could change the interface definition to have a setPerson(), setEmailType(), etc., but apart from being really ugly, it defeats the purpose of using an interface in the first place. A different NotifyService (WebServiceNotifyService or RestNotifyService for example) night not have need for that info.
Is there any elegant, best-practice way to do this?
Thanks.
EDIT
I am using annotations, very little xml. And I am also using transaction management, which might explain why the abstract class isn't properly autowired? This is the only pertitnent info I have in xml:
<context:annotation-config />
<context:component-scan base-package="com.myco.myapp" />
<tx:annotation-driven transaction-manager="transactionManager"/>
What I mean when I say "autowiring isn't working correctly" is that when I try to autowire the abstract class, Spring doesn't seem to be creating a Proxy like it does for interfaces, and all the Autowired fields in my EmailNotifyService (PersonRepository, others ...) are null. When I use an interface, all the Autowired fields are wired correctly.
But my main problem is that I used to work explicitly with a concrete class, using a builder to create a new EmailNotifyService() directly, and pass it info -- Person, EmailType and Event. These are just normal beans. There are no setters/getters for them in EmailNotifyService but there are the EmailBuilder, which used to live inside EmailNotifyService.
But now I am using the NotifyService interface, which knows nothing about Person, EmailType or Event. But I need this info in order for EmailNotifyService to work.
So my question is, if I use Spring to Autowire my EmailNotifyService like this:
#Autowired
#Qualifier("email") // so Spring knows I want to use the EmailNotifyService implementation
NotifyService _notifyService
How can I set the Person, EmailType and Event data, since NotifyService knows nothing about them?
Currently we are using the mailer service within a web app but theoretically the mailer service should be able to work stand-alone. Regardless, I don't see how request scoped beans can help me here.
Robert what do you mean by not autowiring correctly? Are you getting any error?
Generally both interface and class auto-wiring works in Spring unless you have some autoproxy configured example #Transactional.
You do not need to have setPerson(), setEmailType(), etc. in your interface but have them autowired in the concrete class which requires them.
But seems Person is not a service but a bean which holds data and its specific to a request. If yours is a web application then look at request scope proxy to inject Person like bean.
So you are using transactions which is why class based injection is failing. Add proxy-target-class="true" to tx:annotation-driven.
Regarding your injection of Person and EmailType then you have to do that to the bean EmailNotifyService. In EmailNotifyService I do not see any Person or EmailType variables defined. Also read what I said about Person bean above.
Your design is not correct. You should not make EmailBuilder a bean and look to autowire to the EmailNotifyService. Instead in EmailNotifyService you should have a method send(EmailBuilder builder) where you pass the builder which you created somewhere dynamically.

Resources