I have some SQL queries stored in the applicationContext.xml file in the form of the Map
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:map id="queries" key-type="java.lang.String" value-type="java.lang.String">
<description>Map contain SQL queries to handle ETL Framework database operations</description>
<entry key="getJobById" value="SELECT * FROM etl_jobs WHERE job_id = ?"/>
<entry key="getJobsByName" value="SELECT * FROM etl_jobs WHERE job_name LIKE ?"/>
...
</util:map>
In my Java code I have the following:
@Repository
@ImportResource("classpath:applicationContext.xml")
public class EtlDataRepository {
private static final Logger LOG = LoggerFactory.getLogger(EtlDataRepository.class.getName());
@Autowired
private JdbcTemplate jdbc;
private Map<String, String> queries;
...
}
I do have setters and getters for this class as well. However, queries bean is not loaded when application starts, i.e. it is null. I had the very similar code written couple years ago and it was working perfectly fine. What has changed in Spring-boot from v.2.3 to v.3.2 to make it not working and how do I fix it?
Moving @ImportResource to the top, i.e. @SpringBootApplication did not change a thing. Adding @Autowired to the Map queries caused the following error:
*************************** APPLICATION FAILED TO START
Description:
Field queries in com.visa.vms.etl.daemon.dao.EtlDataRepository required a bean of type 'java.util.Map' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
The bean is defined in the applicationContext.xml file. It looks like this context is not being imported.
The very same code (with different content of map) was used in the older application with SpringBoot v.2.3 and was working without autowiring.
With @Qualifier("queries")
I was able to "wire" the described (xml+) map.... like so:
package com.example.demo;
import java.util.Map;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportResource;
@SpringBootApplication
@ImportResource("classpath:applicationContext.xml")
public class Demo {
public static void main(String[] args) {
SpringApplication.run(Demo.class, args);
}
@Bean
InitializingBean hello(/*@Autowired*/ @Qualifier("queries") Map<String, String> queries) {
return () -> System.err.println(queries);
}
}
... there is no strong argument, why it should not work in any Bean/Repository/Service.
Though, I could not reproduce the error so quickly: Omitting qualifier at least populates (somehow in a default quickstart) an empty map.
To reproduce "failed application start" we can use:
@Bean
InitializingBean hello2(Map x) {
return () -> System.err.println(x);
}
, where nor:
It gives us (in a spring-boot quickstart):
...
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method hello2 in com.example.demo.Demo required a single bean, but 5 were found:
- queries: defined in unknown location
- systemProperties: a programmatically registered singleton
- systemEnvironment: a programmatically registered singleton
- contextParameters: a programmatically registered singleton
- contextAttributes: a programmatically registered singleton
This is also possible:
//..somewhere in a spring bean (aware of applicationContext.xml)...
@Value("#{queries}") Map<String, String> queries;
... an (org.springframework...)@Value
+ SpEL for "'queries' bean" + matching field/parameter.