I am using a library that generates code based on IDL definitions. Its great to be able to use common enumerations in various languages (Java, C and C++), but these generated enums don’t seem to play well with JAX-WS.
Basically, main enum ‘super’ class has two members: ordinal and name. It looks similar to this (Note: this is in a third party library and is not JavaBean friendly) :
public class CustomEnum {
int _ordinal;
String _name;
public CustomEnum(int ordinal, String name) {
this._ordinal = ordinal;
this._name = name;
}
public int ordinal() {
return _ordinal;
}
public String name() {
return _name;
}
}
So then in the generated code based on an IDL definition looks similar to this (Using Day as an example — but in actuality I have about 50 ‘enums’ that extend CustomEnum, so I’d like a solution that keeps me from having multiple copies of enums around such as an IDL generated type and a java.lang.enum):
public class Day extends CustomEnum {
public static final Day Sunday = new Day(0, "Sunday");
public static final Day Monday = new Day(1, "Monday");
public static final Day Tuesday = new Day(2, "Tuesday");
public static final Day Wednesday = new Day(3, "Wednesday");
public static final Day Thursday = new Day(4, "Thursday");
public static final Day Friday = new Day(5, "Friday");
public static final Day Saturday = new Day(6, "Saturday");
public Day(int ordinal, String name) {
super(ordinal, name);
}
}
Note that I also do not want to mess with/rearrange/annotate this class either since it is generated code.
So, now what I want to do is to be able to use this ‘Day’ enum as a @WebParam in a JAX-WS @WebMethod. Here is a very simple example of what I want to be able to do:
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@WebService
public class EnumEndpoint {
@WebMethod
public boolean callEndpoint(
@XmlJavaTypeAdapter(CustomEnumAdapter.class) Day day) {
System.out.println(day.ordinal() + " " + day.name());
return false;
}
}
I was hoping by writing an XmlJavaTypeAdapter like so:
import java.lang.reflect.Type;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class CustomEnumAdapter extends XmlAdapter<CustomEnum, EnumBean>
implements Type {
@Override
public EnumBean unmarshal(CustomEnum v) throws Exception {
EnumBean mine = new EnumBean(v.ordinal(), v.name());
return mine;
}
@Override
public CustomEnum marshal(EnumBean v) throws Exception {
CustomEnum customEnum = new CustomEnum(v.getOrdinal(),v.getName());
return customEnum;
}
}
where EnumBean looks like:
public class EnumBean {
int ordinal;
String name;
public EnumBean(int ordinal, String name) {
this.ordinal = ordinal;
this.name = name;
}
public int getOrdinal() {
return ordinal;
}
public void setOrdinal(int ordinal) {
this.ordinal = ordinal;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
but when I declare a Server Endpoint like this:
import javax.xml.ws.Endpoint;
public class Server {
/**
* @param args
*/
public static void main(String[] args) {
Endpoint.publish("http://0.0.0.0:7979/enum", new EnumEndpoint());
}
}
I get this error:
Jun 10, 2012 3:29:21 PM com.sun.xml.internal.ws.model.RuntimeModeler getRequestWrapperClass
INFO: Dynamically creating request wrapper Class test.jaxws.CallEndpoint
Exception in thread "main" javax.xml.ws.WebServiceException: java.lang.IllegalArgumentException: value class test.CustomEnumAdapter
at com.sun.xml.internal.ws.model.WrapperBeanGenerator.createRequestWrapperBean(WrapperBeanGenerator.java:249)
at com.sun.xml.internal.ws.model.RuntimeModeler.getRequestWrapperClass(RuntimeModeler.java:280)
at com.sun.xml.internal.ws.model.RuntimeModeler.processDocWrappedMethod(RuntimeModeler.java:674)
at com.sun.xml.internal.ws.model.RuntimeModeler.processMethod(RuntimeModeler.java:612)
at com.sun.xml.internal.ws.model.RuntimeModeler.processClass(RuntimeModeler.java:401)
at com.sun.xml.internal.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:240)
at com.sun.xml.internal.ws.server.EndpointFactory.createSEIModel(EndpointFactory.java:312)
at com.sun.xml.internal.ws.server.EndpointFactory.createEndpoint(EndpointFactory.java:178)
at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:456)
at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:475)
at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.createEndpoint(EndpointImpl.java:213)
at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.publish(EndpointImpl.java:143)
at com.sun.xml.internal.ws.spi.ProviderImpl.createAndPublishEndpoint(ProviderImpl.java:102)
at javax.xml.ws.Endpoint.publish(Endpoint.java:170)
at test.Server.main(Server.java:11)
Caused by: java.lang.IllegalArgumentException: value class test.CustomEnumAdapter
at com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter.newConstItem(ClassWriter.java:893)
at com.sun.xml.internal.ws.org.objectweb.asm.AnnotationWriter.visit(AnnotationWriter.java:185)
at com.sun.xml.internal.ws.model.WrapperBeanGenerator.createBeanImage(WrapperBeanGenerator.java:111)
at com.sun.xml.internal.ws.model.WrapperBeanGenerator.createRequestWrapperBean(WrapperBeanGenerator.java:245)
... 14 more
What am I missing here? I tried to use ‘Day’ directly, but since it doesn’t have a default constructor and is not get/set friendly, that doesn’t work either. Any tips?
EnumBean
If
EnumBeanis the adapted class then it needs to have a default constructor.CustomEnumAdapter
Also the adapted class should appear as the first parameter when extending
XmlAdapter. Since the parameter you are mapping to is of typeDayyou are going to need to have theXmlAdapterspecifyDayas the bound type.TEST CLIENT
With the changes I suggested, I ran your service in WebLogic 12.1.1 and with the built in test client I got the following:
Service Request
Service Response