具有用户定义类型的 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>
* <complexType name="two">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* </sequence>
* </restriction>
* </complexContent>
* </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
注释定义:FIELD
、NONE
、PROPERTY
和 PUBLIC_MEMBER
.
默认值为 PUBLIC_MEMBER
,这对 JAXB 意味着:映射所有非静态、非瞬态字段和所有 javabean 标准 属性 类型(即 getXXX
和 setXXX
对)。因为您同时拥有 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,其中不包括字段 a 和 b。要重新下载 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>
* <complexType name="two">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="a" type="{http://www.w3.org/2001/XMLSchema}int"/>
* <element name="b" type="{http://www.w3.org/2001/XMLSchema}int"/>
* </sequence>
* </restriction>
* </complexContent>
* </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;
}
}
我正在尝试了解 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>
* <complexType name="two">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* </sequence>
* </restriction>
* </complexContent>
* </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
注释定义:FIELD
、NONE
、PROPERTY
和 PUBLIC_MEMBER
.
默认值为 PUBLIC_MEMBER
,这对 JAXB 意味着:映射所有非静态、非瞬态字段和所有 javabean 标准 属性 类型(即 getXXX
和 setXXX
对)。因为您同时拥有 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,其中不包括字段 a 和 b。要重新下载 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>
* <complexType name="two">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="a" type="{http://www.w3.org/2001/XMLSchema}int"/>
* <element name="b" type="{http://www.w3.org/2001/XMLSchema}int"/>
* </sequence>
* </restriction>
* </complexContent>
* </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;
}
}