简体   繁体   English

@XmlAnyElement不会解组为特定的Java类型,而是在JAXBElement处停止

[英]@XmlAnyElement does not unmarshal into specific Java type, but stop at JAXBElement

To learn how to use @XmlAnyElement , I created the following test service: 为了学习如何使用@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 is a simple class with 2 int fields. SimpleObj是具有2个int字段的简单类。 Below is the code for the ServiceResult class: 下面是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
}

To consume the above service, I created an appclient with the following Main class: 为了使用上述服务,我使用以下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);
        }
    }
}

Based on the documentation, with @XmlAnyElement , the unmarshaller will eagerly unmarshal this element to a JAXB object. 根据文档,使用@XmlAnyElement ,解组器会急切将此元素解组到JAXB对象。 However, what I observed is that JAXB only parsed my object into JAXBElement instead of going all the way into SimpleObj . 但是,我观察到的是JAXB仅将我的对象解析为JAXBElement而不是完全解析为SimpleObj

I'd be extremely grateful if you could show me how I can get SimpleObj out of the ServiceResult . 如果您能向我展示如何从ServiceResult获取SimpleObj ,我将不胜感激。

UPDATE : 更新

Below is the SimpleObj class: 下面是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
}

I am unable to reproduce the issue that you are seeing. 我无法重现您看到的问题。 Below is some demo code that interacts directly with JAXB. 下面是一些直接与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());
        }
    }

}

The output from running the demo code shows that it is instances of SimpleObj in the field annotated with @XmlAnyElement(lax=true) . 运行演示代码的输出显示,它是在@XmlAnyElement(lax=true)注释的字段中的SimpleObj实例。

class forum27871349.SimpleObj
class forum27871349.SimpleObj

UPDATE #1 更新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. 在旁注中,我阅读了您在@XmlAnyElement上的博客文章,而且从未见过您必须在任何示例中都包含@XmlSeeAlso({SimpleObj.class})。

I'm not sure why I never leverage @XmlSeeAlso in my 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 如果您还可以告诉我是否有一种方法可以让消费者在不使用@XmlSeeAlso的情况下了解所有这些类,那就太好了

When you are creating the JAXBContext yourself, you simply need to include anything you would have referenced in an @XmlSeeAlso annotation as part of the classes you used to bootstrap the JAXBContext . 当您自己创建JAXBContext ,只需要包含您在@XmlSeeAlso批注中引用的所有内容, @XmlSeeAlso作为用来引导JAXBContext的类的一部分。

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

In a JAX-WS (or JAX-RS) setting where you don't have direct access to the JAXBContext I would recommend using the @XmlSeeAlso annotation like you have done. 在您没有直接访问JAXBContext的JAX-WS(或JAX-RS)设置中,我建议像您一样使用@XmlSeeAlso批注。


UPDATE #2 更新#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,我从文档中认为,如果解组器无法将元素解组到JAXB对象或JAXBElement对象中,则至少会得到一个DOM节点。

When you have a property mapped with @XmlAnyElement(lax=true) the following will happen: 当您使用@XmlAnyElement(lax=true)映射属性时,将发生以下情况:

  1. If the element corresponds to the @XmlRootElement of a class, then you will get an instance of that class. 如果该元素对应于类的@XmlRootElement ,则您将获得该类的实例。
  2. If the element corresponds to the @XmlElementDecl of a class on the ObjectFactory or another class annotated with @XmlRegistry then you will get an instance of that class wrapped in an instance of JAXBElement . 如果该元素对应于ObjectFactory上一个类的@XmlElementDecl或另一个带有@XmlRegistry注释的类,那么您将获得该类的实例,该实例包装在JAXBElement的实例中。
  3. If JAXB does not have an association between the element and a class, then it will convert it to a DOM Element . 如果JAXB在元素和类之间没有关联,则它将把它转换为DOM Element

I will demonstrate below with an example. 我将在下面举例说明。

ObjectFactory 的ObjectFactory

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);
    }

}

Demo 演示

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());
        }
    }

}

Output 产量

class forum27871349.SimpleObj
class com.sun.org.apache.xerces.internal.dom.ElementNSImpl
class javax.xml.bind.JAXBElement

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM