【问题标题】:Spring - How do you set Enum keys in a Map with annotationsSpring - 如何在带有注释的 Map 中设置枚举键
【发布时间】:2009-07-23 20:34:33
【问题描述】:

我有一个枚举类

public enum MyEnum{
    ABC;
}

比我的 'Mick' 班级有这个属性

private Map<MyEnum, OtherObj> myMap;

我有这个 spring xml 配置。

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

这很好。
我想用 Spring 注释替换这个 xml 配置。
您对如何自动连接地图有任何想法吗?

这里的问题是,如果我从 xml 配置切换到 @Autowired 注释(在 Mick 类的 myMap 属性上),Spring 会抛出这个异常

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 不再能够将字符串 ABC 识别为 MyEnum.ABC 对象。
有什么想法吗?

谢谢

【问题讨论】:

  • 不清楚您要做什么。你在想什么样的注释?
  • 我想使用@Autowired 注释,但它不起作用。我是否必须指定其他内容来告诉 Spring 将该键值视为枚举而不是字符串?

标签: spring enums annotations


【解决方案1】:

这对我有用...

我的 Spring 应用上下文:

<util:map id="myMap">
  <entry key="#{T(com.acme.MyEnum).ELEM1}" value="value1" />
  <entry key="#{T(com.acme.MyEnum).ELEM2}" value="value2" />
</util:map>

Map 被注入的班级:

public class MyClass {

    private @Resource Map<MyEnum, String> myMap;
}

需要注意的重要一点是,在 Spring 上下文中,我使用了 SpEL(Spring 表达式语言),它仅在 3.0 版之后才可用。在我的课堂上,我使用了@Resource,既不是@Inject(它对我不起作用)也不是@Autowired(我没有尝试这个)。我知道@Resource@Autowired 之间的唯一区别是前者按bean 名称自动注入,而后者按bean 类型自动注入。

享受吧!

【讨论】:

  • 记得使用 '$' 而不是 '.'用于在 Spring EL 中将内部枚举与外部类分开。
  • 只是跟进@Autowired 也将产生Key type [class com.foo.Bar$BAZ] of map [java.util.Map] must be assignable to [java.lang.String]@Resource 是赢家。 +1 @Amir,$ 是一个陷阱。
  • 问题说“我想用 Spring 注释替换这个 xml 配置。”但是这里仍然有配置 XML。这是否意味着您不能在 Spring 中仅使用注释来执行此操作?
  • @Jonik 我认为预期的替换是 bean 和资源注入部分,而不是映射部分。否则,我不确定为什么选择了这个答案。
  • 非常感谢您。只有@Resource 有效。我试过@Autowired,但没有用。奇怪,但我会选择@Resource
【解决方案2】:

这个让我很适合,但我能够使用大卫的回答和其他一些链接(如下)将它拼凑起来。

  • 不要更改 MapFactoryBean 声明中的属性名称。
  • 确保 key-type 属性指向要在映射中用作键的枚举。

@Component
public class MyClass {

    private Map<MyEnum, ValueObjectInterface> valueMap;

    @Autowired
    public void setValueMap(final Map<MyEnum, ValueObjectInterface> valueMap) {
        this.valueMap= valueMap;
    }


}

枚举

    public enum MyEnum{
    FOO ("FOO"),
    BAR ("BAR"),
    BAZ ("BAZ");
}

XML 配置文件:

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

链接

【讨论】:

    【解决方案3】:

    应用程序上下文

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

    package com.project;
    
    public class MapProvider {
    
        private Map<MyEnum, ValueObject> myMap;
    
        public void setMyMap(Map<MyEnum, ValueObject> myMap) {
            this.myMap = myMap;
        }
    }
    

    【讨论】:

    • 答案需要对您在此处列出的内容进行更多解释。
    • 我创建了以枚举为键的地图并将其用于设置器参数。我认为这很明显:)
    【解决方案4】:

    应该是:

    public class Mick {
    
      private Map<MyEnum, OtherObj> myMap;
    
      @Autowired
      public void setMyMap(Map<MyEnum, OtherObj> myMap) {
        this.myMap = myMap;
      }
    }
    

    看看http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config

    更新

    问题在于,根据 util 架构,您无法指定键或值类型。但是,您可以实现自己的 MapFactoryBean(只需从 org.springframework.beans.factory.config.MapFactoryBean 继承)。一个注意事项 - 请注意通用定义(甚至认为在运行时已删除)不会妨碍您。

    【讨论】:

    • 嗨,David,我知道 @Autowired 注释。这里的问题是,如果我自动装配地图 Spring 不再能够将字符串 ABC 识别为 MyEnum.ABC 对象。使用 XML 配置它可以正常工作,使用注释配置它会抛出此异常嵌套异常是 org.springframework.beans.FatalBeanException:映射 [java.util.Map] 的键类型 [class com.MyEnum] 必须可分配给 [java.lang .String]
    【解决方案5】:

    &lt;util:map&gt; 元素具有键类型,分别是。值类型属性,分别代表键的类。价值。如果您在 key-type 属性中指定枚举的完全限定类,则在创建映射时会将键解析为该枚举。

    Spring 在注入期间验证映射的键和值类型(在包含映射的类中声明)与映射 bean 的键和值类型的赋值兼容。这实际上是您获得异常的地方。

    【讨论】:

      【解决方案6】:

      您只需要使用具体的Map 类作为HashMap 而不是抽象或接口:

      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() { .. }
      }
      

      【讨论】:

        【解决方案7】:

        如果您有一个Map 和一个Enum 值作为键,那么考虑使用Java 的EnumMap 实现:

        https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/EnumMap.html

        这里还有一个 Baeldung 帖子,其中包含一些关于如何使用它的示例:

        https://www.baeldung.com/java-enum-map

        【讨论】:

          猜你喜欢
          • 2013-06-19
          • 2013-08-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-25
          • 1970-01-01
          • 2012-02-14
          • 1970-01-01
          相关资源
          最近更新 更多