【问题标题】:Creating a JAX-RS object that contains collections and primitives as values of a map创建一个包含集合和原语作为映射值的 JAX-RS 对象
【发布时间】:2013-07-19 19:06:23
【问题描述】:

我试图创建一个 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,我需要知道它支持我正在尝试做的事情。

【问题讨论】:

    标签: xml jaxb jackson moxy


    【解决方案1】:

    几个想法:

    1. Jackson 可以使用 JAXB 注释以及它自己的注释:默认情况下,您的 JAX-RS 容器可能会或可能不会启用支持,但即使没有,启用也很容易
    2. Jackson 还可以使用其 XML 模块从 https://github.com/FasterXML/jackson-dataformat-xml 输出 XML——可以使用 Jackson 和/或 JAXB 注释

    关于 XML 需要注意的一点是,虽然使用 JSON,您通常可以获得任何合理的 JSON 来映射到 Java 对象,但 XML 有其自身的特性,并且可能更难以获得 精确 两侧结构。因此,如果可能的话,最好关注您正在传递的数据,并找出好的对象表示,然后看看可以生成哪些类型的 XML 表示。我意识到在处理其他人产生的 XML 内容时,这可能并不总是一种选择。但是能够接受细微的差异会让生活变得更轻松,尤其是在处理 Java Lists 和 Maps 时。

    关于 JAXB 注释:请记住,它们是特定于 XML 的,因此您对特定于供应商的注释的担忧可以与在 JSON(和/或其他数据类型)上使用 XML 注释的担忧相平衡。避免或尽量减少使用注释的能力是一个好方法;通过使用标准命名约定和默认结构;也就是说,尽量避免对数据格式表示进行过多修改,并接受默认映射。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-07
      • 1970-01-01
      • 2014-10-11
      相关资源
      最近更新 更多