将对象编组为枚举类型时不调用 JAXB XmlJavaTypeAdapter

Posted

技术标签:

【中文标题】将对象编组为枚举类型时不调用 JAXB XmlJavaTypeAdapter【英文标题】:JAXB XmlJavaTypeAdapter is not called when Marshalling Object to Enum type 【发布时间】:2011-07-19 09:18:51 【问题描述】:

我正在使用 CXF 将我的 Web 应用程序转换为 Web 服务。我的 Web 应用程序具有构建为枚举的类。示例:

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;


由于我不想将 GlasssType 类更改为枚举类型,因此我制作了一个适配器以使此类在 WSDL 中显示为枚举。适配器类:

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



使用 package-info.java 中提到的 XmlJavaTypeAdapter 将适配器映射到 GlassType 类:

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

GlassEnum 类:

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;


无论我在哪里使用 GlassType,都会以正确的类型 ="myEnum" 生成 WSDL。

问题:

当我的 Web 服务客户端发送 GlassType 的值时,适配器将调用 Marshall myEnum 到 GlassType。但是当我的 Web 服务使用 GlassType 回复客户端时,会引发以下错误:

[3/20/11 20:43:48:078 CDT] 00000023 PhaseIntercep W org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging 拦截器用于 http://webservices.test/TestWebServiceImplService#http:// webservices.test/getTestResult 已抛出异常,现在展开 org.apache.cxf.interceptor.Fault: Marshalling Error: class test.javabean.GlassType 或其任何超类在此上下文中是已知的。 在 org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:256) 在 org.apache.cxf.jaxb.io.DataWriterImpl.write(DataWriterImpl.java:169) 在 org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.writeParts(AbstractOutDatabindingInterceptor.java:110) 在 org.apache.cxf.interceptor.BareOutInterceptor.handleMessage(BareOutInterceptor.java:68) 在 org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255) 在 org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:77) 在 org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255) 在 org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:113) 在 org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:97) 在 org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:461) 在 org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:188) 在 org.apache.cxf.transport.servlet.AbstractCXFServlet.invoke(AbstractCXFServlet.java:148) 在 org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:179) 在 org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:103) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:763) 在 org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:159) 在 com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1143) 在 com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:591) 在 com.ibm.ws.wswebcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:481) 在 com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3453) 在 com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:267) 在 com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:815) 在 com.ibm.ws.wswebcontainer.WebContainer.handleRequest(WebContainer.java:1466) 在 com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:119) 在 com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:458) 在 com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:387) 在 com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:267) 在 com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214) 在 com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113) 在 com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165) 在 com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217) 在 com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161) 在 com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:136) 在 com.ibm.io.async.ResultHandler.complete(ResultHandler.java:196) 在 com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:751) 在 com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:881) 在 com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1473) 引起:javax.xml.bind.MarshalException - 有关联的例外: [javax.xml.bind.JAXBException: 类 test.javabean.GlassType 或其任何超类在此上下文中都是已知的。] 在 com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:318) 在 com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244) 在 javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:74) 在 org.apache.cxf.jaxb.JAXBEncoderDecoder.writeObject(JAXBEncoderDecoder.java:540) 在 org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:231) ... 36 更多 由:javax.xml.bind.JAXBException:类 test.javabean.GlassType 或其任何超类在此上下文中是已知的。 在 com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:246) 在 com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:261) 在 com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:653) 在 com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:115) 在 com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:340) 在 com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:696) 在 com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:152) 在 com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:340) 在 com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:696) 在 com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:152) 在 com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:189) 在 com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeBody(ElementBeanInfoImpl.java:316) 在 com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:323) 在 com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:72) 在 com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:494) 在 com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:315) ... 40 更多 由:javax.xml.bind.JAXBException:类 test.javabean.GlassType 或其任何超类在此上下文中是已知的。 在 com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:594) 在 com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:648) ... 53 更多

我已经运行了几个测试并注意到适配器类没有被调用 Unmarshalling GlassType。我在这里遗漏了什么吗?

另一种解决方案也会有所帮助。

【问题讨论】:

您的服务是 JAX-WS 服务吗? 您是否尝试过使用@XmlJavaTypeAdapter 作为GlassType 类型参数的参数级别注释? 是的,我做到了。它仍然抛出相同的错误。我还尝试了其他几种组合,例如 Class-to-String adapter Enum-to-String adapter 。一切正常。适配器方法 marshall & unmarshall 每次都被调用。但同样的事情不适用于这种 Class-to-Enum Adapter 的组合。 【参考方案1】:

页面Standards for Annotating Services and Types with JAX-WS and JAXB说

这里明显的选择是 XML 适配器。然而,就在此时 编写 JAXB 似乎没有 正确处理 XML 适配器 用于枚举(不管你是什么 做,它仍然使用 xs:enumeration 生成的模式中的方法)。所以 为了解决这个问题,我们必须对待 这些值作为简单的字符串。

该页面创建于 2011 年 3 月 3 日,最后更新于 2011 年 5 月 16 日,因此在 JAXB 中使用带有枚举的 XmlJavaAdapter 似乎仍然无法正常工作。

【讨论】:

以上是关于将对象编组为枚举类型时不调用 JAXB XmlJavaTypeAdapter的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JAXB2 用动态元素编组 XML

JAXB:如何编组列表中的对象?

编组时出现 JAXB 错误

Jaxb编组原始类型

如何将 JAXB 对象编组到 org.w3c.dom.Document?

带有 java.lang.Object 字段的 JAXB 编组对象