首页 文章

JAX-WS,@ XMLJavaTypeAdapter和自定义枚举

提问于
浏览
4

我正在使用一个基于IDL定义生成代码的库 . 能够在各种语言(Java,C和C)中使用通用枚举非常棒,但这些生成的枚举似乎与JAX-WS不相符 .

基本上,主要枚举“超级”类有两个成员:序数和名称 . 它看起来与此类似(注意:这是在第三方库中,并且不是JavaBean友好的):

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

那么在生成的基于IDL定义的代码中看起来与此类似(使用Day作为示例 - 但实际上我有大约50个'枚举'来扩展CustomEnum,所以我想要一个让我无法使用多个枚举的副本,例如IDL生成的类型和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);
    }
}

请注意,我也不想乱用/重新排列/注释这个类,因为它是生成的代码 .

所以,现在我想做的是能够在JAX-WS @WebMethod中将这个'Day'枚举用作@WebParam . 这是我希望能够做的一个非常简单的例子:

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

    }

我希望通过编写一个像这样的XmlJavaTypeAdapter:

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

}

EnumBean的样子:

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

但是当我声明一个像这样的服务器 endpoints 时:

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

    }

}

我收到此错误:

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

我在这里错过了什么?我试图直接使用'Day',但由于它没有默认构造函数并且没有得到/设置友好,这也不起作用 . 有小费吗?

2 回答

  • 1

    EnumBean

    如果 EnumBean 是改编的类,那么它需要一个默认的构造函数 .

    package forum10972195;
    
    public class EnumBean {
    
        int ordinal;
        String name;
    
        public EnumBean() {
    
        }
    
        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;
        }
    }
    

    CustomEnumAdapter

    当扩展 XmlAdapter 时,改编的类应该作为第一个参数出现 . 由于您要映射的参数是 Day 类型,因此您需要将 XmlAdapter 指定为 Day 作为绑定类型 .

    package forum10972195;
    
    import javax.xml.bind.annotation.adapters.XmlAdapter;
    
    public class CustomEnumAdapter extends XmlAdapter<EnumBean, Day> {
    
        @Override
        public EnumBean marshal(Day v) throws Exception {
            EnumBean mine = new EnumBean(v.ordinal(), v.name());
            return mine;
        }
    
        @Override
        public Day unmarshal(EnumBean v) throws Exception {
            Day day = new Day(v.getOrdinal(),v.getName());
            return day;
        }
    
    }
    

    TEST CLIENT

    根据我建议的更改,我在WebLogic 12.1.1中运行了您的服务,并使用内置测试客户端,我得到了以下内容:

    Service Request

    <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
      <env:Header />
        <env:Body>
        <callEndpoint xmlns="http://forum10972195/">
          <!--Optional:-->
          <arg0 xmlns="">
            <!--Optional:-->
            <name>string</name>
            <ordinal>3</ordinal>
          </arg0>
        </callEndpoint>
      </env:Body>
    </env:Envelope>
    

    Service Response

    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
        <S:Body>
        <ns0:callEndpointResponse xmlns:ns0="http://forum10972195/">
          <return>false</return>
        </ns0:callEndpointResponse>
      </S:Body>
    </S:Envelope>
    
  • 4

    听起来因为webmethod参数上的@XmlJavaTypeAdapter注释在运行时失败 - 如何在请求包装器中包装请求参数 Day 以及包装器消息类型中的布尔响应,只需将其声明为 @XmlRootElement 并声明适配器 @XmlJavaTypeAdapter(CustomEnumAdapter.class) . 这样,您的@Webservice声明就没有@XmlJavaTypeAdapter注释 .

相关问题