Enum.valueOf与JDK 7 SE的错误.values()被破坏

时间:2013-04-30 19:47:38

标签: java enums java-7

这似乎是一个疯狂的错误,但{JD} 7 SE上Enum.valueOf(type, name)似乎不稳定。

表现形式是,在完全相同的名称字符串(我已经验证过)上,对valueOf()的调用有时会抛出IllegalArgumentException消息No enum constant ...

我的团队通过Eclipse调试器运行了这个,我们注意到在enum上的valueOf的以下JDK实现中,enumConstantDirectory(),即枚举的values()列表,有时似乎是缺少一些价值观。不是枚举本身定义的所有值的全部。

我可以通过在JVM启动时调用Enum.valueOf(enumclass.class, "XXX")来获取所有可能的枚举值来解决这个问题。当我这样做时,似乎values()总是包含完整的集合。

但是,如果我不进行此类初始化,有时Enum.valueOf()会抛出IllegalArgumentException

上下文:我在使用XStream 1.4.4转换转换枚举的POJO对象时遇到了这个问题,但XStream似乎并不存在这个问题。

有没有人见过这种错误?如果你有,我很想听听。 这令我难以置信。这是Oracle JDK / JVM实现中的错误吗?

public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                            String name) {
    T result = enumType.enumConstantDirectory().get(name);
    if (result != null)
        return result;
    if (name == null)
        throw new NullPointerException("Name is null");
    throw new IllegalArgumentException(
        "No enum constant " + enumType.getCanonicalName() + "." + name);
}

其他相关细节:

我们正在使用org.reflections库在启动时扫描代码中的所有枚举。在扫描期间,我们采用枚举的类型,并在与枚举关联的Class对象上调用clazz.getEnumConstants()。这可能是一个相关的细节。

在查看和java.lang.Class.getEnumConstants()实现时,它似乎在类中共享相同的enumConstants共享对象。我想知道这里的实现是否存在问题。

我们的枚举很简单,没有静态初始化等等。

public enum ScreeningRuleType
{
  INSERT,
  CONFIRMATION,
  AMOUNT,
  EXISTENCE,
  BAN,
  SELECTION,
  CUSTOM; 

  private long id;
  private String descr;

  ScreeningRuleType()
  {
    id = this.ordinal();
    descr= this.toString().replace("_", " ");
  }
}

修改 在试验这个时,我发现了另一种表现形式。在使用System.out初始化之后,现在不是抛出IllegalArgumentException,而是Enum.valueOf返回的值似乎是随机的。

这显示了我在Eclipse调试器中看到的内容。它清楚地显示我在字符串“EXISTENCE”和“EXISTENCE”.intern()上调用valueOf(),并清楚地显示它正在返回AMOUNT()。

Debugger expression

2 个答案:

答案 0 :(得分:6)

我忘了我遇到类似的东西 - 但我怀疑它是java-7之前的版本,可能已经回到Java 4/5天了。

问题在于,enum附带的伴随结构的构建仅在第一次访问其中一个enum时触发。不幸的是,如果您调用其中一种依赖于这些结构的方法,valueOfEnumSet.allOf,例如之前访问其中一个enum,它通常会灾难性地失败

可悲的是,我重构了代码,所以这不会发生,所以我不再有样本了。我会尝试重现这个问题并回复你。

我在这里看到 - Why the Java enum constants initialization is not complete?演示问题的另一个问题。

答案 1 :(得分:4)

实际上我们发现了这个问题。这是一个面子+掌上的时刻。我们通过尝试包含枚举的类的深(非浅)副本,通过反射API破坏了枚举。这具有消除单例枚举本身的所有实例变量的效果。感谢您的所有帮助和建议。