Transitive inclusion of #Configuration classes from a .xml-based spring config - spring

Suppose we start with an xml-based config, say main.xml, that imports a java config FullConfig.java via:
<context:annotation-config/>
<bean class="test.FullConfig"/>
This java config has the form:
#Configuration
#Import(value = {IncludeConfig.class})
public class FullConfig {
#Autowired
#Qualifier(value = "tmpBean")
private DataClazz autowired;
#Bean
public DataClazz someOtherBean() {
System.out.println("Using autowired tmpBean:" + autowired);
return new DataClazz();
}
}
so it imports a further java config, which contains a definition of the tmpBean of DataClazz type,
#Configuration
public class IncludeConfig {
#Bean
public DataClazz tmpBean() {
return new DataClazz();
}
}
Now two questions:
Is this "transitive inclusion" guaranteed to work in spring (i.e. is someOtherBean() guaranteed not to thrown a NPE)?
IntelliJ up to version 2017.2 does mark #Qualifier(value = "tmpBean") red with a message "Cannot find bean with qualifier 'tmpBean'". Should that be considered a bug?
Note: I have checked that an application using ClassPathXmlApplicationContext("main.xml") does work correctly, i.e. no NPE is thrown (and all relevant beans are visible).

You need to return DataClazz:
#Bean
public DataClazz someOtherBean() {
System.out.println("Using autowired tmpBean:" + autowired);
return autowired;
}
Probably yes but try to test it.
IDEA-82844 (Bug)

Related

Switch bean by changing properties in Spring boot

I have one interface MyInterface, and 2 implementation beans: FirstImpl & SeconImpl. I want to switch between using these 2 implementations while program is running without restarting it, by only changing a property in application.properties file, e.g: interface.bean.default=FirstImpl change to interface.bean.default=SecondImpl.
Anyone knows how to do that with Spring boot?
You could try to use #ConditionalOnProperty:
#Configuration
public class MyInterfaceConfiguration {
#Bean
#ConditionalOnProperty(value = "my.interfacte.impl", havingValue="firstImpl")
public MyInterface firstImpl(){
return new FirstImpl();
}
#Bean
#ConditionalOnProperty(value = "my.interfacte.impl", havingValue="secondImpl")
public MyInterface secondImpl(){
return new SecondImpl();
}
}
and when you update your property in application.properties with actuator/refresh to:
my.interfacte.impl=firstImpl
you will have your FirstImpl instance. When you have:
my.interfacte.impl=secondImpl
you will have your SecondImpl.
#Hasan, your update only works if I customize it a little bit as below:
#Configuration
#RefreshScope
public class MyInterfaceConfiguration {
#Value("${my.interfacte.impl}")
String impl;
#Bean
#RefreshScope
public MyInterface getBean(){
if ("firstImpl".equals(impl)) {
return new FirstImpl();
} else if ("secondImpl".equals(impl)) {
return new SecondImpl();
}
return null;
}
}
I have to use 2 #RefreshScope at class level and bean creation method level!

When to use Qualifier and Primary in Spring

I have read that #Qualifier can be used in Injection phase whereas #Primary is used in Configuration phase. Am still unclear when to use which.
Also I have below doubts
can #Primary and #Qualifier be used together? if yes does #Qualifier take precedence?
can #Primary be used with #Autowired?
How is the Injection phase different from Configuration phase, this in respect to Spring beans
#Primary indicates that a bean should be given preference when multiple candidates
are qualified to autowire a single-valued dependency.
#Qualifier indicates specific bean should be autowired when there are multiple candidates.
For example, we have two beans both implement the same interface.
public interface BeanInterface {
String getName();
}
public class Bean1 implements BeanInterface {
#Override
public String getName() {
return "bean 1";
}
}
public class Bean2 implements BeanInterface {
#Override
public String getName() {
return "bean2";
}
}
Here is our service.
#Service
public class BeanService {
#Autowired
private BeanInterface bean;
}
And our configuration.
#Configuration
public class Config {
#Bean("bean1")
public BeanInterface bean1() {
return new Bean1();
}
#Bean("bean2")
public BeanInterface bean2() {
return new Bean2();
}
}
When Spring starts, it will find there are two beans("bean1" and "bean2") both can be autowired to BeanService since they implement the same interface BeanInterface. It reports an error in my Idea.
Could not autowire. There is more than one bean of 'BeanInterface' type.
Beans: bean1   (Config.java)
bean2   (Config.java)
And without a hint, Spring does not know which one to use.
So in our case, when we add #Primary to Config.bean1().
#Bean("bean1")
#Primary
public BeanInterface bean1() {
return new Bean1();
}
It tells Spring, "when you find more than one beans that both can be autowired, please use the primary one as your first choose." So, Spring will pick bean1 to autowire to BeanService.
Here is another way to autowire bean1 to BeanService by using #Qualifier in BeanService.class.
#Service
public class BeanService {
#Autowired
#Qualifier("bean1")
private BeanInterface bean;
}
#Qualifier will tell Spring, "no matter how many beans you've found, just use the one I tell you."
So you can find both #Qualifier and #Primary are telling Spring to use the specific bean when multiple candidates are qualified to autowire. But #Qualifier is more specific and has high priority. So when both #Qualifier and #Primary are found, #Primary will be ignored.
Here is the test.
#Configuration
public class Config {
#Bean("bean1")
#Primary
public BeanInterface bean1() {
return new Bean1();
}
#Bean("bean2")
public BeanInterface bean2() {
return new Bean2();
}
}
#Service
public class BeanService {
#Autowired
#Qualifier("bean2")
private BeanInterface bean;
#PostConstruct
public void test() {
String name = bean.getName();
System.out.println(name);
}
}
The output is "bean2".
Also, need to remember that #Qualifier as bigger priority then #Primary, that's means that it's waste to define both of the annotations.
#Primary means default implementation, while #Qualifier is the specific implementation.
You can review my blog I wrote regarding this annotations -
http://shaikezam.com/#/spring_qualifier
Yes, #Qualifier takes precedence.
Yes we can user #Primary and #Autowired together.
#Configuration Class related to Application Context which can be use to configure application level configuration.
To access beans with the same type we usually use #Qualifier(“beanName”) annotation. We apply it at the injection point along with #Autowired. In our case, we select the beans at the configuration phase so #Qualifier can't be applied here.
To resolve this issue Spring offers the #Primary annotation along with #Bean annotation.
Source

How to change the implementing class when using annotations with Spring?

I'm used to Spring with xml configuration. With xml, I can have one main implementation and one test implementation for a class, so that the test implementation will be used for JUnit tests, how can I do this with annotations ? Cause it looks like the implementation is already chosen in the "#qualifier" annotation ?
Let's take an example :
<bean id="myService" class="example.Service" />
<bean id="myHibernateDao" class="example.HibernateDao" />
<bean id="myStubDao" class="example.StubDao" />
In xml config, I can have this in src/main/resources :
<bean id="myService" class="example.Service">
<ref="myHibernateDao" />
</bean>
And this in src/test/resources :
<bean id="myService" class="example.Service">
<ref="myStubDao" />
</bean>
How can I do this with annotations, if I have already declared #Qualifier("myHibernateDao") into my service class ?
As explained in the comment above and in spring blog, you can do this via #Profile annotation.
Please find a sample config from the example below,
DataConfig.java
interface DataConfig {
DataSource dataSource();
}
StandaloneDataConfig .java
#Configuration
#Profile("dev")
public class StandaloneDataConfig implements DataConfig {
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
}
JndiDataConfig.java
#Configuration
#Profile("production")
public class JndiDataConfig implements DataConfig {
#Bean
public DataSource dataSource() {
try {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
} catch (NamingException ex) {
throw new RuntimeException(ex);
}
}
}
TransferServiceConfig.java
#Configuration
public class TransferServiceConfig {
#Autowired
DataConfig dataConfig;
#Bean
public TransferService transferService() {
return new DefaultTransferService(accountRepository(), feePolicy());
}
#Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataConfig.dataSource());
}
#Bean
public FeePolicy feePolicy() {
return new ZeroFeePolicy();
}
}
Setting bean profile to an application context
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setDefaultProfiles("dev");
ctx.register(TransferServiceConfig.class, StandaloneDataConfig.class,
JndiDataConfig.class);
ctx.refresh();
Since the bean profile has been set to Dev, The TransferServiceConfigwill be injected with StandaloneDataConfig
You can basically do the same thing with #Configuration classes.
Production Setup
Let's assume you have many different DAO implementations that might or might not implement a common interface (it doesn't matter). Let's further assume that MyServiceDao is the concrete implementation that your Service class needs.
Write the following configuration classes:
#Configuration
public class MyServiceConfiguration {
#Bean
public Service myService(MyServiceDao dao) {
return new Service(dao);
}
}
-
#Configuration
public class MyProductionServiceDaoConfiguration {
#Bean
public MyServiceDao myServiceDao() {
return new MyServiceDao();
}
}
Methods in #Configuration classes that are annotated with #Bean are eligible for Spring's auto-wiring. In the MyServiceConfiguration above, Spring will use the type of the method parameter to find a matching bean. If you include MyProductionServiceDaoConfiguration when creating the Spring context, this will be the instance of MyServiceDao that myServiceDao() created.
Test Setup
In your tests, you want to replace MyServiceDao with a stub. The stub needs to extend MyServiceDao so that Spring can find the right bean based on types. Let's call the stub MyServiceDaoStub. Whether you create it using a library like Mockito (which can also create stubs, not just mocks) or actually write an extension of MyServiceDao is up to you.
Instead of including MyProductionServiceDaoConfiguration in your Spring configuration, use the following class:
#Configuration
public class MyTestServiceDaoConfiguration {
#Bean
public MyServiceDao myServiceDao() {
return new MyServiceDaoStub();
}
}
In your test use #ContextConfiguration to load the test setup:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { MyServiceConfiguration.class, MyTestServiceDaoConfiguration.classs })
public class MyServiceTest {
// your tests
}
Using #Autowired
Spring will also process #Autowired annotations in objects returned from #Bean annotated methods. If your Service looks like this:
public class Service {
#Autowired
private MyServiceDao dao;
// more code
}
you can change the myService() method to:
#Bean
public Service myService() {
return new Service();
}

JavaConfig "auto" injection of beans

I had being using the JSR 330 #Inject annotation to autowire my Spring beans. I started experimenting by removing the #Inject annotation - yet my application context still gets loaded correctly. Not sure if this is expected and cant find any spring documentation to verify this use case.
// This context is loaded correctly - and beans exist for B, C and Db
final ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
#Import({ B.class })
#Configuration
public class ApplicationConfig {
#Bean
public Db db() {
return new Database();
}
#Bean
// I thought this method would need an #Autowire or #Inject annotation to resolve b!?
public C c(final B b){
return new C(b);
}
}
#Configuration
public class BConfig {
#Bean
public B b() {
return new B();
}
}
#Autowired (or #Inject if you prefer) is implicit in #Bean methods (always has been as far as I know).

Spring #Configuration class needs to be autowired

I've created a Spring #Configuration annotated class and I want to autowire a ResourceLoader to it so that I can use it in one of the #Bean methods to lookup a file given by a String. When I am running the app and initialising the context I get a NPE accessing the autowired field, and in debug mode it is shown as being null/not set. Am I wrong expecting the resourceLoader to be present? Am I wrong asserting the autowiring of the Configuration bean happens before its methods get called? The xml configuration loading this bean is tagged with <context:annotation-config/>
#Configuration
public class ClientConfig {
#Autowired
private ResourceLoader resourceLoader;
public #Bean
String configHome() {
return System.getProperty("CONFIG_HOME");
}
public #Bean
PropertiesFactoryBean appProperties() {
String location = "file:" + configHome() + "/conf/webservice.properties";
PropertiesFactoryBean factoryBean = new PropertiesFactoryBean();
factoryBean.setLocation(resourceLoader.getResource(location));
return factoryBean;
}
}
I'm not sure whether this is a bug or is the expected behavior. Sometimes it worked for me, sometimes didn't. Anyway, there is another way of achieving what you want:
public #Bean PropertiesFactoryBean appProperties(ResourceLoader resourceLoader) {
// resourceLoader is injected correctly
...
}

Resources