1

マップとリストの値として、プリミティブ、マップ、およびリストの混合値を許可する JAX-RS サービスを作成しようとしています。ドメイン モデルのすべての属性を明確に定義することはできません。データは、いくつかの属性が存在し、他の属性が存在しない異なるシステムから取得されるためです。このサービスは、XML と JSON の両方をサポートする必要があります。JSON 構造は、ラッパー クラスによる要素の追加のネストなしで、以下にリストされているように類似している必要があります。XML 構造はまだ設定されておらず、順応性があります。

私はこれまで Resteasy と Jackson を使用してきましたが、ベンダー固有の注釈を避けてきましたが、これは避けられない可能性があることを認識しています。これらのサービス API は固定化されていません。この目標を達成できる他の提案を歓迎します。1 つの要件は、これが標準の REST サービスであることです。

記事を表すオブジェクトの例:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class Article {

    @XmlElement
    private String title;

    @XmlElement
    private String creator;

    @XmlElement
    private Map<String, Object> attributes;

    public Map<String, Object> getAttributes() {
        return attributes;
    }

    public void setAttributes(Map<String, Object> attributes) {
        this.attributes = attributes;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

このオブジェクトを考えると、JSON は次のようになると思います。

{
    "title": "Some Title",
    "attributes":
    {
        "relevance": 0.93,
        "rating": 4,
    },
    "actions":
    [
        "A",
        "C"
    ]
}

XML は次のようになります。

<article>
    <title>Some Title</title>
    <attributes>
        <entry>
            <key>relevance</key>
            <value xsi:type="xs:double">0.93</value>
        </entry>
        <entry>
            <key>rating</key>
            <value xsi:type="xs:int">4</value>
        </entry>
        <entry>
            <key>actions</key>
            <value>
                <list xsi:type="xs:string">A</list>
                <list xsi:type="xs:string">C</list>
          </value>
        </entry>
    </attributes>
</article>

私が遭遇した問題は、マップの値が標準の ArrayList である場合、JSON 処理は正常に機能しますが、XML には配列の内容に関する情報が含まれていないことです。XML は次のようになります。

<article>
    <title>Some Title</title>
    <attributes>
        <entry>
            <key>relevance</key>
            <value xsi:type="xs:double">0.93</value>
        </entry>
        <entry>
            <key>rating</key>
            <value xsi:type="xs:int">4</value>
        </entry>
        <entry>
            <key>actions</key>
            <value>
   ----->     <arraylist/>
          </value>
        </entry>
    </attributes>
</article>

マップの値をリストの内容を表示するには、リストを JAXB アノテーションを持つオブジェクトでラップする必要があります。ただし、そうすると、属性にアクセスするときに JSON に別のレベルが追加されますが、これは望ましくありません。入れ子になったオブジェクトのラップを解除するために XmlAdaptor が使用されている場合、XML は再び値を返します。

理想的には、JAXB アノテーションを持つオブジェクト ラッパーのみを追加できるように、マップとリストを厳密に型指定する必要があります。

以下の階層のようなもの:

ルートクラス

@XmlAccessorType(XmlAccessType.NONE)
@XmlSeeAlso({JaxbList.class, JaxbMap.class, JaxbString.class})
abstract public class JaxbObject<E> {

    @XmlElement
    abstract public E getValue();
    abstract public void setValue(E value);
}

クラスの実装

@XmlAccessorType(XmlAccessType.NONE)
@XmlSeeAlso({JaxbObject.class})
public class JaxbList extends JaxbObject<ArrayList<JaxbObject<?>>> {

    private ArrayList<JaxbObject<?>> value;

    public ArrayList<JaxbObject<?>> getValue() {
        return this.value;
    }

    public void setValue(ArrayList<JaxbObject<?>> value) {
        this.value = value;
    }
}

@XmlAccessorType(XmlAccessType.NONE)
@XmlSeeAlso({JaxbObject.class})
public class JaxbMap extends JaxbObject<HashMap<String, JaxbObject<?>>> {

    private HashMap<String, JaxbObject<?>> value;

    public HashMap<String, JaxbObject<?>> getValue() {
        return this.value;
    }

    public void setValue(HashMap<String, JaxbObject<?>> value) {
        this.value = value;
    }
}


@XmlAccessorType(XmlAccessType.NONE)
@XmlType
final public class JaxbString extends JaxbObject<String> {

    private String value;

    public String getValue() {
        return this.value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}


@XmlAccessorType(XmlAccessType.NONE)
@XmlType
final public class JaxbInt extends JaxbObject<Integer> {

    private Integer value;

    public Integer getValue() {
        return this.value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }
}

getValue() に @XmlValue のアノテーションを付けることができれば、ラッパー クラスが XML または JSON に追加されないことが予想されますが、@XMLValue はその場所では有効ではありません。@XMLValue が Moxy のその場所で有効であるという投稿を見ましたが、Moxy に移動するには、私がやろうとしていることがサポートされていることを知る必要があります。

4

1 に答える 1