2

フィールドにマークされたカスタム注釈に応じて、Java pojo の一部の要素をマーシャリング/アンマーシャリングする必要があります。私のJava pojpに3つのフィールドがあるとします

@CustomVersion("v1")
private String field1;
@CustomVersion("v1","v2")
private String field2;
@CustomVersion("v2")
private String field3;

jaxbでの変換時にversion="v1"パラメータを渡すと、v1のフィールドだけマーシャリングしたいです。v2 を渡すと、v2 アノテーションを持つすべてのフィールドのみがマーシャリングされます。

jaxbを使用しても可能ですか?選択的なマーシャリングは、いくつかのライブラリまたは方法でサポートされると確信していますが、かなりの検索を行ってもまだ理解できません。ヘルプ、アドバイス、ポインタは大歓迎です。

4

2 に答える 2

6

注: 私はEclipseLink JAXB (MOXy)のリーダーであり、JAXB (JSR-222)エキスパート グループのメンバーです。

以下は、MOXy の@XmlNamedObjectGraphs拡張機能を使用してユース ケースをマッピングする方法の例です。

Java モデル

フー

この@XmlNamedObjectGraphs拡張機能を使用すると、キーによって識別されるマッピングの複数のサブセットを指定できます。

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

import org.eclipse.persistence.oxm.annotations.XmlNamedAttributeNode;
import org.eclipse.persistence.oxm.annotations.XmlNamedObjectGraph;
import org.eclipse.persistence.oxm.annotations.XmlNamedObjectGraphs;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlNamedObjectGraphs({
    @XmlNamedObjectGraph(
        name="v1",
        attributeNodes = { 
            @XmlNamedAttributeNode("field1"),
            @XmlNamedAttributeNode("field2")}),
    @XmlNamedObjectGraph(
        name="v2",
        attributeNodes = { 
            @XmlNamedAttributeNode("field2"),
            @XmlNamedAttributeNode("field3")})
})
public class Foo {

    private String field1 = "ONE";
    private String field2 = "TWO";
    private String field3 = "THREE";

}

jaxb.properties

MOXy を JAXB プロバイダーとして使用するにはjaxb.properties、次のエントリで呼び出されるファイルを含める必要があります (参照: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html )。

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

デモコード

デモ

オブジェクト グラフに対応するキーを指定して、マーシャリングしているオブジェクトにそのサブセットを適用できます。

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import org.eclipse.persistence.jaxb.MarshallerProperties;

public class Demo {

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

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        Foo foo = new Foo();

        // Marshal Everything
        marshaller.marshal(foo, System.out);

        // Marshal "v1" Data
        marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "v1");
        marshaller.marshal(foo, System.out);

        // Marshal "v2" Data
        marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "v2");
        marshaller.marshal(foo, System.out);
    }

}

出力

<?xml version="1.0" encoding="UTF-8"?>
<foo>
   <field1>ONE</field1>
   <field2>TWO</field2>
   <field3>THREE</field3>
</foo>
<?xml version="1.0" encoding="UTF-8"?>
<foo>
   <field1>ONE</field1>
   <field2>TWO</field2>
</foo>
<?xml version="1.0" encoding="UTF-8"?>
<foo>
   <field2>TWO</field2>
   <field3>THREE</field3>
</foo>

詳細については

于 2013-10-22T18:55:33.190 に答える
3

まず第一に、マーシャリングの前にそのような前処理を行うことをお勧めします。それははるかに簡単です。ただし、何らかの理由でそれができない場合は、カスタム タイプ アダプターを作成できます。次に、@XmlJavaTypeAdapter(VersioningAdapter.class)バージョン管理を有効にしたいすべてのタイプを配置できます。 @XmlJavaTypeAdapterパッケージレベルで指定することもできますが、適用するタイプを指定する必要があります。XmlAdapterどこかを指定しないと使えません@XmlJavaTypeAdapter

このようなソリューションの欠点:

  • バージョン管理された型が複数ある場合は、それぞれに注釈を付ける必要があります@XmlJavaTypeAdapter
  • @XmlJavaTypeAdapterルート要素では機能せず、子要素でのみ機能します。マーシャリングする前に、ルート要素でアダプターを手動で呼び出す必要があります

私の知る限り、JAXBマーシャリングをカスタマイズするための他のオプションはありません。そのため、アノテーション処理はマーシャリングの前に別のステップで実行する必要があると思います。言及された制限を受け入れることができない限り。

サンプル アダプター (完全なコードはここにあります):

public class VersioningAdapter extends XmlAdapter<Object, Object> {

    @Override
    public Object unmarshal(Object v) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Object marshal(Object v) throws Exception {
        if (v == null) {
            return v;
        }
        Field[] fields = v.getClass().getDeclaredFields();
        for (Field field : fields) {
            Annotation[] annotations = field.getDeclaredAnnotations();
            CustomVersion annotation = findCustomVersion(annotations);
            if (annotation != null) {
                if (!contains(annotation, Configuration.getVersion())) {
                    field.setAccessible(true);
                    field.set(v, null);
                }
            }
        }
        return v;
    }

    private CustomVersion findCustomVersion(Annotation[] annotations) {
        for (Annotation annotation : annotations) {
            if (annotation instanceof CustomVersion) {
                return (CustomVersion) annotation;
            }
        }
        return null;
    }

    private boolean contains(CustomVersion annotation, String version) {
        String[] values = annotation.value();
        for (String value : values) {
            if (value.equals(version)) {
                return true;
            }
        }
        return false;
    }

}
于 2013-10-22T08:33:57.580 に答える