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

时间:2015-05-16 09:39:14

标签: web-services jaxb jax-ws java-ee-7

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

这是服务类:

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

和相应复杂类型的类二:

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中的所有类,但生成的 第二类看起来像这样:

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 {


}

如果我手动将原始类2的内容插入此项,那么应用程序按预期工作:UserObjWSApp,但这可能不是用例...因为此项目上的Clean&amp; Build重新生成Two.java并打破了项目。有没有什么方法可以确保Netbeans8.0.2能够从它自己生成的WSDL生成一个合适的复杂类型?

正如maress在他的回答中所建议的那样,Two类应该遵循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并使成员公开以便可以直接访问它们导致与之前相同的行为 - 生成的类Two没有成员。当我在getA()和getB()方法前面移动@XmlElement注释时也会发生同样的情况:部署ok,WSDL包含a,b,但生成的则没有。有什么想法可以试试吗?

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

修改后,您现在面临的问题与数据类型的@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中所述(授予这些优点并不适用于您的用例)

答案 2 :(得分:0)

代码是正确的,注释@XMLRootElement不是必需的,也不是@XmlElement注释。

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

通过刷新WSDL,没有JAXB注释的原始版本和带有JAXB注释的版本都运行良好,并生成了完整的类二:

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

}