Is constructor injection possible in Spring configuration classes? - spring

If I have a Spring configuration class (i.e. a class annotated with #Configuration) can I use constructor injection ?
As it stands if I add one I get a no default constructor message, and if I add a default constructor it uses that rather than the overloaded one, which doesn't really help.

There is a bug report about this limitation. It will be fixed with Spring 4.3.
Please note that another bug report (not fixed yet today fixed in 4.3-RC1) report a problem when using this very new feature and injecting generics in constructor of a #Configuration class.

In Spring 4.3, you can use org.springframework.beans.factory.ObjectProvider in #Configuration annotated class constructors to inject beans. for example:
#Configuration
public class SimpleBean {
private final InnerBean prop1;
public Simple Bean(ObjectProvider<InnerBean> innerBeanProvider) {
prop1 = innerBeanProvider.getObject();
}
}

Related

Spring bean not getting Autowired from custom library

I have created by own library(com.custom.mylib) which returns a string like below.
#Component
public class MyLibrary{
#Value("${str.message}")
private String message; //This val should come from app which is going to use this lib
public String readMessage() {
return message;
}
I have create a project which is going to use above library. I have included the lib as pom dependency .But when I try to call library method from my app. I get the error below.
How to resolve it?
#Autowired
private MyLibrary myLibrary;
Consider defining a bean of type 'com.custom.mylog.MyLibrary' in your
configuration.
I also have below in application.properties file so that library can pick the value up
str.message=Hello world
I got the solution it seems.I need to create META-INF file and do org.springframework.boot.autoconfigure.EnableAutoConfiguration=<fully_qualified_name_of_configuration_file>
as given here
Spring Boot: autowire beans from library project
As it has to be used as a external library, you can instantiate it throught a #Configuration file:
#Configuration
public class AppConfiguration {
#Bean
public MyLibrary createMyLibraryInstance() {
return new MyLibrary();
}
}
The rule I used is the follow (this is not an universal rule):
In your domain classes (Controller, Service) : use #Autowired in your constructor. It is the recommanded way to inject your dependencies.
You want to use external classes : implements a Java Configuration with #Configuration annotation, to instanciate your external classes as beans.
You want to create custom utilities classes : decorate it with #Component.
When you have more than on implementation, use #Qualifier and define your beans in a #Configuration class.

Spring MVC #Value/#ConfigurationProperties working on MainConfig but not on SecurityConfig

I have a simple Spring MVC 5 project, with security layer enabled. Everything works good except the properties loading, only on Security Config.
I let you the scenario so you can see it.
application.properties (located at src/main/resources)
com.company.myapp.prop=myprop
MainConfig.java
#Configuration
public class MainConfig implements WebMvcConfigurer {
#Value("${com.company.myapp.prop}")
private String prop;
#Bean
public MySpecialBean mySpecialBean() {
System.out.println(prop); // output > myprop
return new MySpecialBean();
}
}
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${com.company.myapp.prop}")
private String prop;
#Bean
public MySpecialSecurityBean mySpecialSecurityBean() {
System.out.println(prop); // output > null
return new MySpecialSecurityBean();
}
}
I don't understand why it's happening. I already switched the #EnableWebSecurity annotation to the app class, try to set the PropertySourcesPlaceholderConfigurer myself, but nothing works.
Do you have any idea what's going on?
From official docs about #PropertySource:
Resolving ${...} placeholders in <bean> and #Value annotations
In order to resolve ${...} placeholders in definitions or #Value annotations using properties from a PropertySource, you must ensure that an appropriate embedded value resolver is registered in the BeanFactory used by the ApplicationContext. This happens automatically when using in XML. When using #Configuration classes this can be achieved by explicitly registering a PropertySourcesPlaceholderConfigurer via a static #Bean method. Note, however, that explicit registration of a PropertySourcesPlaceholderConfigurer via a static #Bean method is typically only required if you need to customize configuration such as the placeholder syntax, etc. See the "Working with externalized values" section of #Configuration's javadocs and "a note on BeanFactoryPostProcessor-returning #Bean methods" of #Bean's javadocs for details and examples.
You should try to add annotation #PropertySource into the your config class.
#Configuration
#PropertySource("classpath:my.properties")
public class MainConfig implements WebMvcConfigurer {}
and then try to access your property in SecurityConfig class
To get full information see official docs
I hope it will help you
This works for me.
I guess you have another class that triggers the application and that is annotated with #SpringBootApplication
Also, your methods mySpecialBean do not return a MySpecialBean instance, so this probably does not even compile.
Is there any other class that you are using? Please advice
Finally got it!
The problem was related with some dependency priorities and unnecessary beans declarations. Getting into details, I'm working with OAuht2 and I started with this tutorial. In the end I've made a mix with this one too (more recent). The problem was related with these #Bean's that don't really need to be declared as beans:
ClientRegistrationRepository
ClientRegistration
OAuth2AuthorizedClientService
Spring was calling these beans before any other configuration, so any properties was not loaded yet. Maybe changing the priority, dependence or even the order would resolve the issue, but as I was analysing the code I found that these methods are only used on security configuration and not really needed along any other part of the app. So I removed the #Bean declaration and all works nice now! At the time these methods are called inside security config the properties are already loaded.
Hope to help someone out there.

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.

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.

How to use spring to resolve dependencies of an object created manually?

I would like to know if it's possible to use Spring to resolve the dependencies of an object created manually in my program. Take a look at the following class:
public class TestClass {
private MyDependency md;
public TestClass() {
}
...
public void methodThaUsesMyDependency() {
...
md.someMethod();
...
}
}
This TestClass is not a spring bean, but needs MyDependency, that is a spring bean. Is there some way I can inject this dependency through Spring, even if I instantiate TestClass with a new operator inside my code?
Thanks
Edit: The method I'm describing in my original answer below is the general way to accomplish DI external of the container. For your specific need - testing - I agree with DJ's answer. It's much more appropriate to use Spring's test support, for example:
#Test
#ContextConfiguration(locations = { "classpath*:**/applicationContext.xml" })
public class MyTest extends AbstractTestNGSpringContextTests {
#Resource
private MyDependency md;
#Test
public void myTest() {
...
While the above example is a TestNG test, there is also Junit support explained in 8.3.7.2. Context management and caching.
General approach: Annotate your class with #Configurable and utilize AspectJ load-time or compile-time weaving. See 6.8.1 in the Spring documentation on AOP for more details.
You can then annotate your instance variables with #Resource or #Autowired. Though they accomplish the same goal of dependency injection, I recommend using #Resource since it's a Java standard rather than Spring-specific.
Lastly, remember to consider using the transient keyword (or #Transient for JPA) if you plan on serializing or persisting the objects in the future. Chances are you don't want to serialize references to your DI'd repository, service, or component beans.
See the autowire() method on the AutowireCapableBeanFactory class. If you use an ClasspathXmlApplicationContext, you can get the factory with getAutowireCapableBeanFactory()
To get the ApplicationContext, you would need to use a static singleton or other central repository, such as JNDI or a Servlet container. See DefaultLocatorFactory on how to get an instance of the ApplicationContext.
If what you need is for testing purposes, Spring has good support for the scenario that you described above.
Check out Spring Reference manual section on Testing

Resources