1

我有一种情况,Java 对象包含Payload<T>需要编组为 xml 的泛型。所以给定以下类:

抽象框

@XmlTransient
public abstract class AbstractBox {
    String type = this.getClass().getSimpleName();
    String name = this.getClass().getCanonicalName();

    // setters/getters snipped

    public abstract String saySomething();
}

小盒子

@XmlRootElement(name="small-box")
@XmlType(name="small-box")
public class SmallBox extends AbstractBox {

    @XmlElement
    public String getMsg() {
        return saySomething();
    }
    public void setMsg(String msg) {
        // do nothing
    }

    @Override
    public String saySomething() {
        return "I'm a small box";
    }
}

有效载荷

@XmlTransient
public class Payload<T> {
    private T payload;

    public T getPayload() {
        return payload;
    }

    public void setPayload(T payload) {
        this.payload = payload;
    }
}

和一些这样的代码:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class JaxbAnnotationsTest<P>
{
    String name;
    int age;
    int id;
    Payload<P> payload;

    // setters and getters snipped

    public static void main(String[] args) {
        JaxbAnnotationsTest<AbstractBox> example = new JaxbAnnotationsTest<AbstractBox>();
        example.setName("Brion");
        example.setId(100);
        example.setAge(34);
        Payload<AbstractBox> object = new Payload<AbstractBox>();
        object.setPayload(new SmallBox());
        example.setPayloadContainer(object);

        try {
            XmlMapper xmapper = new XmlMapper();
            xmapper.writeValue(System.out, example);
        } catch (Exception ex) {
            System.err.println("Damn..." + ex.getMessage());
        }
    }

我希望看到:

<JaxbAnnotationsTest>
  <name>Brion</name>
  <age>34</age>
  <id>100</id>
  <payloadContainer>
    <small-box>
      <type>SmallBox</type>
      <name>sandbox.xml.jaxb.annotations.SmallBox</name>
      <msg>I'm a small box</msg>
    </small-box>
  </payloadContainer>
</JaxbAnnotationsTest>

但相反,我得到:

<JaxbAnnotationsTest>
  <name>Brion</name>
  <age>34</age>
  <id>100</id>
  <payloadContainer>
    <payload>
      <type>SmallBox</type>
      <name>sandbox.xml.jaxb.annotations.SmallBox</name>
      <msg>I'm a small box</msg>
    </payload>
  </payloadContainer>
</JaxbAnnotationsTest>

我尝试@XmlType在具体子类上使用来更改payload为,small-box但这也不起作用。如果我删除该Payload<P>对象并仅拥有一个 payload泛型类型 P 的类成员,则该paymentContainer标记将消失,但payload仍保留并且不使用small-box我指定的名称。

有没有办法让我强制 JAXB(任何实现)将标签设置为子类中指定的名称而不是泛型类型属性?

更新: 所选答案提供了解决方案,但我也想跟进问题。我的问题有两个:

  1. @XmlTransientPayload<T>类上使用并且需要在方法上使用@XmlAnyElement注释setPayload(T payload)(尽管我怀疑 setter/getter 对的哪个方法被注释并不重要,只要只有一个具有注释)。
  2. 我使用的是 Jackson 2 JacksonJaxbXmlProvider,它是一个不完整的 JAXB 实现,它忽略了@XmlRootElement用作@XmlAnyElement-annotated 属性值的元素。

将我的 JAXB 提供程序更改为使用 Java 6/7 内置 JAXB 提供程序会生成我预期的输出。

4

1 回答 1

2

您的Payload类需要任何 bean 类型作为属性,因此 JAXB 不知道如何编组该特定对象(在本例中SmallBox)。由于您需要在 Payload 中保留通用属性,因此解决方案应该是

  1. 删除@XmlTransient注释以使这些类型可用于编组(我想知道它如何与您提到的此注释一起使用)
  2. setPayloadPayload课堂上注释@XmlAnyElement如下

公共类有效载荷 { 私有 T 有效载荷;

public T getPayload() {
    return payload;
}

@XmlAnyElement
public void setPayload(T payload) {
    this.payload = payload;
}

}

@XmlAnyElementjavadoc 说

将 JavaBean 属性映射到 XML 信息集表示和/或 JAXB 元素。

@XmlRootElement这意味着传入() 的任何已知 bean 类型(用 注释setPayload)都将由 JAXB 解析为它们对应的类型,这里 bean 是SmallBox,否则为默认元素类型(我认为它应该是 的默认实现org.w3c.dom.Element)。在此更改之后,它将JaxbAnnotationsTest很好地编组到以下 xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxbAnnotationsTest>
    <age>34</age>
    <id>100</id>
    <name>Brion</name>
    <payloadContainer>
        <small-box>
            <name>org.mycode.SmallBox</name>
            <type>SmallBox</type>
            <msg>I'm a small box</msg>
        </small-box>
    </payloadContainer>
</jaxbAnnotationsTest>

希望对您有所帮助。

于 2013-05-10T23:50:10.607 回答