我试图创建一个 JAX-RS 服务,它允许将基元、映射和列表的混合值作为映射和列表的值。领域模型中的所有属性都不能具体定义,因为数据将来自不同的系统,其中一些属性存在而其他属性不存在。该服务需要同时支持 XML 和 JSON。JSON 结构需要类似于下面列出的,由于包装类,没有额外的元素嵌套。XML 结构尚未设置,更具延展性。
到目前为止,我一直在使用 Resteasy 和 Jackson,并且一直在回避特定于供应商的注释,但是我意识到这可能是不可避免的。这些服务 API 没有被锁定,我愿意接受其他可以实现这一目标的建议。一个要求是这是一个标准的 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 将再次返回该值。
理想情况下,我希望 Maps 和 Lists 是强类型的,以便只能添加具有 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,我需要知道它支持我正在尝试做的事情。