web-dev-qa-db-ja.com

JaxBを使用して、共通インターフェースを実装するオブジェクトのリストをマーシャリングする

共通インターフェースを実装するオブジェクトのリストをマーシャリングしようとしています。 3つのクラスと1つのインターフェイスが関係しています。

コミュニティクラス(1つのメソッドがあります:List <Person> getPeople();

Person interface(1つのメソッドがあります:String getName();

Girl class(実装Person)

Boy class(実装Person)

以下のコードを参照してください。

次のような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>

または場合によっては:

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

これまでのところ、私が得るのはこれです:

<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>

要素を別の要素に変更できることに気付きましたが、要素名はGirlクラスまたはBoyクラスで指定した名前にしたいです。

これはできますか?ありがとう。

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

}
36
Beni

このシナリオでは、@ XmlElementsの使用をお勧めします。 @XmlElementsは、選択のXMLスキーマの概念を表すために使用されます。

以下に例を示します。

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

@XmlElementRefは、XMLスキーマの置換グループの概念に対応しています。これが、前の回答でPersonをインターフェイスからクラスに変更する必要がある理由です。

45
bdoughan

わかりました。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();
}

主なトリックは、コミュニティのリストで @ XmlElementRef を使用することでした。これは、@ XmlRootElementを通じてクラスのタイプを識別します。また、コンテキスト宣言を整理するのに役立つ @ XmlSeeAlso に興味があるかもしれません。

そして、出力は

<?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>
12
Gary Rowe