为了学习如何使用@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
是带有2个int
字段的简单类。下面是ServiceResult
类的代码:@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
}
为了使用上述服务,我使用以下
Main
类创建了一个appclient: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
。如果您能告诉我如何从
SimpleObj
中获取ServiceResult
,我将不胜感激。更新:
下面是
SimpleObj
类:@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
在旁注中,我阅读了您在@XmlAnyElement和
我从未见过您必须在其中包含@XmlSeeAlso({SimpleObj.class})
您的任何示例。
我不确定为什么我在示例中从未使用
@XmlSeeAlso
。但是,就我而言,如果我没有这个,我会遇到错误
说***类或它的任何超类在这种情况下是已知的。
如果您还可以告诉我是否有办法让所有人
消费者不使用@XmlSeeAlso的这些类中的
自己创建
JAXBContext
时,只需要包含您在@XmlSeeAlso
批注中引用的所有内容,即可作为用来引导JAXBContext
的类的一部分。JAXBContext jc = JAXBContext.newInstance(ServiceResult.class, SimpleObj.class);
在您没有直接访问
JAXBContext
的JAX-WS(或JAX-RS)设置中,我建议像您一样使用@XmlSeeAlso
批注。更新#2
关于@XmlAnyElement,从文档中,我认为
解组器无法将元素解组到JAXB对象或
JAXBElement对象,我至少会得到一个DOM节点。
当您使用
@XmlAnyElement(lax=true)
映射属性时,将发生以下情况:如果元素对应于类的
@XmlRootElement
,则您将获得该类的实例。如果该元素对应于
@XmlElementDecl
上某个类的ObjectFactory
或带有@XmlRegistry
注释的另一个类,则您将获得该类的实例,该实例包装在JAXBElement
的实例中。如果JAXB在元素和类之间没有关联,则它将把它转换为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