目前,我正在开发一个基于模式的restFul项目。因此,我们使用JAXB进行XSD - > JAVA转换。我有一个课程如下:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"systemResponse"
})
@XmlRootElement(name = "RestResponse")
public class RestResponse implements Serializable {
private final static long serialVersionUID = 1L;
@XmlElementRef(name = "SystemResponse", namespace = "http://www.intuit.com/psd/cdm/v1", type = JAXBElement.class)
protected JAXBElement<? extends CdmComplexBase> systemResponse;
...
}
以下是序列化的方式:
{"systemResponse":{"name":"{http://www.intuit.com/psd/cdm/v1}Transactions","declaredType":"com.intuit.psd.cdm.v1.Transactions","scope":"javax.xml.bind.JAXBElement$GlobalScope","value":{"requestId":null,"requestName":null,"isEncrypted":null,"totalCount":null,"pageSize":null,"genDuration":null,"genDateTime":null,"transaction":[{"id":null,"externalKey":[],"metaData":null,"accountNumber":"12345678798","transactionNumber":null,"transactionReference":null,"batchID":null,"batchCycleDate":null,"paymentType":null,"paymentMethod":null,"transactionType":null,"cardType":null,"amount":null,"transactionDate":null,"authCode":null,"customerTransactionID":null,"ccnumberFirstSix":null,"ccnumberLastFour":null,"etctype":null,"posentryType":null}]},"nil":false,"globalScope":true,"typeSubstituted":false}}
尝试反序列化时,我遇到以下异常:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class javax.xml.bind.JAXBElement<com.intuit.psd.cdm.v1.CdmComplexBase>]: can not instantiate from JSON object (need to add/enable type information?)
at [Source: java.io.StringReader@725d9aa7; line: 1, column: 20] (through reference chain: com.intuit.psd.cdm.v1.RestResponse["systemResponse"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObjectUsingNonDefault(BeanDeserializer.java:400)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:289)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2796)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1942)
at com.bp.samples.json.HelperJackson.testMarshalUnmarshal(HelperJackson.java:122)
at com.bp.samples.json.JSONToJavaTest.main(JSONToJavaTest.java:42)
Google搜索解决方案,建议您必须向序列化表单添加更多元数据或注册反序列化程序。 Jettison正在使用JAXB注释来成功序列化和反序列化。另外,我也可以从序列化中删除命名空间“http://www.intuit.com/psd/cdm/v1”。有没有办法对JACKSON做同样的事情?
这是我用来配置JACKSON的代码:
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspectorPrimary = new JacksonAnnotationIntrospector();
AnnotationIntrospector introspectorSecondary = new JaxbAnnotationIntrospector();
AnnotationIntrospector pair = new AnnotationIntrospector.Pair(introspectorPrimary, introspectorSecondary);
mapper.getSerializationConfig().with(pair);
mapper.getDeserializationConfig().with(pair);
答案 0 :(得分:4)
注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。
Jackson不是JAXB(JSR-222)兼容的实现,它只在其JSON绑定实现中支持JAXB注释的子集。对于JAXB生成的模型,您可能对EclipseLink JAXB(MOXy)感兴趣,它本身支持JSON绑定。
JAVA模型
以下是我从您的问题中推断出的部分Java模型。
<强> RestResponse 强>
package forum13591952;
import java.io.Serializable;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "systemResponse" })
@XmlRootElement(name = "RestResponse")
public class RestResponse implements Serializable {
private final static long serialVersionUID = 1L;
@XmlElementRef(name = "SystemResponse", namespace = "http://www.intuit.com/psd/cdm/v1", type = JAXBElement.class)
protected JAXBElement<? extends CdmComplexBase> systemResponse;
}
<强> CdmComplexBase 强>
以下是CdmComplexBase
课程的简化版。
package forum13591952;
import javax.xml.bind.annotation.XmlSeeAlso;
@XmlSeeAlso({Transactions.class})
public class CdmComplexBase {
}
<强>交易强>
以下是Transactions
课程的简化版。
package forum13591952;
public class Transactions extends CdmComplexBase {
private long accountNumber;
public long getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(long accountNumber) {
this.accountNumber = accountNumber;
}
}
<强>的ObjectFactory 强>
以下是ObjectFactory
课程的简化版。它指定了@XmlElementDecl
使用时使用的@XmlElementRef
注释。
package forum13591952;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
@XmlRegistry
public class ObjectFactory {
@XmlElementDecl(name="SystemResponse", namespace="http://www.intuit.com/psd/cdm/v1")
public JAXBElement<CdmComplexBase> createCdmComplexBase(CdmComplexBase value) {
return new JAXBElement<CdmComplexBase>(new QName("SystemResponse"), CdmComplexBase.class, value);
}
@XmlElementDecl(name="Transactions", namespace="http://www.intuit.com/psd/cdm/v1", substitutionHeadName="SystemResponse", substitutionHeadNamespace="http://www.intuit.com/psd/cdm/v1")
public JAXBElement<Transactions> createTransactions(Transactions value) {
return new JAXBElement<Transactions>(new QName("Transactions"), Transactions.class, value);
}
}
的 jaxb.properties 强>
要将MOXy指定为JAXB提供程序,您需要在与域模型相同的包中包含名为jaxb.properties
的文件,并带有以下条目:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
<强>样本强>
下面的演示代码将对象封装为XML和JSON
package forum13591952;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(RestResponse.class, ObjectFactory.class);
ObjectFactory objectFactory = new ObjectFactory();
RestResponse response = new RestResponse();
Transactions transactions = new Transactions();
transactions.setAccountNumber(12345678798L);
response.systemResponse = objectFactory.createTransactions(transactions);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
// Marshal to XML
marshaller.marshal(response, System.out);
// Marshal to JSON
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
marshaller.marshal(response, System.out);
}
}
<强>输出强>
以下是运行演示代码的输出。请注意JSON表示与XML表示非常相似。
<?xml version="1.0" encoding="UTF-8"?>
<RestResponse xmlns:ns0="http://www.intuit.com/psd/cdm/v1">
<ns0:Transactions>
<accountNumber>12345678798</accountNumber>
</ns0:Transactions>
</RestResponse>
{
"Transactions" : {
"accountNumber" : 12345678798
}
}
更多信息
更新#1
以下是您第一组后续问题的答案:
1)是否可以通过camal来表示JSON变量:所以AccountNumber - &GT; accountNumber仅适用于JSON?
您可以使用MOXy的外部映射文档来自定义JSON表示。有关完整的代码示例,请参阅下面的链接答案。
2)Jettison已经获得了命名空间映射,Moxy也有吗?
默认情况下,MOXy不要求您在JSON消息中模拟名称空间限定以匹配XML结构。在我们的XML绑定中,我们基于限定名称进行匹配,在我们的JSON绑定中,我们基于相同的元数据基于本地名称进行匹配。我们还支持Jettison样式的命名空间。下面的链接答案包含了如何使用MOXy完成此操作的完整示例。
3)我想,Moxy优于Jettison的优势是什么 性能
Jettison是一个将JSON转换为/从StAX事件转换的库,以便它可以与XML绑定库一起使用来生成/使用JSON(请参阅:http://blog.bdoughan.com/2011/04/jaxb-and-json-via-jettison.html)。因此,Jettison对MOXy没有的以下项目有问题。
更新#2
以下是您的第二组后续问题的答案:
1)你如何解决Jettison的列表问题?
Jettison仅根据收到的事件将StAX事件转换为JSON或从JSON转换。这意味着为了使它能够识别集合,它需要接收2个具有相同名称的startElement事件,因此大小为1的列表不表示为JSON数组。由于MOXy提供本机JSON绑定,因此它知道数据何时来自列表。
2)那么,你是从JAXB类直接转到JSON吗?
是的,MOXy将Java对象(带有JAXB和MOXy注释)直接转换为JSON或从JSON转换。
3)是否有一篇论文或链接经历了第3个问题 细节?
我们没有将MOXy与Jettison进行比较的文件。我们确实检查了人们在使用Jettison时遇到的痛点,并确保我们消除了这些痛点。虽然MOXy不需要像Jettison那样模仿JSON中的属性和命名空间等XML概念,但我们提供的设置可以使人们更容易从Jettison过渡到MOXy。
此时我想向Intuit推荐MOXy JAXB + JSON。
感谢您的支持。我在Stack Overflow上非常活跃,但是如果你向EclipseLink Forum发布问题,你将能够得到整个团队的支持。
答案 1 :(得分:1)
JAXBElement是一种特定于XML的数据类型(基本上类似于DOM树),而Jackson不知道如何处理它。 Jettison可能能够解决这个问题的原因是它建立在XML API之上,并且只在输出端(或输入的最低部分)转换为JSON。
但为什么你在那里使用JAXBElement?它是一种后备用于无法真正数据绑定的情况;有点像将数据映射到Java Map
左右。你能用真正的POJO吗?那会很好。