本文介绍了JACKSON对Java Generics的支持?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我正在开发一个基于模式的restFul项目。所以,我们使用JAXB进行XSD - > JAVA转换。我有一个课程如下:

Currently, I am working on a restFul project, which is schema based. So, we are using JAXB to do a XSD-->JAVA conversion. I have a class as follows:

    @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}}

尝试反序列化时,我得到以下内容eption:

When trying to deserialize, I am getting the following exception:

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做同样的事情?

Googling for solutions, suggests that you have to either add more meta-data to the serialized form or register a deserializer. Jettison is using JAXB annotations to successfully serialize and de-serialize. Plus, I can remove the namespace "http://www.intuit.com/psd/cdm/v1" from serialized too. Is there a way to do the same with JACKSON?

这是我用来配置JACKSON的代码:

This is the code that I use to configure 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);


推荐答案

注意:我'在领导和成员专家组。

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

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

Jackson is not a JAXB (JSR-222) compliant implementation, it only supports a subset of JAXB annotations in its JSON-binding implementation. For JAXB generated models you may be interested in EclipseLink JAXB (MOXy) which natively supports JSON binding.

JAVA MODEL

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

Below is a partial Java model that I inferred from your question.

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 {

}

交易

以下是交易的简化版本 class。

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 类的简化版。它指定与 @XmlElementRef 用法一起使用的 @XmlElementDecl 注释。

Below is a simplified version of your ObjectFactory class. It specifies the @XmlElementDecl annotations that are used with your @XmlElementRef usage.

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 与您的域模型在同一个包中,并带有以下条目:

To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry:

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






DEMO

下面的演示代码会将对象编组为XML和JSON

The demo code below will marshal the objects to both XML and 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表示非常相似。

Below is the output from running the demo code. Note how the JSON representation is very similar to the XML representation.

<?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
   }
}






更多信息





  • http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html
  • http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html
  • http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

更新#1

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

Below are the answers to your first set of follow-up questions:

你可以使用MOXy的外部映射文档以自定义JSON表示。请参阅下面的链接答案以获取完整的代码示例。

You can use MOXy's external mapping document to customize the JSON representation. See linked answer below for a full code example.



  • Can I get MOXy to rename an element when generating json?

默认情况下,MOXy不要求您在JSON消息中模拟名称空间限定以匹配XML结构。在我们的XML绑定中,我们基于限定名称进行匹配,在我们的JSON绑定中,我们基于相同的元数据基于本地名称进行匹配。我们还支持Jettison样式的命名空间。以下链接的答案包含了如何使用MOXy完成此操作的完整示例。

By default MOXy does not require that you emulate namespace qualification in your JSON message to match your XML structure. In our XML binding we do matching based on the qualified name and in our JSON binding we do the matching based on the local name based on the same metadata. We also support Jettison style namespaces. The linked answer below contains a full example of how this is done with MOXy.



  • How to provide JACKSON with the namespace-mapper in the code?

Jettison是一个将JSON转换为/从StAX事件转换的库,以便它可以与XML绑定库一起使用来生成/使用JSON (参见:)。由于这个问题,Jettison在MOXy没有的下列项目方面存在问题。

Jettison is a library that converts JSON to/from StAX events so that it can be used with an XML binding library to produce/consume JSON (see: http://blog.bdoughan.com/2011/04/jaxb-and-json-via-jettison.html). Because of this Jettison has problems with the following items that MOXy doesn't.


  • Jettison在将大小为1的列表表示为JSON数组时出现问题。

  • XML属性需要特殊指示符

  • 难以指定是否希望字符串1表示为1或1表示JSON 。

  • XML命名空间需要一个特殊的表示形式(参见:)。

  • Jettison has problems representing lists of size 1 as JSON arrays.
  • A special indicator is required for XML attributes
  • Difficult to specify whether you want the String "1" represented as "1" or 1 in JSON.
  • A special representation is required for XML namespaces (see: http://blog.bdoughan.com/2011/04/jaxb-and-json-via-jettison-namespace.html).

更新#2

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

Below are the answers to your second set of follow-up questions:

Jettison仅根据收到的事件将StAX事件转换为JSON或从JSON转换。这意味着为了使它能够识别集合,它需要接收2个具有相同名称的startElement事件,因此大小为1的列表不表示为JSON数组。由于MOXy提供本机JSON绑定,因此它知道数据何时来自列表。

Jettison converts StAX events to/from JSON based solely on the events received. This means that in order for it to recognize a collection it needs to receive 2 startElement events with the same name, so lists of size 1 are not represented as JSON arrays. Since MOXy provides native JSON-binding it knows when data is coming from a list.

是的,MOXy将Java对象(带有JAXB和MOXy注释)直接转换为JSON或从JSON转换。

Yes, MOXy converts Java objects (with JAXB and MOXy annotations) directly to/from JSON.

我们没有将MOXy与Jettison进行比较的文件。我们确实检查了人们在使用Jettison时遇到的痛点,并确保我们消除了这些痛点。虽然MOXy不需要模拟像Jt之类的XML属性和命名空间这样的XML概念,但我们提供的设置可以让人们更容易从Jettison过渡到MOXy。

We don't have a document comparing MOXy with Jettison. We did examine the pain points people experienced when using Jettison and made sure we eliminated those. And although MOXy does not need to emulate XML concepts like attributes and namespaces in JSON like Jettison does we provide settings to enable this behaviour to make it easier for people to transition from Jettison to MOXy.



  • How to provide JACKSON with the namespace-mapper in the code?

谢谢你的支持支持。我在Stack Overflow上非常活跃,但如果您将问题发布到您将获得整个团队的支持。

Thank you for your support. I'm pretty active on Stack Overflow, but if you post questions to the EclipseLink Forum you'll be able to get support from the entire team.



  • http://www.eclipse.org/forums/eclipse.rt.eclipselink

这篇关于JACKSON对Java Generics的支持?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 10:57