【问题标题】:Enum "does not have a no-arg default constructor" with Jaxb and cxf使用 Jaxb 和 cxf 枚举“没有无参数默认构造函数”
【发布时间】:2009-09-15 20:42:32
【问题描述】:

客户端在其某些代码上运行 java2ws 时遇到问题,该代码使用 & 扩展了从我的 SOAP Web 服务使用的类。迷茫了吗? :)

我正在公开一个 SOAP Web 服务(JBoss5、Java 6)。有人正在使用 Axis1 使用该 Web 服务,并使用数据类型和客户端存根创建一个 jar。然后他们定义了自己的类型,扩展了我的一种类型。我的类型包含一个枚举。

class MyParent {
 private MyEnumType myEnum;

 // getters, settters for myEnum;
 }

 class TheirChild extends MyParent {
 ...
 }

当他们在他们的代码(扩展我的类)上运行 java2ws 时,他们得到 ​​p>

Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
net.foo.bar.MyEnuMType does not have a no-arg default constructor.
    this problem is related to the following location:
            at net.foo.bar.MyEnumType
            at public net.foo.bar.MyEnumType net.foo.bar.MyParent.getMyEnum()

我定义的枚举如下。这是现在它被消费后的样子,但这是我在应用服务器上定义的方式:

@XmlType(name = "MyEnumType") @XmlEnum public enum MyEnumType { Val1("Val1"), Val2("Val2") private final String value; MyEnumType(String v) { value = v; } public String value() { return value; } public static MyEnumType fromValue(String v) { if (v == null || v.length() == 0) { return null; } if (v.equals("Val1")) { return MyEnumType.Val1; } if (v.equals("Val2")) { return MyEnumType.Val2; } return null; } }

我在网上和其他帖子中看到过东西,比如 (this one) 关于 Jaxb 无法处理列表或类似的东西,但我对我的枚举感到困惑。我很确定你不能有一个枚举的默认构造函数(好吧,至少是一个公共的无参数构造函数,当我尝试时 Java 会对我大喊大叫),所以我不确定是什么导致了这个错误。有什么想法吗?

此外,“2 个 IllegalAnnotationsExceptions 计数”可能是因为我的代码实际上有两个编写类似的枚举,但为了简洁起见,我将它们排除在此示例之外。

【问题讨论】:

  • 这是一种奇怪的技术组合... java2ws 是 Apache CXF,对吧?那是基于Java5的。 Axis1 是古老的,并且是 Java5 之前的版本。这是怎么回事?
  • 客户正在为项目 1 使用和使用我们的 WSDL。项目 2 出现(为他们),他们获取了我们的一些对象(他们通过使用axis1 wsdl2java 获得),包装它们,并且试图通过 CXF 为其他人导出它们。所以第一部分(使用我们的 WSDL 并使用它)似乎可以工作,但是尝试使用来自 axis1 消费的 java2ws 对象显然是相当冒险的。

标签: java jaxb cxf


【解决方案1】:

JAXB 的无参数构造函数不必是public,可以是private

private String value;
private MyEnumType() {} // for JAXB

MyEnumType(String v) {
    value = v;
}

但是,您不能以这种方式保留 value 成员 final

【讨论】:

  • 如果这是在服务器端的XML类型中完成的,它会在被wsconsumed时向下传播,还是需要将其编辑到生成的.java文件中(wsdl2java的输出)?
  • 我不完全确定您的设置,但据我了解,WSDL 是在某些时候使用 JAXB 从枚举生成的,因此据我了解,这在您的服务器端完成时应该可以工作枚举定义。
【解决方案2】:

我确信您可以为枚举使用默认构造函数。 事实上,当您没有明确定义构造函数时,您所拥有的 (就像你的字符串参数一样)。

您还可以有多个构造函数,一个无参数和其他。


在您给出的精确示例中,完全避免使用 String 参数会很简单。 提供的 name() 方法与您提供的值完全相同。 代码会更简单:

    @XmlType(name = "MyEnumType")
    @XmlEnum
    public enum MyEnumType {

    Val1, Val2;

    public String value() {
      return name();
    }

    public static MyEnumType fromValue(String v) {
      for(MyEnumType type : values()) {
        if (type.value().equals(v)) {
          return type;
        }
      }
      return null;
    }
   }

如果您确实需要为每个值设置一些复杂的参数,并且由于库而无法使用特定的构造函数,您还可以将不同的值存储到 EnumMap 中,并根据需要读取。

【讨论】:

    【解决方案3】:

    当你做from-java-to-wsdl时,apache首先检查它是否是枚举类,只有当这个检查失败时,它才会检查构造函数。您可以在 org.apache.axis.wsdl.fromJava.Types::isBeanCompatible 中看到它。任何正常人,都会认为如果他写了

    public enum MyEnum{} 
    

    这就够了。但是 Apache 开发者不这么认为(IDK 为什么,可能是出于某些兼容性的原因)。他们使用这种方法 - org.apache.axis.utils.JavaUtils::isEnumClassSub。

    如果你将这个类分解,你会看到你的枚举

    1. 必须实现 public String getValue() {return name();}
    2. 必须实现 public MyEnum fromString(String v){return valueOf(v);}
    3. 不能包含 public void setValue(){}
    4. 必须实现 String toString(),但每个对象都实现它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-14
      • 2012-12-08
      相关资源
      最近更新 更多