我正在尝试序列化 JAXB 生成的类。使用 Jettison,我能够创建一个哈希映射,将 XML 命名空间映射到任何 JSON 前缀。使用 Jettison,我还可以在序列化中正确区分大小写。对于 JACKSON,它都是小写的。所以,似乎 Jettison 能够XMLRootElement(name=…)
更好地理解。
如何让 JACKSON 更好地理解 JAXB 注释XMLRootElement
?
如何为 JACKSON 提供 XML→JSON 命名空间映射器?
注意: 我是EclipseLink JAXB (MOXy)负责人,也是JAXB (JSR-222)专家组的成员。
EclipseLink MOXy 是符合 JAXB (JSR-222) 的实现。在 EclipseLink 2.4.0 中,我们引入了 JSON 绑定。由于 MOXy 是一个 JAXB 实现,您会发现 MOXy 生成的 JSON 输出将与基于相同元数据的 XML 输出非常一致。我将在下面用一个例子来演示。
领域模型
以下是我将用于此答案的域模型。有关在 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);
}
}
输入.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_TYPE
需要在Marshaller
和上启用该属性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);
}
}
输入.json/输出
下面是运行演示代码的输入和输出。请注意 JSON 文档中没有模拟命名空间信息。
{
"customer" : {
"firstName" : "Jane",
"lastName" : "Doe"
}
}
JSON 处理 - 使用模拟的命名空间
演示
如果您真的想在 JSON 文档中模拟名称空间,您可以利用andNAMESPACE_PREFIX_MAPPER
上的属性来执行此操作。Marshaller
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);
}
}
输入.json/输出
{
"a.customer" : {
"a.firstName" : "Jane",
"b.lastName" : "Doe"
}
}
了解更多信息
与 XML 不同,JSON 没有名称空间。那么为什么你觉得你需要命名空间映射呢?数据绑定意味着 Java POJO 和数据格式之间的映射,使用格式的特性。对于 XML,这包括名称空间、元素与属性的选择等。使用 JSON 可以消除大部分复杂性,这意味着按原样使用属性名称。
至于 JAXB 注解:Jackson 有自己的一组更匹配的注解,但如果您确实想使用 JAXB 注解作为附加或替代配置源,则需要使用JAXB Annotation 模块。但是对于使用XMLRootElement
,JSON 是没有必要的:JSON 对象没有名称。
我不知道您所说的“在序列化中正确区分大小写”是什么意思——在什么意义上?问题是什么?您将需要给出 POJO 定义的示例以及预期的 JSON。
最后,请记住,JSON 和 XML 表示法没有必要看起来彼此相似。这些是具有不同逻辑数据模型的不同数据格式,以及自然不同的映射:例如,JSON 在 Arrays 和 Objects 之间具有原生区别;而 XML 必须同时使用 Elements。XML 具有 JSON 所缺乏的名称空间和属性。这些导致不同的自然映射,并且尝试将两者“统一”会导致其中一个或另一个或两者都有一些不自然的结果。对于 Jettison(以及使用它的框架),它是丑陋的 JSON(“franken-JSON”)。