Rest + Spring AOP + interface doesn't inject - java

I have a Spring AOP aspect used for logging, where a method can be included for logging by adding an annotation to it, like this:
#AspectLogging("do something")
public void doSomething() {
...
}
I've been using this on Spring beans and it's been working just fine. Now, I wanted to use it on a REST-service, but I ran into some problems. So, I have:
#Path("/path")
#Service
public class MyRestService {
#Inject
private Something something;
#GET
#AspectLogging("get some stuff")
public Response getSomeStuff() {
...
}
}
and this setup works just fine. The Rest-service that I'm trying to add the logging to now has an interface, and somehow that messes stuff up. As soon as I add the #AspectLogging annotation to one of the methods, no dependencies are injected in the bean, and also, the aspect is newer called!
I've tried adding an interface to the REST-service that works, and it gets the same error.
How can having an interface lead to this type of problems? The aspect-logger works on classes with interfaces elsewhere, seems it's only a problem when it's a REST-service..

Ref the below Spring documentation (para 2) -
To enable AspectJ annotation support in the Spring IoC container, you
only have to define an empty XML element aop:aspectj-autoproxy in your
bean configuration file. Then, Spring will automatically create
proxies for any of your beans that are matched by your AspectJ
aspects.
For cases in which interfaces are not available or not used in an
application’s design, it’s possible to create proxies by relying on
CGLIB. To enable CGLIB, you need to set the attribute
proxy-targetclass= true in aop:aspectj-autoproxy.
In case your class implements an interface, a JDK dynamic proxy will be used. However if your class does not implement any interfaces then a CGLIB proxy will be created. You can achieve this #EnableAspectJAutoProxy. Here is the sample
#Configuration
#EnableAspectJAutoProxy
public class AppConfig {
#Bean
public LoggingAspect logingAspect(){
return new LoggingAspect();
}
}
#Component
#Aspect
public class LoggingAspect {
...
...
}

In my opinion what you are actually trying to do is to add spring annotations to a class maintained by jersey. In the result you are receiving a proxy of proxy of proxy of somethng. I do not think so this is a good idea and this will work without any problems. I had a similar issue when I tried to implement bean based validation. For some reasons when there were #PahtParam and #Valid annotations in the same place validation annotations were not visible. My advice is to move your logging to a #Service layer instead of #Controller.

Related

How to call Spring Framework repositories methods

I know that there are questions similar to this one, but none of them have helped me. I'm following along this tutorial, and the part I can't wrap my mind around is:
#SpringBootApplication
public class Application {
private static final Logger log =
LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
#Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args) -> {
// save a couple of customers
...
// more lines, etc...
What I don't understand is where the repository passed into demo comes from. I know that the Autowired annotation can do something like that, but it isn't used at all here.
The more specific reason I ask is because I'm trying to adapt what they do here to an application I'm working on. I have a class, separate from all of the persistence/repository stuff, and I want to call repository methods like save and findAll. The issue is that the repository is an interface, so I can't instantiate an object of it to call the methods. So do I have to make a new class that implements the interface and create an object of that? Or is there an easier way using annotations?
When creating a #Bean, adding the repository in the parameters of the bean is enough to wire the repos in your bean. This works pretty much like adding #Autowired annotation inside a class that is annotated as #Component or something similar.
Spring works mostly with interface, since that is simplier to wire vs wiring concrete classes.
Can you try #Repository before the declaration of class? Worked for me in a Spring MVC structure.
#Repository
public class EntityDAOImpl implements EntityDAO{
...
}
The thing to wrap your head around is a Spring Boot application at startup time aims to resolve its dependancy tree. This means discovering and instantiating Beans that the application defines, and those are classes annotated with #Service, #Repository, etc.
This means the default constructor (or the one marked with #Autowire) of all beans is invoked, and after all beans have been constructed the application starts to run.
Where the #Bean annotation comes into play is if you have a bean which does not know the values of it's constructor parameters at compile time (e.g. if you want to wire in a "started at" timestamp): then you would define a class with an #Configuration annotation on it, and expose an #Bean method in it, which would return your bean and have parameters that are the beans dependencies. In it you would invoke the beans constructor and return the bean.
Now, if you want a certain method of some class to be invoked after the application is resolved, you can implement the CommandLineRunner interface, or you can annotate a method with #PostConstruct.
Some useful links / references:
https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
Running code after Spring Boot starts
Execute method on startup in Spring

Override/disable Aspect on runtime

In my spring-boot application I have a dependency on external jar, which contains a class marked with annotation, on which #Aspect from this jar is being triggered.
I have dao method annotated with mu custom annotation:
#MyAnnotation
public void save(MyEntity entity)
{
super.save(entity);
}
I have an aspect, which has an advice, sending message after save() method is called:
#Aspect
public class MySuperAspect
{
#Autowired
MessageSender messageSender;
#Around("#annotation(MyAnnotation) && args(entity)")
public void sendMessage(MyEntity entity)
{
messageSender.send();
}
}
I do need Dao method from the jar, but I want to disable aspect for it.
Aspect is being created via Spring XML configuration, which is inside the jar I use as well.
I could modify the aspect itself, but it's undesirable as it's being used not only by my spring-boot app.
I tried:
Disabling xml configuration from scanning in my spring-boot app;
Changing xml config to annotations and filter it in scanning;
Adding #ConditionalOnExpression and #ConditionalOnProperty on aspect to be disabled by property;
As of now the only way which works is adding #Value annotation with property by which I may control logic inside the advice, but I'm curious is this the only way to do that or probably I'm missing something?
You need to stop spring boot from scanning this class... Because it must be configured to scan this aspect otherwise it wouldn't be picking up and applying the aspect.

Generic Autowiring Not Working with #Transactional

Spring appears fully capable of autowiring the correct type based on generic parameters without the need for #Qualifiers. However, as soon as I tack on a #Transactional annotation, it can no longer autowire based on generic parameters. Consider this example, invented only for purposes of illustrating the issue:
interface Product {}
interface Book extends Product {}
interface Toy extends Product {}
interface Store<P extends Product> {}
#Component
class BookStore implements Store<Book> {}
#Component
class ToyStore implements Store<Toy> {}
#Component
class BookDealer {
#Autowired
BookDealer(Store<Book> store) {
...
}
void inventoryBooks() {
... doesn't really matter what this does ...
}
}
Note that the above code wires up fine. The BookStore class is autowired into the BookDealer constructor without any issue. I can call inventoryBooks() and it works fine.
However, if I add a #Transactional annotation to a method upstream from the call to inventoryBooks(), e.g. on the client method that calls it, the BookDealer will no longer autowire, and I must resort to either injecting concrete types, or using a #Qualifier. The error is that there are two matching beans for the constructor argument of BookDealer, meaning both the BookStore and the ToyStore and Spring can't decide which one is needed. That tells me that Spring can no longer detect the generic types now that some upstream method has been proxied for the #Transactional. Something like that anyway...
I would like to stick to interfaces and not use #Qualifiers. Is there a way to do this with #Transactional, or is it a known limitation of generics and autowiring and things like #Transactional?
The Spring uses the JDK Proxy to generate the proxy used in AOP by default. The JDK proxy is based on the interface. So it maybe the problem, when you need to autowire the concrete class. So use the cglib instead(add the denpendency) and set the "" in the spring config file to "" and have a try. Hope it helps.
Using #Transaction annotation with #Autowired - Spring

Whats the best way to inject same instance of service in service for Spring AOP

I'va a ServiceImpl with is annotated with #Service stereotype of Spring and have two methods in it each one is annotated with custom annotations which are intercepted by Spring.
#Service
public class ServiceImpl implements Service{
#CustomAnnotation
public void method1(){
...
}
#AnotherCustomAnnotation
public void method2(){
this.method1();
...
}
}
}
Now Spring uses proxy based AOP approach and hence as I'm using this.method1() interceptor for #CustomAnnotation will not able to intercept this call, We used to inject this service in another FactoryClass and in that way we were able to get the proxy instance like -
#AnotherCustomAnnotation
public void method2(){
someFactory.getService().method1();
...
}
I'm now using Spring 3.0.x, which is the best way to get the proxy instance?
The other alternative is to use AspectJ and #Configurable.
Spring seems to be going towards these days (favoring).
I would look into it if you are using Spring 3 as it is faster (performance) and more flexible than proxy based aop.
Both methods are inside the same proxy, whereas the AOP functionality just enriches calls from the outside (see Understanding AOP Proxies). There are three ways for you to deal with that restriction:
Change your design (that's what I would recommend)
Change proxy type from JDK-proxy to proxy-target-class (CGLib-based subclassing) Nope, that doesn't help, see #axtavt's comment, it would have to be static AspectJ compilation.
Use ((Service)AopContext.currentProxy()).method1() (Works, but is an awful violation of AOP, see the end of Understanding AOP Proxies)
You could make your ServiceImpl class implement the BeanFactoryAware interface, and lookup itself thanks to the provided bean factory. But this is not dependency injection anymore.
The best solution is to put method1 in another service bean, which would be injected in your existing service bean and to which your existing service bean would delegate.

Spring-MVC Problem using #Controller on controller implementing an interface

I'm using spring 2.5 and annotations to configure my spring-mvc web context. Unfortunately, I am unable to get the following to work. I'm not sure if this is a bug (seems like it) or if there is a basic misunderstanding on how the annotations and interface implementation subclassing works.
For example,
#Controller
#RequestMapping("url-mapping-here")
public class Foo {
#RequestMapping(method=RequestMethod.GET)
public void showForm() {
...
}
#RequestMapping(method=RequestMethod.POST)
public String processForm() {
...
}
}
works fine. When the context starts up, the urls this handler deals with are discovered, and everything works great.
This however does not:
#Controller
#RequestMapping("url-mapping-here")
public class Foo implements Bar {
#RequestMapping(method=RequestMethod.GET)
public void showForm() {
...
}
#RequestMapping(method=RequestMethod.POST)
public String processForm() {
...
}
}
When I try to pull up the url, I get the following nasty stack trace:
javax.servlet.ServletException: No adapter for handler [com.shaneleopard.web.controller.RegistrationController#e973e3]: Does your handler implement a supported interface like Controller?
org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1091)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:874)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
javax.servlet.http.HttpServlet.service(HttpServlet.java:627)
However, if I change Bar to be an abstract superclass and have Foo extend it, then it works again.
#Controller
#RequestMapping("url-mapping-here")
public class Foo extends Bar {
#RequestMapping(method=RequestMethod.GET)
public void showForm() {
...
}
#RequestMapping(method=RequestMethod.POST)
public String processForm() {
...
}
}
This seems like a bug. The #Controller annotation should be sufficient to mark this as a controller, and I should be able to implement one or more interfaces in my controller without having to do anything else. Any ideas?
What I needed to do was replace
<tx:annotation-driven/>
with
<tx:annotation-driven proxy-target-class="true"/>
This forces aspectj to use CGLIB for doing aspects instead of dynamic proxies - CGLIB doesn't lose the annotation since it extends the class, whereas dynamic proxies just expose the implemented interface.
Ed is right, adding
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
works fine
If you wish to use interfaces for your Spring MVC controllers then you need to move the annotations around a bit, as mentioned in the Spring docs: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping
Using #RequestMapping On Interface Methods A common pitfall when
working with annotated controller classes happens when applying
functionality that requires creating a proxy for the controller object
(e.g. #Transactional methods). Usually you will introduce an interface
for the controller in order to use JDK dynamic proxies. To make this
work you must move the #RequestMapping annotations to the interface as
well as the mapping mechanism can only "see" the interface exposed by
the proxy. Alternatively, you could activate proxy-target-class="true"
in the configuration for the functionality applied to the controller
(in our transaction scenario in ). Doing so
indicates that CGLIB-based subclass proxies should be used instead of
interface-based JDK proxies. For more information on various proxying
mechanisms see Section 8.6, “Proxying mechanisms”.
Unfortunately it doesn't give a concrete example of this. I have found a setup like this works:
#Controller
#RequestMapping(value = "/secure/exhibitor")
public interface ExhibitorController {
#RequestMapping(value = "/{id}")
void exhibitor(#PathVariable("id") Long id);
}
#Controller
public class ExhibitorControllerImpl implements ExhibitorController {
#Secured({"ROLE_EXHIBITOR"})
#Transactional(readOnly = true)
#Override
public void exhibitor(final Long id) {
}
}
So what you have here is an interface that declares the #Controller, #PathVariable and #RequestMapping annotations (the Spring MVC annotations) and then you can either put your #Transactional or #Secured annotations for instance on the concrete class. It is only the #Controller type annotations that you need to put on the interface because of the way Spring does its mappings.
Note that you only need to do this if you use an interface. You don't necessarily need to do it if you are happy with CGLib proxies, but if for some reason you want to use JDK dynamic proxies, this might be the way to go.
There's no doubt that annotations and inheritance can get a little tricky, but I think that should work. Try explicitly adding the AnnotationMethodHandlerAdapter to your servlet context.
http://static.springframework.org/spring/docs/2.5.x/reference/mvc.html#mvc-ann-setup
If that doesn't work, a little more information would be helpful. Specifically, are the two annotated controller methods from the interface? Is Foo supposed to be RegistrationController?
I know it is too late but i'm writing this for anyone have this problem
if you are using annotation based configuration... the solution might be like this:
#Configuration
#ComponentScan("org.foo.controller.*")
#EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppConfig { ...}
The true reason you need to use 'proxy-target-class="true"' is in DefaultAnnotationHandlerMapping#determineUrlsForHandler() method: though it uses ListableBeanFactory#findAnnotationOnBean for looking up a #RequestMapping annotation (and this takes care about any proxy issues), the additional lookup for #Controller annotation is done using AnnotationUtils#findAnnotation (which does not handles proxy issues)

Categories

Resources