1

为了学习如何使用@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;
    }
}

SimpleObjint是一个有 2 个字段的简单类。下面是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
}
4

1 回答 1

2

我无法重现您看到的问题。下面是一些直接与 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在我的例子中利用。

但是,在我的情况下,如果我没有这个,我会有错误说 Class *** 或者它的任何超类在这种情况下都是已知的。如果您还可以告诉我是否有一种方法可以让消费者知道所有这些类而不使用@XmlSeeAlso,那就太好了

当您JAXBContext自己创建时,您只需将您在@XmlSeeAlso注释中引用的任何内容作为您用来引导JAXBContext.

JAXBContext jc = JAXBContext.newInstance(ServiceResult.class, SimpleObj.class);

在您无法直接访问的 JAX-WS(或 JAX-RS)设置中,JAXBContext我建议@XmlSeeAlso您像您所做的那样使用注释。


更新#2

关于@XmlAnyElement,从文档中,我认为如果解组器无法将元素解组为 JAXB 对象或 JAXBElement 对象,我至少会得到一个 DOM 节点。

当您有一个属性映射时@XmlAnyElement(lax=true),将发生以下情况:

  1. 如果元素对应于@XmlRootElement类的,那么您将获得该类的实例。
  2. 如果该元素对应于或另一个类@XmlElementDecl上的类的ObjectFactory注释,@XmlRegistry那么您将获得该类的实例包装在 的实例中JAXBElement
  3. 如果 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
于 2015-01-14T10:49:41.777 回答