JACKSON 支持 Java 泛型吗?

Beh*_*ali 4 json jettison jackson

目前,我正在研究一个基于架构的 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;

...
}
Run Code Online (Sandbox Code Playgroud)

这是它的序列化方式:

{"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}}
Run Code Online (Sandbox Code Playgroud)

尝试反序列化时,出现以下异常:

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)
Run Code Online (Sandbox Code Playgroud)

谷歌搜索解决方案,建议您必须向序列化表单添加更多元数据或注册反序列化器。Jettison 正在使用 JAXB 注释来成功地序列化和反序列化。另外,我也可以从序列化中删除命名空间“http://www.intuit.com/psd/cdm/v1”。有没有办法对杰克逊做同样的事情?

这是我用来配置 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);
Run Code Online (Sandbox Code Playgroud)

bdo*_*han 5

注意: 我是EclipseLink JAXB (MOXy) 的负责人和JAXB (JSR-222)专家组的成员。

Jackson 不是 JAXB (JSR-222) 兼容实现,它仅支持其 JSON 绑定实现中的 JAXB 注释子集。对于 JAXB 生成的模型,您可能对 EclipseLink JAXB (MOXy) 感兴趣,它本机支持 JSON 绑定。

爪哇模型

以下是我从您的问题中推断出的部分 Java 模型。

休息反应

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;

}
Run Code Online (Sandbox Code Playgroud)

CdmComplexBase

以下是您的CdmComplexBase课程的简化版本。

package forum13591952;

import javax.xml.bind.annotation.XmlSeeAlso;

@XmlSeeAlso({Transactions.class})
public class CdmComplexBase {

}
Run Code Online (Sandbox Code Playgroud)

交易

以下是您的Transactions课程的简化版本。

package forum13591952;

public class Transactions extends CdmComplexBase {

    private long accountNumber;

    public long getAccountNumber() {
        return accountNumber;
    }

    public void setAccountNumber(long accountNumber) {
        this.accountNumber = accountNumber;
    }

}
Run Code Online (Sandbox Code Playgroud)

对象工厂

以下是您的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);
    }

}
Run Code Online (Sandbox Code Playgroud)

jaxb.properties

要将 MOXy 指定为您的 JAXB 提供程序,您需要包含一个jaxb.properties在与域模型相同的包中调用的文件,其中包含以下条目:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Run Code Online (Sandbox Code Playgroud)

演示

下面的演示代码将对象编组为 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);
    }

}
Run Code Online (Sandbox Code Playgroud)

输出

下面是运行演示代码的输出。请注意 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
   }
}
Run Code Online (Sandbox Code Playgroud)

想要查询更多的信息


更新 #1

以下是您的第一组后续问题的答案:

1) 有没有办法对 JSON 变量进行 camal 大小写:所以 AccountNumber --> 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 相互转换。

3) 是否有更详细地通过问题 3 的论文或链接?

我们没有将 MOXy 与 Jettison 进行比较的文档。我们确实检查了人们在使用 Jettison 时遇到的痛点,并确保我们消除了这些痛点。尽管 MOXy 不需要像 Jettison 那样模拟 JSON 中的属性和命名空间等 XML 概念,但我们提供了启用此行为的设置,以便人们更轻松地从 Jettison 过渡到 MOXy。

在这一点上,我想在做 JAXB+JSON 时为 Intuit 推荐 MOXy。

感谢您的支持。我在 Stack Overflow 上非常活跃,但如果您向EclipseLink 论坛提出问题,您将能够获得整个团队的支持。