rest - JAXB Jackson - 如何处理 map ?

标签 rest jaxb jackson

我有一个 Web 应用程序,可以在其中从域对象生成 POJO。我的一个域对象包含一个 map ,并且 JAXB 生成以下架构:

<xs:element name="persons">
  <xs:complexType>
      <xs:sequence>
          <xs:element name="entry" minOccurs="0" maxOccurs="unbounded">
              <xs:complexType>
                 <xs:sequence>
                    <xs:element name="key" minOccurs="0" type="xs:string"/>
                    <xs:element name="value" minOccurs="0" type="person"/>
                 </xs:sequence>
              </xs:complexType>
          </xs:element>
      </xs:sequence>
   </xs:complexType>
</xs:element>

这是从 HashMap<String, Person> 生成的人员:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "personConfiguration", propOrder = {
    "persons",
})
@XmlRootElement(name = "personConfiguration")
public class PersonConfiguration
{

    @XmlElement(required = true)
    protected PersonConfiguration.Persons persons;

    /**
     * Gets the value of the persons property.
     * 
     * @return
     *     possible object is
     *     {@link PersonConfiguration.Persons }
     *     
     */
    public PersonConfiguration.Persons getPersons() {
        return persons;
    }

    /**
     * Sets the value of the persons property.
     * 
     * @param value
     *     allowed object is
     *     {@link PersonConfiguration.Persons }
     *     
     */
    public void setPersons(PersonConfiguration.Persons value) {
        this.persons = value;
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "entry"
    })
    public static class Persons
    {

        protected List<PersonConfiguration.Persons.Entry> entry;

        /**
         * Gets the value of the entry property.
         * 
         * <p>
         * This accessor method returns a reference to the live list,
         * not a snapshot. Therefore any modification you make to the
         * returned list will be present inside the JAXB object.
         * This is why there is not a <CODE>set</CODE> method for the entry property.
         * 
         * <p>
         * For example, to add a new item, do as follows:
         * <pre>
         *    getEntry().add(newItem);
         * </pre>
         * 
         * 
         * <p>
         * Objects of the following type(s) are allowed in the list
         * {@link PersonConfiguration.Persons.Entry }
         * 
         * 
         */
        public List<PersonConfiguration.Persons.Entry> getEntry() {
            if (entry == null) {
                entry = new ArrayList<PersonConfiguration.Persons.Entry>();
            }
            return this.entry;
        }


        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "", propOrder = {
            "key",
            "value"
        })
        public static class Entry
        {

            protected String key;
            protected Person value;

            /**
             * Gets the value of the key property.
             * 
             * @return
             *     possible object is
             *     {@link String }
             *     
             */
            public String getKey() {
                return key;
            }

            /**
             * Sets the value of the key property.
             * 
             * @param value
             *     allowed object is
             *     {@link String }
             *     
             */
            public void setKey(String value) {
                this.key = value;
            }

            /**
             * Gets the value of the value property.
             * 
             * @return
             *     possible object is
             *     {@link Person }
             *     
             */
            public Person getValue() {
                return value;
            }

            /**
             * Sets the value of the value property.
             * 
             * @param value
             *     allowed object is
             *     {@link Person }
             *     
             */
            public void setValue(Person value) {
                this.value = value;
            }

        }

    }

}

正如人们所看到的,JAXB 添加了这一额外级别的间接条目 -> 键、值。难题的其他部分是 Spring MVC、使用 JSON 对象的 REST 调用。

现在,基于 XML 的 REST 调用可以与上面的对象架构一起正常工作,但是当使用具有相同架构的 JSON 消息发送相同的调用时,我会收到 JSONMappingException。

你知道为什么会发生这种情况吗?

最佳答案

注意:我是EclipseLink JAXB (MOXy) JAXB (JSR-222) 的领导者和成员专家组。

当使用不同的 XML 和 JSON 绑定(bind)提供程序时,很难保持 XML 和 JSON 表示的一致性。下面的示例说明了如何使用 MOXy 作为 XML 和 JSON 提供程序来简化这一过程,并将所有映射信息作为 JAXB 注释提供。

下面是一个示例域对象,其中 persons 字段将从您的问题生成 XML 架构片段。

package forum13784163;

import java.util.Map;

import javax.xml.bind.annotation.*;

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

    Map<String, Person> persons;

}

下面是您的 Person 类的示例。请注意我如何将 id 字段映射到 XML 属性。

package forum13784163;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Person {

    @XmlAttribute
    int id;

    String name;

    int age;

}

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

input.json

如果 MOXy 用作 JSON 绑定(bind)提供程序,则 JSON 表示形式如下所示。

{
   "persons" : {
      "entry" : [ {
         "key" : "Jane",
         "value" : {
            "id" : 123,
            "name" : "Jane",
            "age" : 30
         }
      } ]
   }
}

演示

在下面的演示代码中,JSON 被解码为对象,然后这些相同的对象被编码为 XML。这是通过包含一组元数据的一个 JAXBContext 完成的。

package forum13784163;

import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
        unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
        StreamSource json = new StreamSource("src/forum13784163/input.json");
        Root root = unmarshaller.unmarshal(json, Root.class).getValue();

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

}

输出

下面是生成的 XML。

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <persons>
      <entry>
         <key>Jane</key>
         <value id="123">
            <name>Jane</name>
            <age>30</age>
         </value>
      </entry>
   </persons>
</root>

了解更多信息

关于rest - JAXB Jackson - 如何处理 map ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13784163/

相关文章:

java - 使用 Jackson 注释映射 Hibernate 实体

web-services - 授权和构建 RESTful 后端的正确方法是什么

java - XSD 转 Java,指定使用 Java HashMap

JAXB Marshalling - 扩展现有类

java - 序列化 cglib 创建的代理对象

java - 使用 Jackson 从 ObjectNode 获取嵌套的 JSON 元素

rest - 如何使用 ArcGIS REST 正确设置 geocodeAddresses POST 格式

rest - 基本 HTTP 和不记名 token 身份验证

java - 在java中用rest返回实现的类型

java - 是否可以有多个 xmlRootElement?