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
Spring Framework : Populating a Map<Enum,Object> with util:map
提问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:map
instead 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 经验,我无法提供。