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 ではなく 1 つの要素しかありません。First要素は完全に失われます。実行しようとするとobject.getThings()、そのサイズは 1 で、コレクション内の唯一のオブジェクトは のインスタンスですSecond。コレクション内の両方のオブジェクトを取得するにはどうすればよいですか? それが不可能な場合、どうすればこれに似たものを達成できますか?

私がこれを行っている理由は、(私のプロジェクト ロジックでは) すべてBobarの s のコレクションがFirstそのコレクションに を持っていますが、すべてBarSecondそのコレクションに を持っているわけではなく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 スキーマに対してこれを検証するべきではないと思います。しかし、それ以外にも、そのようなシナリオでは、Secondとが失われます。FirstThird

4

2 に答える 2

5

スーパー タイプのプロパティに注釈を付けて、そのマッピングにサブを段階的に追加することはできません。以下は、あなたが求めているすべてのユースケースをサポートできる方法です。注意すべきことの 1 つは、オブジェクト階層のすべてのレベルが同じ要素セットをサポートすることです。目的の値を制限するには、外部の検証手段を使用する必要があります。

Thingクラスがインターフェースではなく、拡張されている場合は、First代わりSecondに使用するThingことに興味があるかもしれません( http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.htmlを参照)。いくつかの検証を犠牲にして、より高い柔軟性を提供します (有効な値のセットを制限するのは困難です)。@XmlElementRef@XmlElements

バー

JAXB 実装が処理しないように、 Barwithに注釈を付けます。@XmlTransient

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

}

ボバー

@XmlElementRefXML スキーマの置換グループの概念に対応します。@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 {

}

2番

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

}

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

}

input.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 {

}

2番

package forum11698160;

public class Second implements Thing {

}
于 2012-08-03T16:23:13.830 に答える