@XmlAnyElement 不会解组为特定的 Java 类型,而是在 JAXBElement 处停止
@XmlAnyElement does not unmarshal into specific Java type, but stop at JAXBElement
为了学习如何使用 @XmlAnyElement
,我创建了以下测试服务:
@WebService(serviceName = "TestServices")
@Stateless()
public class TestServices {
@WebMethod(operationName = "testMethod")
public ServiceResult testMethod() {
ServiceResult result = new ServiceResult();
result.addObject(new SimpleObj(1, 2));
result.addObject(new SimpleObj(3, 4));
return result;
}
}
SimpleObj
是一个简单的 class,有 2 个 int
字段。下面是 ServiceResult
class:
的代码
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({SimpleObj.class})
public class ServiceResult {
@XmlAnyElement(lax = true)
private List<Object> body;
public void addObject(Object objToAdd) {
if (this.body == null)
this.body = new ArrayList();
this.body.add(objToAdd);
}
// Getters and Setters
}
为了使用上述服务,我创建了一个具有以下内容的 appclient Main
class:
public class Main {
@WebServiceRef(wsdlLocation = "META-INF/wsdl/localhost_8080/TestServices/TestServices.wsdl")
private static TestServices_Service service;
private static TestServices port;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
port = service.getAdminServicesPort();
ServiceResult result = port.testMethod();
for (Object o : result.getAny()) {
System.out.println("TEST: " + o);
}
}
}
根据文档,使用 @XmlAnyElement
,解组器将急切地将此元素解组为 JAXB 对象。但是,我观察到 JAXB 仅将我的对象解析为 JAXBElement
而不是一直解析为 SimpleObj
.
如果你能告诉我如何从 ServiceResult
中得到 SimpleObj
,我将不胜感激。
更新:
下面是SimpleObj
class:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class SimpleObj {
private int a;
private int b;
public SimpleObj() {}
public SimpleObj(int a, int b) {
this.a = a;
this.b = b;
}
// Getters and Setters
}
我无法重现您遇到的问题。下面是一些直接与 JAXB 交互的演示代码。
import java.io.*;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(ServiceResult.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader xml = new StringReader("<serviceResult><simpleObj/><simpleObj/></serviceResult>");
ServiceResult result = (ServiceResult) unmarshaller.unmarshal(xml);
for(Object item : result.getBody()) {
System.out.println(item.getClass());
}
}
}
运行 演示代码的输出显示它是 SimpleObj
在用 @XmlAnyElement(lax=true)
注释的字段中的实例。
class forum27871349.SimpleObj
class forum27871349.SimpleObj
更新 #1
On the side note, I've read your blog articles on @XmlAnyElement and
I've never seen you had to include @XmlSeeAlso({SimpleObj.class}) in
any of your examples.
我不确定为什么我从不在示例中使用 @XmlSeeAlso
。
However, in my case, if I don't have this, I would have the error
saying Class *** nor any of its super class is known to this context.
It'd be great if you could also show me if there is a way to make all
of these classes known to the consumer without using @XmlSeeAlso
当您自己创建 JAXBContext
时,您只需将您在 @XmlSeeAlso
注释中引用的任何内容包含在您曾经 [=] 的 classes 中74=] JAXBContext
.
JAXBContext jc = JAXBContext.newInstance(ServiceResult.class, SimpleObj.class);
在无法直接访问 JAXBContext
的 JAX-WS(或 JAX-RS)设置中,我建议像您一样使用 @XmlSeeAlso
注释。
更新#2
Regarding the @XmlAnyElement, from the documentation, I thought if the
unmarshaller cannot unmarshal elements into JAXB objects or
JAXBElement objects, I will at least get a DOM node.
当您将 属性 映射到 @XmlAnyElement(lax=true)
时,将发生以下情况:
- 如果该元素对应于 class 的
@XmlRootElement
,那么您将获得该 class 的实例。
- 如果元素对应于
ObjectFactory
上的 class 的 @XmlElementDecl
或另一个用 @XmlRegistry
注释的 class 那么你将得到一个实例其中 class 包裹在 JAXBElement
. 的实例中
- 如果 JAXB 没有元素与 class 之间的关联,那么它将把它转换为 DOM
Element
.
下面我会举例说明。
对象工厂
import javax.xml.namespace.QName;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
@XmlRegistry
public class ObjectFactory {
@XmlElementDecl(name="simpleObjJAXBElement")
public JAXBElement<SimpleObj> createSimpleObj(SimpleObj simpleObj) {
return new JAXBElement<SimpleObj>(new QName("simpleObjJAXBElement"), SimpleObj.class, simpleObj);
}
}
演示
import java.io.*;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(ServiceResult.class, ObjectFactory.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader xml = new StringReader("<serviceResult><simpleObj/><unmapped/><simpleObjJAXBElement/></serviceResult>");
ServiceResult result = (ServiceResult) unmarshaller.unmarshal(xml);
for(Object item : result.getBody()) {
System.out.println(item.getClass());
}
}
}
输出
class forum27871349.SimpleObj
class com.sun.org.apache.xerces.internal.dom.ElementNSImpl
class javax.xml.bind.JAXBElement
为了学习如何使用 @XmlAnyElement
,我创建了以下测试服务:
@WebService(serviceName = "TestServices")
@Stateless()
public class TestServices {
@WebMethod(operationName = "testMethod")
public ServiceResult testMethod() {
ServiceResult result = new ServiceResult();
result.addObject(new SimpleObj(1, 2));
result.addObject(new SimpleObj(3, 4));
return result;
}
}
SimpleObj
是一个简单的 class,有 2 个 int
字段。下面是 ServiceResult
class:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({SimpleObj.class})
public class ServiceResult {
@XmlAnyElement(lax = true)
private List<Object> body;
public void addObject(Object objToAdd) {
if (this.body == null)
this.body = new ArrayList();
this.body.add(objToAdd);
}
// Getters and Setters
}
为了使用上述服务,我创建了一个具有以下内容的 appclient Main
class:
public class Main {
@WebServiceRef(wsdlLocation = "META-INF/wsdl/localhost_8080/TestServices/TestServices.wsdl")
private static TestServices_Service service;
private static TestServices port;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
port = service.getAdminServicesPort();
ServiceResult result = port.testMethod();
for (Object o : result.getAny()) {
System.out.println("TEST: " + o);
}
}
}
根据文档,使用 @XmlAnyElement
,解组器将急切地将此元素解组为 JAXB 对象。但是,我观察到 JAXB 仅将我的对象解析为 JAXBElement
而不是一直解析为 SimpleObj
.
如果你能告诉我如何从 ServiceResult
中得到 SimpleObj
,我将不胜感激。
更新:
下面是SimpleObj
class:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class SimpleObj {
private int a;
private int b;
public SimpleObj() {}
public SimpleObj(int a, int b) {
this.a = a;
this.b = b;
}
// Getters and Setters
}
我无法重现您遇到的问题。下面是一些直接与 JAXB 交互的演示代码。
import java.io.*;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(ServiceResult.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader xml = new StringReader("<serviceResult><simpleObj/><simpleObj/></serviceResult>");
ServiceResult result = (ServiceResult) unmarshaller.unmarshal(xml);
for(Object item : result.getBody()) {
System.out.println(item.getClass());
}
}
}
运行 演示代码的输出显示它是 SimpleObj
在用 @XmlAnyElement(lax=true)
注释的字段中的实例。
class forum27871349.SimpleObj
class forum27871349.SimpleObj
更新 #1
On the side note, I've read your blog articles on @XmlAnyElement and I've never seen you had to include @XmlSeeAlso({SimpleObj.class}) in any of your examples.
我不确定为什么我从不在示例中使用 @XmlSeeAlso
。
However, in my case, if I don't have this, I would have the error saying Class *** nor any of its super class is known to this context. It'd be great if you could also show me if there is a way to make all of these classes known to the consumer without using @XmlSeeAlso
当您自己创建 JAXBContext
时,您只需将您在 @XmlSeeAlso
注释中引用的任何内容包含在您曾经 [=] 的 classes 中74=] JAXBContext
.
JAXBContext jc = JAXBContext.newInstance(ServiceResult.class, SimpleObj.class);
在无法直接访问 JAXBContext
的 JAX-WS(或 JAX-RS)设置中,我建议像您一样使用 @XmlSeeAlso
注释。
更新#2
Regarding the @XmlAnyElement, from the documentation, I thought if the unmarshaller cannot unmarshal elements into JAXB objects or JAXBElement objects, I will at least get a DOM node.
当您将 属性 映射到 @XmlAnyElement(lax=true)
时,将发生以下情况:
- 如果该元素对应于 class 的
@XmlRootElement
,那么您将获得该 class 的实例。 - 如果元素对应于
ObjectFactory
上的 class 的@XmlElementDecl
或另一个用@XmlRegistry
注释的 class 那么你将得到一个实例其中 class 包裹在JAXBElement
. 的实例中
- 如果 JAXB 没有元素与 class 之间的关联,那么它将把它转换为 DOM
Element
.
下面我会举例说明。
对象工厂
import javax.xml.namespace.QName;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
@XmlRegistry
public class ObjectFactory {
@XmlElementDecl(name="simpleObjJAXBElement")
public JAXBElement<SimpleObj> createSimpleObj(SimpleObj simpleObj) {
return new JAXBElement<SimpleObj>(new QName("simpleObjJAXBElement"), SimpleObj.class, simpleObj);
}
}
演示
import java.io.*;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(ServiceResult.class, ObjectFactory.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader xml = new StringReader("<serviceResult><simpleObj/><unmapped/><simpleObjJAXBElement/></serviceResult>");
ServiceResult result = (ServiceResult) unmarshaller.unmarshal(xml);
for(Object item : result.getBody()) {
System.out.println(item.getClass());
}
}
}
输出
class forum27871349.SimpleObj
class com.sun.org.apache.xerces.internal.dom.ElementNSImpl
class javax.xml.bind.JAXBElement