具有用户定义类型的 JAX-WS

JAX-WS with user-defined types

我正在尝试了解 JAX-WS,尤其是如何使用复杂类型。在我可以访问的所有关于 Java EE 的三本书中,他们都提到这是可能的,但没有给出任何例子......奇怪的是,在网络上搜索都没有找到完整的 - 包括服务和客户,但也许我就是找不到它。

这是服务 class:

package userobj;    
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.WebParam;

@WebService(serviceName = "UserObj")
public class UserObj 
{    
    @WebMethod(operationName = "sum")
    public int sum(@WebParam(name = "obj") Two obj) 
    {
        return obj.getA() + obj.getB();
    }
}

和class对应复杂类型 二:

package userobj;
public class Two 
{           
        private int a, b;
        public int getA() { return a; }
        public void setA(int newA) { a = newA; }
        public int getB() { return b; }
        public void setB(int newB) { b = newB; }
}

当我尝试在客户端 web 服务应用程序中使用它时,Glassfish4.1 自动从 WSDL 生成所有 classes,但是生成的 class 两个看起来像这样:

package uowsapp;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for two complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="two">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "two")
public class Two {


}

如果我手动将原始 class 二的内容插入到这个,那么应用程序将按预期工作:UserObjWSApp,但这可能不是预期的用例...因为 Clean&Build在此项目上重新生成 Two.java 并中断项目。有什么方法可以确保 Netbeans8.0.2 从它自己生成的 WSDL 中生成正确的复杂类型吗?

正如 maress 在他的回答中所建议的那样,两个 class 应该遵循 JAXB 的要求,但是,修改如下:

package userobj;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="Two")
public class Two 
{
        @XmlElement
        private int a;
        @XmlElement
        private int b;

        public int getA() { return a; }
        public void setA(int newA) { a = newA; }
        public int getB() { return b; }
        public void setB(int newB) { b = newB; }
}

在部署有服务的应用程序期间导致以下异常,部署失败:

com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Class has two properties of the same name "a"
    this problem is related to the following location:
        at public int userobj.Two.getA()
        at userobj.Two
        at public userobj.Two userobj.jaxws.Sum.obj
        at userobj.jaxws.Sum
    this problem is related to the following location:
        at private int userobj.Two.a
        at userobj.Two
        at public userobj.Two userobj.jaxws.Sum.obj
        at userobj.jaxws.Sum

b 属性 相同。然后,注释掉所有的 getter 和 setter 并使成员 public 以便可以直接访问它们会导致与以前相同的行为 - 生成的 class Two 没有成员。当我将 @XmlElement 注释移到 getA() 和 getB() 方法前面时,也会发生同样的情况:部署正常,WSDL 包含 a、b,但生成的两个不包含。请问还有什么可以尝试的想法吗?

jax-ws 在后台使用 jaxb 生成模式。

因此,您的 类 必须符合 jaxb 才能生成有效的复杂类型。

对于你们两个来说,很简单:

@XmlRootElement(name="Two")
public class Two {

  @XmlElement
  private int a;
  @XmlElement
  private int b;

  public int getA() {return a;}
  public void setA(int a) {this.a = a;}
  public int getB() {return b;}
  public void setB(int b) {this.b = b}
}

在您修改之后,您现在面临的问题与数据类型上的 @XmlAccessorType 注释(或缺少注释)有关。注释确定 JAXB 将如何访问,因此能够将字段映射到您定义的类型上。注释提供了四个选项,由 @XmlAccessType 注释定义:FIELDNONEPROPERTYPUBLIC_MEMBER.

默认值为 PUBLIC_MEMBER,这对 JAXB 意味着:映射所有非静态、非瞬态字段和所有 javabean 标准 属性 类型(即 getXXXsetXXX对)。因为您同时拥有 int a;getA(),这相当于拥有 2 个同名字段 - a.

您现在需要做的是定义一个 XmlAccessorType 来消除混淆:

@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlRootElement(name="Two")
public class Two {
//
}

我在这里选择 PROPERTY 是因为它更符合 Javabeans 约定,但它还具有其他优势,如 Blaise Doughan's blog post 中所述(假设这些并不真正适用于您的使用例)

代码正确,不需要注释@XMLRootElement,@XmlElement 也不需要。

NetBeans 没有生成正确的 class 字段和访问器的唯一原因是它使用的是 WSDL 的旧副本。我没有意识到 Clean&Build——即使它删除了旧生成的源代码并重新生成它——也没有下载当前版本的 WSDL。从我第一次尝试开始,它总是使用旧版本的 WSDL,其中不包括字段 ab。要重新下载 WSDL,请在项目浏览器中打开项目 - 打开 "Web Service References" 项并右键单击特定的 Web 服务引用(在本例中为 UserObj)并选择 Refresh... 并勾选 "also WSDL..."即将出现的对话框中的复选框

刷新WSDL后,原来没有JAXB注解的版本和有JAXB注解的版本都运行良好,生成了完整的class二:

package uowsapp;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for two complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="two">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="a" type="{http://www.w3.org/2001/XMLSchema}int"/>
 *         &lt;element name="b" type="{http://www.w3.org/2001/XMLSchema}int"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "two", propOrder = {
    "a",
    "b"
})
public class Two {

    protected int a;
    protected int b;

    /**
     * Gets the value of the a property.
     * 
     */
    public int getA() {
        return a;
    }

    /**
     * Sets the value of the a property.
     * 
     */
    public void setA(int value) {
        this.a = value;
    }

    /**
     * Gets the value of the b property.
     * 
     */
    public int getB() {
        return b;
    }

    /**
     * Sets the value of the b property.
     * 
     */
    public void setB(int value) {
        this.b = value;
    }

}