Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Framework : Populating a Map<Enum,Object> with util:map

Tags:

java

spring

I have this factory class, which i want to wire via spring for runtime configuration of the map. The map contains an enum object and standard pojo.

public class GenericEntityFactoryImpl implements GenericEntityFactory
{
    private Map<IndexType,IEntity> indexEntityMap = null;

    @Override
    public IEntity getIndexEntity(IndexType index) {
        return indexEntityMap.get(index);
    }

    public Map<IndexType, IEntity> getIndexEntityMap() {
        return indexEntityMap;
    }

    public void setIndexEntityMap(Map<IndexType, IEntity> indexEntityMap) {
        this.indexEntityMap = indexEntityMap;
    }
}

I'm having trouble with my spring util:map wiring, since i'm not sure how to correctly reference a specific enum type when definiting the key value. The bean ref for the map value is easy. All the examples of spring map wiring seem to assume that the key is a string!

<!-- the value object bean -->
<bean id="cell" class="com.xx.xx.common.index.entity.CellEntity"/>

<bean id="genericEntityFactory" class="com.xx.xx.common.index.GenericEntityFactoryImpl">
  <util:map 
       id="indexEntityMap" 
       map-class="java.util.HashMap" 
       key-type="com.xx.xx.common.index.IndexType" 
       value-type="com.xx.xx.common.index.GenericEntityFactoryImpl">
           <entry key="CELL">
                <ref bean="cell"/>
            </entry>
       </util:map>
</bean> 

Edit

So i refactored the mapping

<bean id="genericEntityFactory" class="com.xx.xx.common.index.GenericEntityFactoryImpl" >
    <property name="indexEntityMap">
        <map >
            <entry key="com.xx.xx.common.index.CELL"><ref bean="cell"/></entry>
        </map>   
    </property>
</bean>

but assumption that spring will be smart fails...

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'genericEntityFactory' defined in class path resource [com/xx/xx/common/index/index-application-context.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.util.LinkedHashMap] to required type [java.util.Map] for property 'indexEntityMap'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [com.xx.xx.common.index.IndexType] for property 'indexEntityMap[com.xx.xx.common.index.CELL]': no matching editors or conversion strategy found
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:480)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:729)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:381)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:84)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:42)
    at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:173)
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:197)
    ... 17 more
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.util.LinkedHashMap] to required type [java.util.Map] for property 'indexEntityMap'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [com.xx.xx.common.index.IndexType] for property 'indexEntityMap[com.xx.xx.common.index.CELL]': no matching editors or conversion strategy found
    at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:391)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1288)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1249)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1010)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472)
    ... 32 more
Caused by: java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [com.xx.xx.common.index.IndexType] for property 'indexEntityMap[com.xx.xx.common.index.CELL]': no matching editors or conversion strategy found
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:219)
    at org.springframework.beans.TypeConverterDelegate.convertToTypedMap(TypeConverterDelegate.java:508)
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:194)
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:138)
    at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:386)
    ... 36 more
like image 926
emeraldjava Avatar asked Sep 02 '10 14:09

emeraldjava


1 Answers

I found a workaround by defining each enum I plan to add to the map as a separate bean - thanks to creating-spring-bean-from-java-5-enum

<bean id="CELL" class="com.xx.xx.common.index.IndexType" factory-method="valueOf">
    <constructor-arg>
        <value>CELL</value>
    </constructor-arg>
</bean>

<bean id="APN" class="com.xx.xx.common.index.IndexType" factory-method="valueOf">
    <constructor-arg>
        <value>APN</value>
    </constructor-arg>
</bean>

Having defined the enums I can them key-ref them in the map

<bean id="genericEntityFactory" class="com.xx.xx.common.index.GenericEntityFactoryImpl" >
    <property name="indexEntityMap">
        <map>
            <entry key-ref="CELL"><ref bean="cell"/></entry>
            <entry key-ref="APN"><ref bean="apn"/></entry>
        </map>   
    </property>
</bean>
like image 125
emeraldjava Avatar answered Oct 18 '22 15:10

emeraldjava