Java Spring Framework:使用 util:map 填充 Map<Enum,Object>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3627897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 02:53:21  来源:igfitidea点击:

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

javaspring

提问by emeraldjava

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.

我有这个工厂类,我想通过 spring 连接它以进行地图的运行时配置。该地图包含一个枚举对象和标准 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!

我的 spring util:map 接线有问题,因为我不确定在定义键值时如何正确引用特定的枚举类型。映射值的 bean 引用很简单。spring map 接线的所有例子似乎都假设 key 是一个字符串!

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

采纳答案by emeraldjava

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,我找到了一种解决方法 - 感谢created-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

定义了枚举后,我可以在地图中对它们进行 key-ref

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

回答by mR_fr0g

I think this is what you need. Note i don't think you need to specify the key-type and value-type attributes. Spring should be able to work that out.

我认为这就是你所需要的。请注意,我认为您不需要指定 key-type 和 value-type 属性。Spring 应该能够解决这个问题。

<bean id="genericEntityFactory" class="com.xx.xx.common.index.GenericEntityFactoryImpl">
  <property name="indexEntityMap" ref="indexEntityMapBean"/>
</bean>

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

The only reason you would use <util:mapinstead of the cleaner annonomous <map>(see section 3.3.3.3) is if you wanted to wire the same map into multiple places or you wanted to use a different underlying map implementation eg ConcurrentHashMap.

使用<util:map更简洁的 annonomous <map>(参见第3.3.3.3节)的唯一原因是,如果您想将同一个映射连接到多个位置,或者您想使用不同的底层映射实现,例如 ConcurrentHashMap。

回答by chris

Here's an alternate and shorter format:

这是另一种更短的格式:

<bean id="versionService" class="my.service.VersionService" 
        p:animalDAOMap-ref="animalDAOMap"/>

<util:map id="p:animalDAOMap">
    <entry key="chicken" value-ref="chickenDAO"/>
    <entry key="monkey" value-ref="monkeyDAO"/>
    <entry key="pig" value-ref="pigDAO"/>
</util:map>

Make sure to include the namespace

确保包含命名空间

xmlns:util="http://www.springframework.org/schema/util"

And the schema

和模式

http://www.springframework.org/schema/util 
http://www.springframework.org/schema/util/spring-util-3.0.xsd

By the way I'm using Spring 3.0+ here

顺便说一下,我在这里使用 Spring 3.0+

回答by Mosolov Sergey

Got the same error as you do. I was able to avoid it by moving my enum to standalone file and make my enum public.

遇到和你一样的错误。我能够通过将我的枚举移动到独立文件并公开我的枚举来避免它。

So my

所以我的

public enum EventType { INFO, ERROR }

Are placed in

被放置在

EventType.java

事件类型.java

Also I have only one package if that matters somehow. I'm injecting dependency that way (through xml by constructor arg):

另外,如果这很重要的话,我只有一个包裹。我正在以这种方式注入依赖项(通过构造函数 arg 通过 xml):

spring.xml:

弹簧.xml:

<constructor-arg>
    <map>
        <entry key="INFO" value-ref="consoleEventLogger"></entry>
        <entry key="ERROR" value-ref="combinedEventLogger"></entry>
    </map>
</constructor-arg>

That's working for me with spring-core 4.3.6

这对我使用 spring-core 4.3.6

I believe there is an explanation, that depends on reflection and internal Spring logic. But I don't has much Java experience, and I can't provide that.

我相信有一种解释,这取决于反射和内部 Spring 逻辑。但我没有太多的 Java 经验,我无法提供。