JAXB XmlJavaTypeAdapter is not called when Marshalling Object to Enum type
I am converting my web application to web servcies using CXF. My web application has classes build to work as enum. Example:
package test.javabean;
import java.util.HashMap;
import java.util.Map;
public class GlassType {
private static Map<String, GlassType> glasses = new HashMap<String, GlassType>();
private final String id;
private final String desc;
private GlassType(String id, String desc) {
this.id = id;
this.desc = desc;
glasses.put(id, this);
}
public static final GlassType RED = new GlassType("R", "Bloody Red");
public static final GlassType BLACK = new GlassType("B", "Pitch Black");
public static final GlassType WHITE = new GlassType("W", "Blind White");
public static GlassType valueOf(final String id) {
return glasses.get(id);
}
public String getDesc() {
return desc;
}
public String getId() {
return id;
}
}
As I don't want to change my GlasssType class to enum type, I made an adapter to make this class appear as enum in WSDL. Adapter Class:
package test.adapters;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import test.javabean.GlassType;
public class GlassTypeEnumAdapter extends XmlAdapter<GlassEnum, GlassType> {
@Override
public GlassEnum marshal(GlassType arg0) throws Exception {
System.out.println("MARSHALLING");
return GlassEnum.valueOf(arg0.getId());
}
@Override
public GlassType unmarshal(GlassEnum arg0) throws Exception {
System.out.println("UNMARSHALLING");
return GlassType.valueOf(arg0.getId());
}
}
The adapter is mapped with class GlassType using XmlJavaTypeAdapter mentioned in package-info.java:
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters( {
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(
value = test.adapters.GlassTypeEnumAdapter.class,
type = test.javabean.GlassType.class) })
package test.javabean;
The GlassEnum class:
package test.adapters;
import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlType;
@XmlEnum(String.class)
@XmlType(name = "myEnum")
public enum GlassEnum {
RED("R"), BLACK("B"), WHITE("W");
private final String id;
private GlassEnum(String id) {
this.id = id;
}
private GlassEnum() {
this.id = "RED";
}
public String getId() {
return id;
}
}
The WSDL generated with correct type ="myEnum" whereever I have used GlassType.
PROBLEM:
When my web service client send the value for GlassType, the adapter is called to Marshall myEnum to GlassType. BUT when my web service replies back to client with GlassType following error is thrown:
[3/20/11 20:43:48:078 CDT] 00000023 PhaseIntercep W org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging Interceptor for {http://webservices.test/}TestWebServiceImplService#{http://webservices.test/}getTestResult has thrown exception, unwinding now org.apache.cxf.interceptor.Fault: Marshalling Error: class test.javabean.GlassType nor any of its super class is known to this context. at org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:256) at org.apache.cxf.jaxb.io.DataWriterImpl.write(DataWriterImpl.java:169) at org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.writeParts(AbstractOutDatabindingInterceptor.java:110) at org.apache.cxf.interceptor.BareOutInterceptor.handleMessage(BareOutInterceptor.java:68) at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255) at org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:77) at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255) at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:113) at org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:97) at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:461) at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:188) at org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:148) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:179) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:103) at javax.servlet.http.HttpServlet.service(HttpServlet.java:763) at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:159) at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1143) at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:591) at com.ibm.ws.wswebcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:481) at com.ibm.ws.webcontainer.webapp.Web开发者_JS百科App.handleRequest(WebApp.java:3453) at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:267) at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:815) at com.ibm.ws.wswebcontainer.WebContainer.handleRequest(WebContainer.java:1466) at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:119) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:458) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:387) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:267) at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214) at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113) at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165) at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217) at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161) at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:136) at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:196) at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:751) at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:881) at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1473) Caused by: javax.xml.bind.MarshalException - with linked exception: [javax.xml.bind.JAXBException: class test.javabean.GlassType nor any of its super class is known to this context.] at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:318) at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244) at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:74) at org.apache.cxf.jaxb.JAXBEncoderDecoder.writeObject(JAXBEncoderDecoder.java:540) at org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:231) ... 36 more Caused by: javax.xml.bind.JAXBException: class test.javabean.GlassType nor any of its super class is known to this context. at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:246) at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:261) at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:653) at com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:115) at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:340) at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:696) at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:152) at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:340) at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:696) at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:152) at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:189) at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeBody(ElementBeanInfoImpl.java:316) at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:323) at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:72) at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:494) at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:315) ... 40 more Caused by: javax.xml.bind.JAXBException: class test.javabean.GlassType nor any of its super class is known to this context. at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:594) at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:648) ... 53 more
I have run several tests and noticed that Adapter class is not getting called for Unmarshalling GlassType. Am I missing something in here?
An alternate solution would also be helpful.
The page Standards for Annotating Services and Types with JAX-WS and JAXB says
The obvious choice here is an XML adapter. However, at the time of this writing JAXB does not appear to properly handle XML adapters that are used on enums (regardless of what you do, it still uses the xs:enumeration approach in the generated schema). So to get around this, we must treat these values as simple strings.
The page was created on 03-Mar-2011 and last updated 16-May-2011, so it seems using XmlJavaAdapter with enums in JAXB is still not working correctly.
精彩评论