tags:

views:

1378

answers:

2

A client is having an issue running java2ws on some of their code, which uses & extends classes that are consumed from my SOAP web services. Confused yet? :)

I'm exposing a SOAP web service (JBoss5, Java 6). Someone is consuming that web service with Axis1 and creating a jar out of it with the data types and client stubs. They are then defining their own type, which extends one of my types. My type contains an enumeration.

class MyParent {
 private MyEnumType myEnum;

 // getters, settters for myEnum;
 }

 class TheirChild extends MyParent {
 ...
 }

When they are running java2ws on their code (which extends my class), they get

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

The enum I've defined is below. This is now how it comes out after being consumed, but it's how I have it defined on the app server:


@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;
    }
}

I've seen things online and other posts, like (this one) regarding Jaxb's inability to handle Lists or things like that, but I'm baffled about my enum. I'm pretty sure you can't have a default constructor for an enum (well, at least a public no-arg constructor, Java yells at me when I try), so I'm not sure what makes this error possible. Any ideas?

Also, the "2 counts of IllegalAnnotationsExceptions" may be because my code actually has two enums that are written similarly, but I left them out of this example for brevity.

A: 

I am certain you can have a default constructor for an enum. In fact, that what you have when you don't define a constructor explicitely (like yours with a String parameter).

You can also have several constructors, one no-args and others.


In the precise example you give, it would be simple to avoid the String parameter altogether. The provided name() method has exactly the value you are provided. The code would even be simpler:

    @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;
    }
   }


If you have really some complex parameters to set to each value, and can't have specific constructors because of a library, you could also store your varying values into an EnumMap, and read this as needed.

KLE
A: 

The no-arg constructor for JAXB doesn't have to be public, it can be private:

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

MyEnumType(String v) {
    value = v;
}

You can't keep the value member final this way, though.

Fabian Steeg
If this is done in the server-side XML type, will it propagate down when it's been wsconsumed, or does this need to be edited into the generated .java file (the output of wsdl2java)?
Dave
I'm not entirely sure for your setup, but from what I understand the WSDL is generated from the enum using JAXB at some point, so from my understanding this should work when done in your server-side enum definition.
Fabian Steeg