Spring Injecting util:map in Kotlin with type safety - spring

I have the several bean definitions in XML to store my SQL externally. I want to inject them in Kotlin as Map<String,String> however the only way I've been able to make it work so far it injecting it as Map<Any,Any>. Is there a way to ensure type safety here. Injecting it as Map<Any,Any> feels ghetto.
When I try Map<String,String> or even Map<String,Any> I get not qualifying beans found...
Example XML
<?xml version="1.0" encoding="UTF-8" ?>
<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"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<util:map id="brandSql" key-type="java.lang.String" value-type="java.lang.String">
<entry key="selectBrands">
<value type="java.lang.String">
<![CDATA[
SELECT
ID,
NAME
FROM BRAND
]]>
</value>
</entry>
</util:map>
</beans>
Injection into service
#Service
open class JdbcBrandService #Autowired constructor(
private val namedJdbcTemplate: NamedParameterJdbcTemplate
): BrandService {
companion object {
val logger = LoggerFactory.getLogger(JdbcBrandService::class.java)
}
#Autowired
#Qualifier(value = "brandSql")
private lateinit var queries: Map<Any,Any>
/// methods and what not go here
}
In Java I can get away with doing something like the following, but Kotlin's type system being more strict seems to prevent this.
#RestController
public class JavaBrandController {
private final Map<String, String> brandSql;
#Autowired
public JavaBrandController(#Qualifier("brandSql") Map sql) {
this.brandSql = sql;
}
#GetMapping("/javaBrands")
public Map getBrandSql() {
return this.brandSql;
}
}

Personally, it feels strange to have beans floating around that are of such generic types as Map<String, String>. It would create confusion when you need other maps.
What I would do is create a container class that holds a reference to the map, so you have a proper type to reference.
Example:
class SqlConfig(val map: Map<String, String>)
Then create a bean of this type in your xml:
<util:map id="brandSql" key-type="java.lang.String" value-type="java.lang.String">
<entry key="selectBrands">
<value type="java.lang.String">
<![CDATA[
SELECT
ID,
NAME
FROM BRAND
]]>
</value>
</entry>
</util:map>
<bean id = "sqlConfig" class = "test.package.SqlConfig">
<constructor-arg ref = "brandSql"/>
</bean>
Now you can autowire it as needed with the proper type in a non-guetto way:
#Autowired
#Qualifier(value = "sqlConfig") // <-- the qualifier is no longer needed
private lateinit var queries: SqlConfig

Related

#Autowired annotation returns null [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 6 years ago.
When I develop in the Spring Framework, I wanted to get an access to DB using mybatis on the specific class, here is problem.
public class ScheduleManager {
private Scheduler scheduler;
#Autowired
private TriggerService triggerService;
public void doit() {
System.out.println(triggerService);
}
}
At here, value of triggerService is null. I think triggerService was not autowired.
But it is autowired at this class.
#Controller
public class TestController {
#Autowired
private TriggerService triggerService;
#RequestMapping("/scheduletest")
public String scheduleTest() {
System.out.println(triggerService);
ScheduleManager sm = new ScheduleManager();
sm.doit();
}
}
this code print some value not null.
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.scheduler"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="order" value="0"/>
</bean>
</beans>
TriggerService interface
#Service
public interface TriggerService {
public List<Trigger> getAll();
}
Why does this problem appear?
You create the ScheduleManager instance by yourself:
ScheduleManager sm = new ScheduleManager();
So Spring doesn't know about this object and doesn't do any autowiring.
To resolve this, add the #Component annotation to ScheduleManager and let it also inject in the controller:
#Autowired
private ScheduleManager scheduleManager;
Your TriggerService is only an Interface, how could spring find the acutual implementation.
remove #Service from TriggerService and add it to one of the implementation of TriggerService will fix your problem

Why `autowire=byType` will also inject beans by name?

I found something not clear about the autowire=byType behavior.
Java code under package my:
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class UserService {
#Autowired
private User user1;
#Autowired
private User user2;
public String getNames() {
return user1.getName() + " & " + user2.getName();
}
}
Spring config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<context:component-scan base-package="my"/>
<context:annotation-config/>
<bean id="user1" class="my.User" autowire="byType">
<constructor-arg value="Freewind"/>
</bean>
<bean id="user2" class="my.User" autowire="byType">
<constructor-arg value="Lily"/>
</bean>
</beans>
Running code:
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = context.getBean(UserService.class);
System.out.println(service.getNames());
}
}
It's working well and prints:
Freewind & Lily
But I was expecting it should not work, because I used autowire="byType" when I defined the beans, and there are two beans with the same type User in UserService.
And, if I changed the name of the bean, say, user1 -> user999, it will report some error like No qualifying bean of type [my.User] is defined error.
It seems spring will automatic check the name even if I specified byType, which is strange.
PS: I've tested with spring 4.1.3.RELEASE and 3.2.2.RELEASE, same behavior.
<bean id="user2" class="my.User" autowire="byType">
<constructor-arg value="Lily"/>
</bean>
The autowire="byType" here means that you want to have (missing) dependencies injected into this bean byType. It only applies to the bean the attribute is placed on. In the xml namespace the default for all the beans could be set.
However in your case you are using actually using annotations (note <context:annotation-config /> is already implied by the usage of </context:component-scan />). Annotation driven injection (#Autowired, #Inject are always by type, #Resource uses a name or jndi lookup and as fallback by name).
When starting the application and scanning for components for each needed dependency the DependencyDescriptor is created. This class contains the details used for autowiring, it amongst other things contains the type and the name. The name, in case of a Field is derived from the actual name.

about a BeanCurrentlyInCreationException, unresolvable circular reference

Good afternoon, I have a project based on apache-cxf v 2.5.2, spring 2.5.6 and hibernate v v 3.2.1. I'm using annotations to mark the units and objects I persist and am having a problem when deploying the war. Giving me the following exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'storeService': Can not resolve reference to bean 'storeService' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'storeService': Requested bean is Currently in creation: is there an unresolvable loop reference?
this is the applicationContext.xml file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
">
<context:component-scan base-package="com.aironman.core" />
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:hibernate.properties"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=${database.hibernate.dialect}
hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
hibernate.show_sql=true
hibernate.use_sql_comments=true
hibernate.jdbc.batch_size=0
hibernate.hbm2ddl.auto=create-drop
hibernate.default_schema=${hibernate.default_schema}
hibernate.generate_statistics=true
hibernate.cache.use_structured_entries=true
</value>
</property>
<property name="annotatedClasses">
<list>
<value>com.aironman.core.pojos.Usuario</value>
<value>com.aironman.core.pojos.Item</value>
<value>com.aironman.core.pojos.Persona</value>
</list>
</property>
</bean>
</beans>
this is beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- DECLARACION DE LOS ENDPOINTS DE LOS WEB SERVICES-->
<jaxws:endpoint
id="storeService" implementor="#storeService"
implementorClass="com.aironman.core.cxf.service.StoreServiceImpl"
address="/Store" />
</beans>
both files are included on web.xml
this is implementation end point web service, storeService:
**#Service("storeService")
#WebService(endpointInterface = "com.aironman.core.cxf.service.StoreService")
public class StoreServiceImpl implements StoreService** {
private Log log = LogFactory.getLog(StoreServiceImpl.class);
#Autowired
#Qualifier("servicioUsuarios")
private ServicioUsuarios servicioUsuarios;
#Autowired
#Qualifier("servicioItems")
private ServicioItems servicioItems;
#Autowired
#Qualifier("servicioApuntes")
private ServicioApuntesContables servicioApuntesContables;
[B]public StoreServiceImpl()[/B]{
log.info("CONSTRUCTOR SIN tipo StoreServiceImpl...");
}
some methods... getters and setters ...
}
this is ServicioUsuariosImpl file:
package com.aironman.core.service;
**#Service("servicioUsuarios")
public class ServicioUsuariosImpl implements ServicioUsuarios** {
private static ConcurrentHashMap <String,Usuario>hashMapUsuarios = new ConcurrentHashMap <String,Usuario> () ;
private Log log = LogFactory.getLog(ServicioUsuariosImpl.class);
#Autowired
#Qualifier("servicioEncriptacion")
private ServicioEncriptacion servicioEncriptacion;
#Autowired
#Qualifier("servicioPersistenciaUsuarios")
private ServicioPersistenciaUsuarios servicioPersistenciaUsuarios;
public ServicioUsuariosImpl(){
log.info("Constructor SIN tipo ServicioUsuariosImpl...");
//TODO pendiente cargar el mapa con una llamada al servicioPersistencia
}
#PostConstruct
public void init()
{
log.info("init method on ServicioUsuariosImpl. Initializing hashMap...");
//i need to call persistence layer to fill the hashMap
}
some methods, getters and setters
}
As you can see, this service has inyected a persistent service called servicioPersistenciaUsuarios, which basically uses a dao marked as #repository.
this is ServicioPersistenciaUsuariosImpl implementation file:
package com.aironman.core.service;
**#Service("servicioPersistenciaUsuarios")
public class ServicioPersistenciaUsuariosImpl implements ServicioPersistenciaUsuarios** {
#Autowired
#Qualifier("usuarioHibernateDao")
private UsuarioHibernateDao usuarioHibernateDao;
private Log log = LogFactory.getLog(ServicioPersistenciaUsuariosImpl.class);
public ServicioPersistenciaUsuariosImpl()
{
log.info("Constructor ServicioPersistenciaUsuariosImpl...");
}
some methods, getters and setters
}
this is usuarioHibernateDao implementation file:
package com.aironman.core.hibernate;
**#Repository
public class UsuarioHibernateDao extends HibernateGenericDao<Usuario, String> implements UsuarioDao**
{
private Log log = LogFactory.getLog(UsuarioHibernateDao.class);
[B]#Autowired
public UsuarioHibernateDao(#Qualifier("sessionFactory") SessionFactory sessionFactory) [/B]{
super(sessionFactory);
}
some methods...
}
ServicioUsuariosImpl has another dependencie, servicioEncriptacion, and as you may see, this is the implementation:
package com.aironman.core.service;
#Service("servicioEncriptacion")
public class ServicioEncriptacionImpl implements ServicioEncriptacion
{
private static final String algoritmo = "SHA-256";
private Log log = LogFactory.getLog(ServicioEncriptacionImpl.class);
private static java.security.MessageDigest diggest ;
[B]public ServicioEncriptacionImpl()[/B]
{some code...
}
some methods...
}
this is ServicioItemsImpl implementation file, another dependencie belongs to StoreServiceImpl.
package com.aironman.core.service;
**#Service("servicioItems")
public class ServicioItemsImpl implements ServicioItems**{
private static final ConcurrentHashMap
<String,com.aironman.core.pojos.Item>
//La pk es el isbn del item
hashMapItems = new ConcurrentHashMap<String,com.aironman.core.pojos.Item>() ;
private Log log = LogFactory.getLog(ServicioItemsImpl.class);
#Autowired
#Qualifier("servicioPersistenciaItems")
private ServicioPersistenciaItems servicioPersistenciaItems;
[B]public ServicioItemsImpl()[/B]
{
log.info("Constructor SIN TIPO ServicioItemsImpl");
}
[B]#PostConstruct
public void init()[/B]
{
log.info("init method on ServicioItemsImpl. Initializing hashMap...");
}
some methods, getters and setters
}
this is servicioPersistenciaItems implementation file:
package com.aironman.core.service;
#Service("servicioPersistenciaItems")
public class ServicioPersistenciaItemsImpl implements ServicioPersistenciaItems
{
#Autowired
#Qualifier("itemHibernateDao")
private ItemHibernateDao itemHibernateDao;
private Log log = LogFactory.getLog(ServicioPersistenciaItemsImpl.class);
[B]public ServicioPersistenciaItemsImpl()[/B]
{
log.info("Constructor SIN tipo ServicioPersistenciaItemsImpl...");
}
some methods, getters and setters...
}
and finish, ServicioApuntesContablesImpl implementation file, with no dependencies
package com.aironman.core.service;
[B]#Service("servicioApuntes")
public class ServicioApuntesContablesImpl implements ServicioApuntesContables[/B]{
private Log log = LogFactory.getLog(ServicioApuntesContablesImpl.class);
private static ConcurrentHashMap <ClaveApunteContable,ApunteContable> mapaApuntesContables
= new ConcurrentHashMap <ClaveApunteContable,ApunteContable> ();
//TODO al final tendre que persistir los apuntes contables, por ahora los mantendre en memoria...
[B]public ServicioApuntesContablesImpl()[/B]
{}
some methods
}
in short, the problem is happening when Spring tries to instantiate the endpoint implementation file storeService and do not understand it because I have no typed constructor in any of the files, getters and setters I have the right and above any dependence is used to each other. Can someone please help me and explain what is happening? thank you very much
PD i have not put some code for readability issues and i easyly reach limit caracters, if someone needs to watch, let me know.
Ok, i allready solved my problem. Inside the endpoints.xml file a declared my ws with a id and i d already have declared the implementation ws file with a #Service annotation, so the exception is now clear to me...

Spring Autowire Fundamentals

I am a newbie in Spring and am trying to understand the below concept.
Assume that accountDAO is a dependency of AccountService.
Scenario 1:
<bean id="accServiceRef" class="com.service.AccountService">
<property name="accountDAO " ref="accDAORef"/>
</bean>
<bean id="accDAORef" class="com.dao.AccountDAO"/>
Scenario 2:
<bean id="accServiceRef" class="com.service.AccountService" autowire="byName"/>
<bean id="accDAORef" class="com.dao.AccountDAO"/>
In AccountService Class:
public class AccountService {
AccountDAO accountDAO;
....
....
}
In the second scenario, How is the dependency injected ? When we say it is autowired by Name , how exactly is it being done. Which name is matched while injecing the dependency?
Thanks in advance!
Use #Component and #Autowire, it's the Spring 3.0 way
#Component
public class AccountService {
#Autowired
private AccountDAO accountDAO;
/* ... */
}
Put a component scan in your app context rather than declare the beans directly.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com"/>
</beans>
<bean id="accServiceRef" class="com.service.accountService" autowire="byName">
</bean>
<bean id="accDAORef" class="com.dao.accountDAO">
</bean>
and
public class AccountService {
AccountDAO accountDAO;
/* more stuff */
}
When spring finds the autowire property inside accServiceRef bean, it will scan the instance variables inside the AccountService class for a matching name. If any of the instance variable name matches the bean name in the xml file, that bean will be injected into the AccountService class. In this case, a match is found for accountDAO.
Hope it makes sense.

Spring - How do you set Enum keys in a Map with annotations

I've an Enum class
public enum MyEnum{
ABC;
}
than my 'Mick' class has this property
private Map<MyEnum, OtherObj> myMap;
I've this spring xml configuration.
<util:map id="myMap">
<entry key="ABC" value-ref="myObj" />
</util:map>
<bean id="mick" class="com.x.Mick">
<property name="myMap" ref="myMap" />
</bean>
and this is fine.
I'd like to replace this xml configuration with Spring annotations.
Do you have any idea on how to autowire the map?
The problem here is that if I switch from xml config to the #Autowired annotation (on the myMap attribute of the Mick class) Spring is throwing this exception
nested exception is org.springframework.beans.FatalBeanException: Key type [class com.MyEnum] of map [java.util.Map] must be assignable to [java.lang.String]
Spring is no more able to recognize the string ABC as a MyEnum.ABC object.
Any idea?
Thanks
This worked for me...
My Spring application context:
<util:map id="myMap">
<entry key="#{T(com.acme.MyEnum).ELEM1}" value="value1" />
<entry key="#{T(com.acme.MyEnum).ELEM2}" value="value2" />
</util:map>
My class where the Map gets injected:
public class MyClass {
private #Resource Map<MyEnum, String> myMap;
}
The important things to note are that in the Spring context I used SpEL (Spring Expression Language) which is only available since version 3.0. And in my class I used #Resource, neither #Inject (it didn't work for me) nor #Autowired (I didn't try this). The only difference I'm aware of between #Resource and #Autowired, is that the former auto-inject by bean name while the later does it by bean type.
Enjoy!
This one gave me fits but I was able to piece it together using David's answer and some other links (below).
do not change the names of the properties in the MapFactoryBean declaration.
ensure that key-type attribute points to the enum that you want to use as a key in the map.
Class
#Component
public class MyClass {
private Map<MyEnum, ValueObjectInterface> valueMap;
#Autowired
public void setValueMap(final Map<MyEnum, ValueObjectInterface> valueMap) {
this.valueMap= valueMap;
}
}
Enum
public enum MyEnum{
FOO ("FOO"),
BAR ("BAR"),
BAZ ("BAZ");
}
XML Config file:
<bean id="valueMap" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="targetMapClass">
<value>java.util.HashMap</value>
</property>
<property name="sourceMap">
<map key-type="com.company.packagepath.MyEnum">
<entry key="FOO" value-ref="valueObject1" />
<entry key="BAR" value-ref="valueObject2" />
<entry key="BAZ" value-ref="valueObject3" />
</map>
</property>
</bean>
<bean id="valueObject1" class="com.company.packagepath.ValueObject1" />
<bean id="valueObject2" class="com.company.packagepath.ValueObject2" />
<bean id="valueObject3" class="com.company.packagepath.ValueObject3" />
LINKS
Code Ranch
Spring MapFactoryBean example at mkyong.com
How assign bean's property an Enum value in Spring config file?
Application context
<?xml version="1.0" encoding="UTF-8"?>
<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-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd ">
<bean id="myProvider" class="com.project.MapProvider">
<property name="myMap" ref="myMap"/>
</bean>
<util:map id="myMap" key-type="com.project.MyEnum" value-type="com.project.ValueObject">
<entry>
<key><value type="com.project.MyEnum">FOO</value></key>
<ref bean="objectValue1"/>
</entry>
</util:map>
</beans>
Java class
package com.project;
public class MapProvider {
private Map<MyEnum, ValueObject> myMap;
public void setMyMap(Map<MyEnum, ValueObject> myMap) {
this.myMap = myMap;
}
}
Should be:
public class Mick {
private Map<MyEnum, OtherObj> myMap;
#Autowired
public void setMyMap(Map<MyEnum, OtherObj> myMap) {
this.myMap = myMap;
}
}
Have a look at http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config
Updated
The problem is that according to the util schema, you cannot specify the key or value types. You can however to implement a MapFactoryBean of your own (just inherit from org.springframework.beans.factory.config.MapFactoryBean). One ceveat - notice that the generic definition (even thought erased in runtime) doesn't get in the way.
The <util:map> element has key-type, resp. value-type attributes, that represents the class of the keys, resp. the values. If you specify the fully qualified class of your enum in the key-type attribute, the keys are then parsed into that enum when creating the map.
Spring verifies during injection that the map's key and value types -as declared in the class containing the map- are assignment-compatible with the key and value types of the map bean. This is actually where you get the exception from.
You just need to use concrete Map class as HashMap and not abstract or interface:
public class Mick {
private HashMap<MyEnum, OtherObj> myMap;
#Autowired
public void setMyMap(HashMap<MyEnum, OtherObj> myMap) {
this.myMap = myMap;
}
}
public class AppConfig
{
#Bean
public HashMap<MyEnum, OtherObj> myMap() { .. }
}
If you have a Map with an Enum values as keys, then consider using Java's EnumMap implementation:
https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/EnumMap.html
Here you also have a Baeldung post with some examples on how to use it:
https://www.baeldung.com/java-enum-map

Resources