4

モデル クラスには @XmlJavaTypeAdapter (クラス レベル) のアノテーションが付けられます。アンマーシャリングは、ルート要素とコンテインメント/ネストに対して正常に機能します (カスタム XmlAdapter で実装した内容に従って)。

これまでのところ、XML と JSON のシリアライゼーション/デシリアライゼーションの両方に満足していました。しかし、新たな必要性が生じ、それを実装する方法がわかりません。

特定の状況では、封じ込めのためにデフォルトの JAXB 動作に「戻す」ことができるようにしたいと考えています。クラスレベルの @XmlJavaTypeAdapter アノテーションを無視/オーバーライドしたいと考えています。

Blaise Doughan のブログ ( http://blog.bdoughan.com/ ) を読み、StackOverflow と Google を検索するのに何時間も費やしましたが、エレガントで実用的なソリューションが見つかりません。

以下は、現在持っているものを説明するための簡単なセットアップです (わかりやすくするために、すべての JPA/Hibernate/その他のアノテーションはリストされていませんが、モデル クラス (POJO) には存在することに注意してください)。

クラスマスター

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
@XmlJavaTypeAdapter(XmlMasterAdapter.class)
public class Master {
    @XmlElement
    private Long masterPrimaryKey;

    @XmlElement
    private String name;
}

クラス詳細

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
@XmlJavaTypeAdapter(XmlDetailAdapter.class)
public class Detail {
    @XmlElement
    private Long detailPrimaryKey;

    @XmlElement
    private Master master; // reference/foreign key. No need for @XmlJavaTypeAdapter since it's defined at the class-level in Master.

    @XmlElement
    private String value;
}

Master がルート要素として使用される場合、XML は次のようになります。

<master>
    <masterPrimaryKey>1234</masterPrimaryKey>
    <name>master name</name>
</master>

Master が含まれる/ネストされた要素として使用される場合、XML は次のようになります (カスタム XmlAdapter のおかげで、<master> 要素は主キーによって「要約」されます)。

<detail>
    <detailPrimaryKey>5678</detailPrimaryKey>
    <master>1234</master>
    <value>detail value</value>
</detail>

これまでのところ、すべてがうまく機能しており、満足しています。

さて、私たちの新しい必要性:

特定の状況では、封じ込めが別の方法で機能することを望みます。マスターのクラスレベルの @XmlJavaTypeAdapter を、特定のコンテキストで「一時的に」無視/元に戻し/オーバーライドしたい。デフォルトの JAXB unmarshaller が起動することを期待します (含まれているクラスにクラスレベルの @XmlJavaTypeAdapter がなかったかのように)。

マスターとすべての詳細を 1 つのペイロードで受け取るデータ インポートの状況について考えてみましょう。あたかも大きな DTO/トランスポート コンテナーにラップされたすべての独立したルート要素であるかのように。

以下は、必要なものを表す XML です。

<masterDetailImport>
    <master>
        <!-- Primary keys omitted because of the import mode -->
        <name>master name</name>
    </master>

    <details>
        <detail>
            <value>detail 1 value</value>
        </detail>

        <detail>
            <value>detail 2 value</value>
        </detail>

        <detail>
            <value>detail 3 value</value>
        </detail>
    </details>
</masterDetailImport>

クラス MasterDetailImport

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class MasterDetailImport implements Serializable 
{
    @XmlElement
    @PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT
    private Master master;

    @XmlElementWrapper(name="details")
    @XmlElement
    @PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT
    private List<Detail> detail = new ArrayList<Detail>();
}

私が探しているのは、魔法の [まだ存在しない] @PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT アノテーションです。これにより、ネストされたクラスのクラスレベルで @XmlJavaTypeAdapter が定義されていないかのように JAXB に指示することができます。

これまでのところ、私たちが想定している [そして気に入らない] ソリューションは次のとおりです。

  1. インポートをサポートする必要がある場合にのみ、デシリアライゼーション用の「ミラー」DTO オブジェクトを作成します。このアプローチには多くの短所があります (デシリアライゼーションにのみ使用されるコードの重複、DTO コンテンツをモデル クラスにコピーするためのアダプター、作成/維持する単体テストの増加など)。

  2. インポート/ネストできるようにしたいすべてのエンティティでクラスレベルの @XmlJavaTypeAdapter を取り除き、ネスティング/コンテインメントが使用されているすべての属性で @XmlJavaTypeAdapter を明示的に使用します。私はこのアプローチをテストし、それがうまくいくことを知っています。ただし、エラーが発生しやすく、クラスレベルで定義するほどエレガントではなく、クラスで @XmlJavaTypeAdapter が定義されていることを知らなかったかのように一時的に動作するように JAXB に指示する例外/特別なケース/オーバーライド処理を持つことができると思います.

ここでアイデアが不足しています... JAXBのデフォルトのXMLアダプターを探してみましたが、成功しませんでした: javax.xml.bind.annotation.adapters.XmlAdapter<ValueType,BoundType> is abstract and inherits from Java.lang.Object .

さて、簡単な質問: @PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT を実装する方法は?

前もって感謝します !

4

1 に答える 1