Spring #Configuration class needs to be autowired - spring

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
...
}

Related

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

Could not autowire. No beans of 'InstructionRepository' type found

Trying to create a bean in SpringBoot application, but getting the following error "Could not autowire. No beans of 'InstructionRepository' type found."
InstructionRepository is annotated with #Repository annotation in the jar and is an Interface extending a Spring Data Interface
ScheduleProcessor is a method
When I Try adding the #ComponentScan annotation by passing the base package value, the error goes away BUT, when I boot up the application get the following error
Parameter 0 of constructor in com.xxx.resync.config.AppConfig required a bean of type 'com.xxx.repo.InstructionRepository' that could not be found. Action: Consider defining a bean of type 'com.xxx.repo.InstructionRepository' in your configuration.
#Configuration
#EnableAutoConfiguration
//#ComponentScan(basePackages = {"com.xxx.repo"})
public class AppConfig {
#Value("${pssHttp.connectTimeout:3000}")
private int connectTimeout;
#Bean
public RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(connectTimeout);
factory.setReadTimeout(connectTimeout);
restTemplate.setRequestFactory(factory);
return restTemplate;
}
#Bean
public ScheduleUpdater getScheduleUpdater() {
return new ScheduleUpdater(true);
}
#Bean
public ScheduleProcessor scheduleProcessor(InstructionRepository instructionRepository, ScheduleUpdater scheduleUpdater) {
return new ScheduleProcessor(instructionRepository, scheduleUpdater);
}
}
InstructionRepository
#Repository
public interface InstructionRepository extends CouchbaseRepository<Instruction, String> {
}
How can we fix the error and be able to boot up the Spring boot application?
Any suggestions appreciated.
You need to add #EnableCouchbaseRepositories to enable repo building eg to AppConfig.

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

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)

CommandLineRunner and Beans (Spring)

code what my question is about:
#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 Object test(RestTemplate restTemplate) {
Quote quote = restTemplate.getForObject(
"http://gturnquist-quoters.cfapps.io/api/random", Quote.class);
log.info(quote.toString());
return new Random();
}
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
#Bean
public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
return args -> {
Quote quote = restTemplate.getForObject(
"http://gturnquist-quoters.cfapps.io/api/random", Quote.class);
log.info(quote.toString());
};
}
}
I'm very new to Spring. As far as I understood the #Bean annotation is responsible that an Object is saved in a IoC container, correct?
If so: Are first all Methods with #Bean collected and then executed?
In my example I added a method test() what does the same as run() but returns an Object (Random()) instead.
The result is the same so it is working with CommandLineRunner and Object.
Is there a Reason why it should return a CommandLineRunner i.e. use the syntax like run()?
Moreover: At that point I don't see so far the advantage to move methods to an container. Why not just execute it?
Thank you!
#Configuration classes (#SpringBootApplication extends #Configuration) are the place where the spring beans are registered.
#Bean is used to declare a spring bean. The method that is annotated with #Bean has to return an object(the bean). By default the spring beans are singletons, so once the method annotated with #Bean is executed and returns it's value this object lives til the end of the application.
In your case
#Bean
public Object test(RestTemplate restTemplate) {
Quote quote = restTemplate.getForObject(
"http://gturnquist-quoters.cfapps.io/api/random", Quote.class);
log.info(quote.toString());
return new Random();
}
this will produce s singleton bean of type Random with name 'test'. So if you try to inject (e.g. with #Autowire) a bean of that type or name in other spring bean you will get that value. So this is not a good use of #Bean annotation, unless you want exactly that.
CommandLineRunner on the other hand is a special bean that lets you execute some logic after the application context is loaded and started. So it makes sense to use the restTemplate here, call the url and print the returned value.
Not long ago the only way to register a Spring bean was with xml. So we had an xml files and bean declarations like this:
<bean id="myBean" class="org.company.MyClass">
<property name="someField" value="1"/>
</bean>
The #Configuration classes are the equivalent of the xml files and the #Bean methods are the equivalent of the <bean> xml element.
So it's best to avoid executing logic in bean methods and stick to creating objects and setting their properties.

Spring JavaConfig + WebMvcConfigurerAdapter + #Autowired => NPE

I have an application with 2 Contexts. Parent for web agnostic business logic and ChildContext (implicitly created by dispatcher servlet) for web logic.
My setup loks like
#Configuration
public class BusinessConfig {
#Bean
public ObjectMapper jacksonMapper() { return new ObjectMapper() }
}
and
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
private ObjectMapper objectMapper; // <- is null for some reason
#Override
public configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper); // <- bang!
messageConverters.add(converter);
}
}
I need the the object mapper in the parent context, as I use it also in security configuration. But can someone explain me, why the #Autowired objectMapper is null? Its created in the parent context (the fact that the parent exists is even logged by spring at startup). Also #Autowired has required=true by default, so it should not blow up in the configure method (it should have blown up in construction of the context, if the bean wasn't there for some reason).
It seems to me that there might be some lifecycle problem in spring - in a sense that it calls the overridden methods first, and then #Autowires the dependencies... I have also tried to #Autowire the BusinessConfig (should be perfectly legal according to documentation - the result was the same (null)).
What should I do to make this working?
Thanks in advance!
EDIT - ISSUE FOUND
I found the issue. Unfortunately it had nothing to do with WebMvcConfigurerAdapter nor #Configuration. It was caused by premature initialization of context triggered by missing static modifier for propertyPlaceholderConfigurer... I have created issue in Spring core jira (https://jira.spring.io/browse/SPR-14382)
What about simply renaming the bean declaration method to match with the autowired bean?
#Configuration
public class BusinessConfig {
#Bean
public ObjectMapper objectMapper() { return new ObjectMapper() }
}
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
private ObjectMapper objectMapper;
[...]
}

Resources