使用Jaxb和cxf,枚举“没有no-arg默认构造函数”

时间:2009-09-15 20:42:32

标签: java jaxb cxf

客户端在某些代码上运行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(扩展我的类)时,他们会得到

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会对我大吼大叫),所以我不确定是什么原因导致这个错误成为可能。有什么想法吗?

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

3 个答案:

答案 0 :(得分:9)

JAXB的no-arg构造函数不必是public,它可以是private

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

MyEnumType(String v) {
    value = v;
}

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

答案 1 :(得分:2)

我确信你可以拥有枚举的默认构造函数。 实际上,当你没有明确地定义构造函数时,你拥有的是什么 (和你的String参数一样)。

你也可以有几个构造函数,一个没有参数和其他构造函数。


在您给出的精确示例中,完全避免使用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中,并根据需要进行读取。

答案 2 :(得分:0)

当您从-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. CAN' T包含public void setValue(){}
  4. 必须实现String toString(),但每个对象都实现它。