マップとリストの値として、プリミティブ、マップ、およびリストの混合値を許可する 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 に移動するには、私がやろうとしていることがサポートされていることを知る必要があります。