【问题标题】:JAX-WS with user-defined types具有用户定义类型的 JAX-WS
【发布时间】:2015-05-16 09:39:13
【问题描述】:

我正在尝试学习 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 {


}

如果我手动将原始类 Two 的内容插入到这个类中,那么应用程序将按预期工作:UserObjWSApp,但这可能不是预期的用例...因为此项目上的 Clean&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; }
}

在app with service on deploy时出现如下异常,部署失败:

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 没有成员。当我将 @XmlElement 注释移到 getA() 和 getB() 方法前面时也会发生同样的情况:部署正常,WSDL 包含 a、b,但生成的 Two 没有。有什么想法可以尝试吗?

【问题讨论】:

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


    【解决方案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}
    }
    

    【讨论】:

    • 非常感谢您的提示,我怀疑这样的事情,但它在部署期间导致异常 - 我已经编辑了上面的问题(根据建议...)
    【解决方案2】:

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

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

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

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

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

    【讨论】:

    • 非常感谢!现在我了解了如何使用 JAXB 注释来部署类。不过,我仍然无法生成正确的二类。看了NetBeans使用的WSDL的本地副本,不明白为什么和网上的不一样。事实证明,问题更简单 - 请参阅我的答案。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      • 2013-03-15
      • 2012-01-23
      • 1970-01-01
      • 2011-03-06
      • 1970-01-01
      • 2015-02-13
      相关资源
      最近更新 更多