Java 使用 JaxB 编组实现公共接口的对象列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4144296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 12:03:30  来源:igfitidea点击:

Marshalling a List of objects implementing a common interface, with JaxB

javaxmljaxb

提问by Beni

I am trying to marshall a list of objects implementing a common interface. There are 3 classes and 1 interface involved:

我正在尝试编组实现通用接口的对象列表。涉及3个类和1个接口:

Communityclass (has one method: List<Person> getPeople();)

社区类(有一个方法:List<Person> getPeople();

Personinterface (has one method: String getName();)

Person接口(有一个方法:String getName();

Girlclass (implements Person)

Girl类(实现 Person)

Boyclass (implements Person)

男孩类(实现人)

See code below.

请参阅下面的代码。

I want an XML that looks something like this:

我想要一个看起来像这样的 XML:

<community>
  <people>
    <girl>
      <name>Jane</name>
    </girl>
    <boy>
      <name>John</name>
    </boy>
    <girl>
      <name>Jane</name>
    </girl>
    <boy>
      <name>John</name>
    </boy>
  </people>
</community>

or possibly:

或者可能:

<community>
  <people>
   <person>
      <girl>
        <name>Jane</name>
      </girl>
    </person>
    <person>
      <boy>
        <name>John</name>
      </boy>
    </person>
  </people>
</community>

So far what I get is this:

到目前为止,我得到的是:

<community>
    <people>
        <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="girl">
            <name>Jane</name>
        </person>
        <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="boy">
            <name>John</name>
        </person>
        <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="girl">
            <name>Jane</name>
        </person>
        <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="boy">
            <name>John</name>
        </person>
    </people>
</community>

I realize I can change the element to something else, but I want the element name to be the name spesified in the Girl or Boy class.

我意识到我可以将元素更改为其他内容,但我希望元素名称是在 Girl 或 Boy 类中指定的名称。

Can this be done? Thanks.

这能做到吗?谢谢。

@XmlRootElement(name = "community")
public class Community {

 private List<Person> people;

 @XmlElementWrapper
 @XmlElement(name="person")
 public List<Person> getPeople() {
  return people;
 }

 public Community() {
  people = new ArrayList<Person>();
  people.add(new Girl());
  people.add(new Boy());
  people.add(new Girl());
  people.add(new Boy());
 }
}







@XmlRootElement(name = "girl")
public class Girl implements Person {

 @XmlElement
 public String getName() {
  return "Jane";
 }
}


@XmlRootElement(name = "boy")
public class Boy implements Person {

 @XmlElement
 public String getName() {
  return "John";
 }
}



@XmlJavaTypeAdapter(AnyTypeAdapter.class)
public interface Person {
 public String getName();
}



public class AnyTypeAdapter extends XmlAdapter<Object, Object> {

 @Override
   public Object marshal(Object v) throws Exception {
    return v;
   }

 @Override
   public Object unmarshal(Object v) throws Exception {
    return v;
   }

}

采纳答案by bdoughan

For this scenario I would recommend the use of @XmlElements. @XmlElements is used to represent the XML schema concept of choice:

对于这种情况,我建议使用@XmlElements。@XmlElements 用于表示选择的 XML 模式概念:

Here is how it would look for your example:

以下是它如何查找您的示例:

@XmlElements({ 
    @XmlElement(name="girl", type=Girl.class),
    @XmlElement(name="boy", type=Boy.class)
})
@XmlElementWrapper
public List<Person> getPeople() {
    return people;
}

@XmlElementRef corresponds to the concept of substitution groups in XML schema. This is why the previous answer requires Person to be changed from an interface to a class.

@XmlElementRef 对应于 XML 模式中替换组的概念。这就是为什么之前的答案要求将 Person 从接口更改为类的原因。

回答by Gary Rowe

OK, if you're prepared to change Person from an interface into an abstract base class, then you're golden. Here's the code:

好的,如果您准备将 Person 从接口更改为抽象基类,那么您就是金子。这是代码:

public class Main {


  public static void main(String[] args) throws Exception {

    Community community = new Community();

    JAXBContext context = JAXBContext.newInstance(Community.class);
    Marshaller marshaller = context.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.marshal(community, System.out);

  }
}

@XmlRootElement(name = "community")
@XmlSeeAlso({Person.class})
public class Community {

 private List<Person> people;

 @XmlElementWrapper(name="people")
 @XmlElementRef()
 public List<Person> getPeople() {
  return people;
 }

 public Community() {
  people = new ArrayList<Person>();
  people.add(new Girl());
  people.add(new Boy());
  people.add(new Girl());
  people.add(new Boy());
 }
}

@XmlRootElement(name="boy")
public class Boy extends Person {

 public String getName() {
  return "John";
 }
}

@XmlRootElement(name="girl")
public class Girl extends Person {

 public String getName() {
  return "Jane";
 }
}

@XmlRootElement(name = "person")
@XmlSeeAlso({Girl.class,Boy.class})
public abstract class Person {

  @XmlElement(name="name")
 public abstract String getName();
}

The main trick was the use of @XmlElementRefin the List of Community. This identifies the type of the class through it's @XmlRootElement. You may also be interested in the @XmlSeeAlsowhich helps to organise context declarations.

主要技巧是在社区列表中使用@XmlElementRef。这通过它的@XmlRootElement 标识类的类型。您可能还对有助于组织上下文声明的@XmlSeeAlso感兴趣。

And the output is

输出是

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<community>
    <people>
        <girl>
            <name>Jane</name>
        </girl>
        <boy>
            <name>John</name>
        </boy>
        <girl>
            <name>Jane</name>
        </girl>
        <boy>
            <name>John</name>
        </boy>
    </people>
</community>