#ControllerAdvice with #Autowired dependency not being injected - spring

Anyone knows how to inject a dependency to a #ControllerAdvice?
My #ControllerAdvice extends Spring's ResponseEntityExceptionHandler and implements no interfaces.
The #ControllerAdvice gets called correctly, but the #Autowired dependency is never injected. There are no startup injection errors, the dependency is simply null.
I guess it has to do with how Spring proxies the #ControllerAdvice with cglib so that the #Autowired annotation gets lost.
I tested by implementing an interface, so that Spring could create a JDK proxy but it didn't work either. Actually with an interface, it didn't even gets called at all... even if I also annotate the interface with #ControllerAdvice.
Is there a way to specify that Spring should use JDK proxies for that particular case?
EDIT: I'm using Spring 3.2.4.RELEASE, by the way.
Sample class:
#ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
#Autowired(required = true)
public AuditService auditService;
#ExceptionHandler(value = { RuntimeException.class })
public final ResponseEntity<Object> handleRuntimeException(Exception ex, WebRequest request) {
// auditService is null here!
}
}

In your case your bean is behind a CGLIB proxy.
It creates a subclass of your bean and as the method has final modifier it can't change the behavior of the original ResponseEntityExceptionHandler class to insert a call to the bean behind - please check my other answer about CGLIB.
CGLIB proxy is a different object that delegates the method calls to the original bean.
Please note that it would not be possible to implement much of Spring functionality only with subclassing i.e. without this separation of objects. How would it work when singleton-scoped bean references a session-scoped bean - obviously there are many session-scope beans and only one singleton-scoped bean.

Related

How to Fix Could not autowire. No beans of error in Spring Boot

How can I solve this error. I'm New to Spring-boot
As I can see the spring unable to find the bean UserDetailsServiceImpl, there might be couple of reason for it.
First, you might forgot to put #Service annotation on top of the class UserDetailsServiceImpl. Also, as the context is about Spring security so make sure that this class UserDetailsServiceImpl must implement the interface UserDetailsService
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
}
Second, spring might be unable to scan this folder. So make sure spring IOC must scan this package while intialization and configure the bean.
In order to #Autowired a bean instance, a class should be decorated with Spring stereotype annotation like #Component, #Service, #Repository, #Controller or #Indexed. Just by decorating the class with one of these role annotations, you can use #Autowired to bind with the instance.
Otherwise, if none of these annotations are used, your class instances, you have to manually registered to the BeanFactory like this;
#Configuration
public class SomeClass {
...
#Bean
public UserDetailsServiceImpl userDetailsService() {
return new UserDetailsServiceImpl()
}
}
This answer just talk about your specific question, but you get to find out why #Configuration is used in preceeding example. Define scopes for bindings, singleton (one instance for the application) is the default scope in Spring, you should define scopes for beans if they should be in different scope on your requirements.

Spring #configure annotation usage without bean definitions

I have some experience with spring dependency injection and transaction management but I am new to spring security. When i was reading an article related to spring security, I found that #Configuration annotation is used in an example but there were no bean definitions to be found.
According to my understanding, #Configuration annotation is used in classes which contain bean definitions. I need to know that what does the #Configuration annotation do in this example.
#Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
... // web stuff here
#Override
public configure(AuthenticationManagerBuilder builder) {
builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
.password("secret").roles("USER");
}
}
Thank you
It's not mandatory to have Bean definitions in Spring managed classes.
In this case #Configuration (which wraps #Component) is used to indicate to Spring that this class should be instantiated and all it's dependencies should be injected - in this case that's DataSource and AuthenticationManagerBuilder. This is an example of Inversion of Control principle.
Spring also provides these ConfigurerAdapter hook points, where you can tweak the default configuration of an already instantiated component.
This is exactly what is happening in your Configuration class.

Spring Java config, #Autowire vs. Constructor Injection, #Transactional and CGLIB

We've been using #Autowired plus Java-based Spring configuration with some success but now, we're losing control. Everyone is starting to add autowired dependencies everywhere, creating cycles and strange bugs.
So we are considering using constructor injection and autowiring of Spring configurations.
Old:
class Bean {
#Autowired Foo foo;
}
#Configuration
#Import( FooCfg.class )
class BeanCfg {
#Bean public Bean bean() { return new Bean(); }
}
New:
class Bean {
public Bean(Foo foo) {...}
}
#Configuration
class BeanCfg {
#Autowired FooCfg fooCfg;
#Bean public Bean bean() { return new Bean(fooCfg.foo()); }
}
This works pretty well (and it drives people to split beans instead of creating monsters with 10+ constructor arguments).
But it fails when Bean has a method annotated with #Transactional since CGLIB then tries to create a proxy which fails since it can't find a no-argument constructor.
What's the solution for this?
You have a couple of possible of solutions
Introduce interfaces your classes
Upgrade the Spring Version to at least 4.0
Add protected no-arg constructor
Introduce Interfaces
When introducing interfaces for your classes you can drop the usage of CgLib. Spring will then be able to use JDK Dynamic Proxies which work around interfaces. It creates a proxy around an already existing bean instance and that proxy implements all the interfaces of the class it is wrapping. That way it doesn't matter if your class has a no-arg constructor or not.
Upgrade to Spring 4
In Spring 4.0 support was added to allow proxying of classes with a missing no-arg constructor (See SPR-10594). To enable this upgrade your Spring version and add Objenesis to your classpath, Spring 4 comes with its own repacked cglib version so that shouldn't be needed anymore.
One thing to note is that you should have a constructor with no logic if you do null checks or init logic in the constructor it might fail in the case where cglib creates an instance. I would suspect that it pass null to all the constructor arguments (or some default for primitives).
Added protected no-arg constructor
Cglib needs to be able to create an instance which is used to wrap the actual class. It should be enough to have a protected constructor in your classes so that cglib can call it.

Why #Resource can't work in HttpServlet?

I am tiro to Spring, and want to use auto wire with annotation #Resource in my servlet.
In service layer and dao layer, this annotation works well, when I use it in my Servlet, the exception comes:
com.fruit.action.merchant.MerAdd.service name='merAddService' is an unknown #Resource
as you see, MerAdd is a servlet extends my own BaseServlet which extends HttpServlet, service is an object of MerAddServie, in MerAdd servlet:
#Resource(name="merAddService")
private MerAddBusiness service;
public MerAddBusiness getService() {
return service;
}
public void setService(MerAddBusiness service) {
this.service = service;
}
Is there anything I should do to fix this problem, mybe I misunderstand #Resource, can you help me , thanks ahead~
Unfortunately You cannot autowire using #Resource annotaion in Servlet.
Same Question is discussed in this spring forum link
Problem:-"The problem here is that some J2EE components have dependencies injected into them by the web container. Which means that #Resource() annotations won't work -- the container will try to resolve those dependencies to JNDI (or somewhere else)."
Possible Workaround:-
As you can use #Autowired annotation in your servlet
So You can delegate request processing to the dedicated bean which will have #Resource Bean autowired in it , i.e. make your servlet to be just an entry point that conforms to the API supported by servlet container. Hence, you can configure that actual business logic holder bean as necessary via spring and just retrieve it from IoC container and call necessary method from the servlet

Wiring beans into TestNG listener that implements IInvokedMethodListener

I have a TestNG listener that implements IInvokedMethodListener. I would like to wire in a Spring bean inside this listener and use it. Unfortunately, this class is instantiated by TestNG and so Spring cannot wire anything in that is annotated using #Autowired. I tried implementing ApplicationContextAware, but that doesn't work either.
Is there a way to wire Spring beans into classes that implement IInvokedMethodListener?
ApplicationContextAware only works for Spring Beans. You can use #Configurable, but that requires AspectJ.
Here's a simple hack that should work: Add a static member to your listener class and inject it via a non-static setter.
public class MyMethodListener implements IInvokedMethodListener {
private static MyBean myBean;
#Autowired
public void setMyBean(MyBean myBean) {
MyMethodListener.myBean = myBean;
}
}
Include a bean of the required type in your application context.
The listener instantiated by TestNG will not be the same instance as the one from the Spring context, but it will have the static member set, provided that context creation has finished before TestNG instantiates the listener.
I had the same problem recently, it is basically Listeners are not maintained by spring. So I did some googling around this concept like "Injecting beans into classes not managed by spring", I got https://dzone.com/articles/autowiring-spring-beans-into-classes-not-managed-by-spring link which explains exactly the same problem and the solution. It worked for me.

Resources