如何在代码中为JACKSON提供namespace-mapper?

时间:2012-11-03 22:52:51

标签: json jaxb jackson

我正在尝试序列化一个JAXB生成的类。使用Jettison,我可以创建一个哈希映射,将XML名称空间映射到任何JSON前缀。使用Jettison,我也可以在序列化中获得区分大小写。使用JACKSON,它都是小写的。所以,看来Jettison能够更好地理解XMLRootElement(name=…)

如何让JACKSON更好地理解XMLRootElement之类的JAXB注释?

如何为JACKSON提供XML→JSON命名空间映射器?

2 个答案:

答案 0 :(得分:2)

注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。

EclipseLink MOXy是一个符合JAXB(JSR-222)的实现。在EclipseLink 2.4.0中,我们引入了JSON绑定。由于MOXy是一个JAXB实现,您会发现MOXy生成的JSON输出与基于相同元数据的XML输出非常一致。我将在下面举例说明。


DOMAIN MODEL

以下是我将用于此答案的域模型。有关在JAXB模型中指定名称空间信息的更多信息,请参阅:http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

包信息

@XmlSchema(
        namespace="http://www.example.com/A",
        elementFormDefault=XmlNsForm.QUALIFIED,
        xmlns={
                @XmlNs(prefix="a",namespaceURI = "http://www.example.com/A"),
                @XmlNs(prefix="b",namespaceURI = "http://www.example.com/B")
        }
)
package forum13214306;

import javax.xml.bind.annotation.*;

<强>客户

package forum13214306;

import javax.xml.bind.annotation.*;

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

    String firstName;

    @XmlElement(namespace="http://www.example.com/B")
    String lastName;

}

XML处理

以下是域模型如何与XML表示形式对应的示例。

演示

package forum13214306;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum13214306/input.xml");
        Customer customer = (Customer) unmarshaller.unmarshal(xml);

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

}

input.xml中/输出

<?xml version="1.0" encoding="UTF-8"?>
<a:customer xmlns:b="http://www.example.com/B" xmlns:a="http://www.example.com/A">
   <a:firstName>Jane</a:firstName>
   <b:lastName>Doe</b:lastName>
</a:customer>

JSON处理 - 没有名字

命名空间不是JSON概念,所以如果可以避免这种情况,我建议不要模拟它们。下面我将演示MOXy不需要它们。请注意完全相同的域模型,此处使用的JAXBContext用于带有名称空间的XML文档。

jaxb.properties

要将MOXy指定为JSON提供程序,您需要在与域模型相同的程序包中包含名为jaxb.properties的文件,并带有以下条目(请参阅:http://blog.bdoughan.com/search/label/jaxb.properties)。

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

演示

要启用JSON绑定,需要在MEDIA_TYPEMarshaller上启用Unmarshaller属性。

package forum13214306;

import java.io.File;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
        File json = new File("src/forum13214306/input.json");
        Customer customer = (Customer) unmarshaller.unmarshal(json);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
        marshaller.marshal(customer, System.out);
    }

}

input.json /输出

以下是运行演示代码的输入和输出。请注意JSON文档中没有模拟的命名空间信息。

{
   "customer" : {
      "firstName" : "Jane",
      "lastName" : "Doe"
   }
}

JSON处理 - 使用模拟的名字

演示

如果您真的想在JSON文档中模拟名称空间,可以利用NAMESPACE_PREFIX_MAPPERMarshaller上的Unmarshaller属性来执行此操作。

package forum13214306;

import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;

public class Demo {

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

        Map<String, String> namespaceToPrefixMap = new HashMap<String, String>(2);
        namespaceToPrefixMap.put("http://www.example.com/A", "a");
        namespaceToPrefixMap.put("http://www.example.com/B", "b");

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
        unmarshaller.setProperty(UnmarshallerProperties.JSON_NAMESPACE_PREFIX_MAPPER, namespaceToPrefixMap);
        File json = new File("src/forum13214306/input.json");
        Customer customer = (Customer) unmarshaller.unmarshal(json);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
        marshaller.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER, namespaceToPrefixMap);
        marshaller.marshal(customer, System.out);
    }

}

<强> input.json /输出

{
   "a.customer" : {
      "a.firstName" : "Jane",
      "b.lastName" : "Doe"
   }
}

更多信息

答案 1 :(得分:0)

与XML不同,JSON没有名称空间。那么为什么你觉得你需要命名空间映射?数据绑定意味着使用格式的特征在Java POJO和数据格式之间进行映射。对于XML,这包括名称空间,元素与属性的选择等。使用JSON,大部分复杂性被删除,这意味着属性名称按原样使用。

对于JAXB注释:Jackson有自己的一组注释可以更好地匹配,但如果您确实希望使用JAXB注释作为附加或替代配置源,则需要使用JAXB Annotation module。 但是对于使用XMLRootElement,JSON没有必要:JSON对象没有名称。

我不知道你的意思是“在序列化中获得案例敏感性” - 在什么意义上是正确的?问题是什么?您需要提供POJO定义以及预期JSON的示例。

最后,请记住,JSON和XML符号不需要彼此看起来像。这些是具有不同逻辑数据模型的不同数据格式,以及自然不同的映射:例如,JSON在数组和对象之间具有本机区别;而XML必须同时使用Elements。 XML具有JSON缺少的名称空间和属性。这些导致不同的自然映射,并且试图“统一”两者导致对于一个或另一个或两者的某种不自然的结果。对于Jettison(以及使用它的框架),它是丑陋的JSON(“franken-JSON”)。