4

我目前在我的项目中有这个环境:

public abstract class Foo {

   private List<Thing> things;

   public List<Thing> getThings() { return this.things; }
}

public abstract class Bar extends Foo {


   @XmlElements({@XmlElement(name = "first", type = First.class)})
   public List<Thing> getThings() { return super.getThings(); }

}

public class Bobar extends Bar {

   @XmlElements({@XmlElement(name = "second", type = Second.class)})
   public List<Thing> getThings() { return super.getThings(); }

}

对于以下 XML 文档

<bobar>
   <first>blablabla</first>
   <second>blublublu</second>
</bobar>

当我做

context = JAXBContext.newInstance("the.package.structure");
unmarshaller = context.createUnmarshaller();
Bar object = (Bar) unmarshaller.unmarshal("path-to-xml-document");

Barobject在集合中只有一个元素,而不是 2。该First元素完全丢失,当我尝试这样做时object.getThings(),它的大小为 1,集合中唯一的对象是Second. 有人可以帮助我如何获得集合中的两个对象吗?如果那不可能,我怎样才能实现类似的目标?

我这样做的原因是(在我的项目逻辑中)每个Bobars things 集合First在它的集合中都有一个,但不是每个在它的集合中Bar都有一个Second,并且Foo是一个泛型类。

编辑:

当我更改 XML 文档中的顺序时,输出会有所不同。

<bobar>
   <second>blablabla</second>
   <first>blublublu</first>
</bobar>

在这种情况下,我只得到First集合中的一个实例,并且Second丢失了。并且更多地改变场景,我得到了有趣的结果:

public abstract class Foo {

   private List<Thing> things;

   public List<Thing> getThings() { return this.things; }
}

public abstract class Bar extends Foo {


   @XmlElements({@XmlElement(name = "first", type = First.class), @XmlElement(name = "third, type = Third.class)})
   public List<Thing> getThings() { return super.getThings(); }

}

public class Bobar extends Bar {

   @XmlElements({@XmlElement(name = "second", type = Second.class)})
   public List<Thing> getThings() { return super.getThings(); }

}

如果我做

<bobar>
   <third>bliblibli</third>
   <second>blablabla</second>
   <first>blublublu</first>
</bobar>

理论上,我认为这不应该针对由此生成的 XML Schema 进行验证,因为这里的顺序不正确。但除此之外,在这种情况下,我得到Secondand FirstThird丢失了。

4

2 回答 2

5

不可能在超类型上注释属性,并让子尝试逐步添加到该映射中。以下是一种支持您所追求的所有用例的方法。需要注意的一点是对象层次结构中的所有级别都将支持同一组元素。您需要使用外部验证方法来限制所需的值。

如果Thing是类而不是接口,First并且Second扩展,Thing那么您可能有兴趣使用@XmlElementRef而不是@XmlElements(请参阅:http ://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html )。它将为您提供更大的灵活性,但代价是一些验证(难以限制有效值的集合)。

酒吧

我们将注释Bar@XmlTransient使 JAXB 实现不处理它。

package forum11698160;

import java.util.List;

import javax.xml.bind.annotation.XmlTransient;

@XmlTransient
public abstract class Bar extends Foo {

    public List<Thing> getThings() {
        return super.getThings();
    }

}

波巴尔

@XmlElementRef对应于 XML 模式中的替换组的概念。与属性匹配的值将基于@XmlRootElement声明。

package forum11698160;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Bobar extends Bar {

    @XmlElementRef
    public List<Thing> getThings() {
        return super.getThings();
    }

}

事物

由于 JAXB 实现不能使用反射来找到一个类型的所有子类,我们可以使用@XmlSeeAlso注解来帮助解决。如果您不使用此注解,那么在引导JAXBContext.

package forum11698160;

import javax.xml.bind.annotation.XmlSeeAlso;

@XmlSeeAlso({First.class, Second.class})
public class Thing {

}

第一的

我们需要First注释 @XmlRootElement

package forum11698160;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class First extends Thing {

}

第二

Second还需要注释@XmlRootElement

package forum11698160;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Second extends Thing {

}

演示

package forum11698160;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Bobar.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum11698160/input.xml");
        Bobar bobar =  (Bobar) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(bobar, System.out);
    }

}

输入.xml/输出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bobar>
    <first/>
    <second/>
</bobar>

其他文件

以下是运行此示例所需的其他文件:

package forum11698160;

import java.util.*;

public abstract class Foo {

    private List<Thing> things = new ArrayList<Thing>();

    public List<Thing> getThings() {
        return this.things;
    }

}
于 2012-08-03T17:29:16.677 回答
2

以下是您如何通过利用来映射此用例@XmlTransient

波巴尔

您不能在子类中扩展映射,因此您需要确保在进行@XmlElements映射时您会做所有事情(请参阅: http ://blog.bdoughan.com/2010/10/jaxb-and-xsd-choice-xmlelements .html)。

package forum11698160;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Bobar extends Bar {

    @XmlElements({ 
        @XmlElement(name = "first", type = First.class),
        @XmlElement(name = "second", type = Second.class)
    })
    public List<Thing> getThings() {
        return super.getThings();
    }

}

酒吧

您也不能覆盖继承的属性。所以我们需要@XmlTransient在类型级别使用来表明我们不希望我们的 JAXB 实现处理超类型(参见:http ://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient .html)。

package forum11698160;

import java.util.List;

import javax.xml.bind.annotation.*;

@XmlTransient
public abstract class Bar extends Foo {

    public List<Thing> getThings() {
        return super.getThings();
    }

}

演示

以下演示代码可用于演示一切正常:

package forum11698160;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Bobar.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum11698160/input.xml");
        Bobar bobar =  (Bobar) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(bobar, System.out);
    }

}

输入.xml/输出

<?xml version="1.0" encoding="UTF-8"?>
<bobar>
   <first/>
   <second/>
</bobar>

其他文件

以下是运行此示例所需的其他文件:

package forum11698160;

import java.util.*;

public abstract class Foo {

    private List<Thing> things = new ArrayList<Thing>();

    public List<Thing> getThings() {
        return this.things;
    }

}

事物

package forum11698160;

public interface Thing {

}

第一的

package forum11698160;

public class First implements Thing {

}

第二

package forum11698160;

public class Second implements Thing {

}
于 2012-08-03T16:23:13.830 回答