0

背景:

(注意日期元素 - 即具有“nillable”属性 - 似乎导致“com.fasterxml.jackson.databind.JsonMappingException”)。

问题:

如何使用 com.fasterxml.jackson.databind.ObjectMapper 将 json 字符串解析为相应的 JAXB 对象形式(参见下面的示例代码)?

非常简单的模式如下所示(注意带有“nillable”属性的日期元素):

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema 
    targetNamespace="http://aaa.bbb.ccc/things"
    attributeFormDefault="unqualified"
    elementFormDefault="qualified"
    xmlns:es="http://aaa.bbb.ccc/things"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">        
    <xs:complexType name="ThingType">
    <xs:all>            
        <xs:element name="ThingNbr" type="xs:string" minOccurs="0" />
        <xs:element name="ThingDt" type="xs:date" minOccurs="0" nillable="true"/>               
    </xs:all>
    </xs:complexType>
    <xs:element name="ThingList">
    <xs:complexType>
        <xs:sequence>
        <xs:element name="Thing" type="es:ThingType" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
    </xs:element>
</xs:schema>

失败的示例代码...

package aaa.bbb.ccc.jar;

import aaa.bbb.ccc.generated.ThingList;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;

public class Thingtst {

    public static void main(String[] args) {
    Thingtst tt = new Thingtst();
    ObjectMapper om = new ObjectMapper();
    om.setPropertyNamingStrategy(new PreservePropertyNameStrategy()); //not available in jackson 2.6.3:  PropertyNamingStrategy.UPPER_CASE);

    String jsonString = "{\"Thing\":[{\"ThingNbr\":\"33333333\",\"ThingDt\":\"2017-10-18T00:00:00.000-04:00\"}]}";

    try {

        ThingList tl = om.readValue(jsonString, ThingList.class);  //<== causes JsonMappingException!!!

        System.out.println("ThingNbr=" + tl.getThing().get(0).getThingNbr() + "...ThingDt=" + tl.getThing().get(0).getThingDt());

    } catch (IOException e) {
        e.printStackTrace();
    }
    }
}

这是相关的异常堆栈跟踪:

-
-
-
[INFO] --- exec-maven-plugin:1.2.1:exec (default-cli) @ thingtst ---
com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class javax.xml.bind.JAXBElement<javax.xml.datatype.XMLGregorianCalendar>] from String value ('2017-10-18T00:00:00.000-04:00'); no single-String constructor/factory method
 at [Source: {"Thing":[{"ThingNbr":"33333333","ThingDt":"2017-10-18T00:00:00.000-04:00"}]}; line: 1, column: 33] (through reference chain: aaa.bbb.ccc.generated.ThingList["Thing"]->java.util.ArrayList[0]->aaa.bbb.ccc.generated.ThingType["ThingDt"])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:878)
    at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:281)
    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:284)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1176)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:145)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:520)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:95)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:258)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:125)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:217)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:25)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:520)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:101)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:258)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:125)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3736)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2726)
    at aaa.bbb.ccc.jar.Thingtst.main(Thingtst.java:18)    -
-
-

如有需要,提供更多信息

ThingList.java(我一直无法将 json 字符串解析成这个对象)

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.11 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2017.10.12 at 06:32:00 PM EDT 
//


package aaa.bbb.ccc.generated;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType&gt;
 *   &lt;complexContent&gt;
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
 *       &lt;sequence&gt;
 *         &lt;element name="Thing" type="{http://aaa.bbb.ccc/things}ThingType" maxOccurs="unbounded" minOccurs="0"/&gt;
 *       &lt;/sequence&gt;
 *     &lt;/restriction&gt;
 *   &lt;/complexContent&gt;
 * &lt;/complexType&gt;
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "thing"
})
@XmlRootElement(name = "ThingList")
public class ThingList {

    @XmlElement(name = "Thing")
    protected List<ThingType> thing;

    /**
     * Gets the value of the thing property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the thing property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getThing().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link ThingType }
     * 
     * 
     */
    public List<ThingType> getThing() {
    if (thing == null) {
        thing = new ArrayList<ThingType>();
    }
    return this.thing;
    }

}

事物类型.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.11 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2017.10.12 at 06:32:00 PM EDT 
//


package aaa.bbb.ccc.generated;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlType;
import javax.xml.datatype.XMLGregorianCalendar;


/**
 * <p>Java class for ThingType complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="ThingType"&gt;
 *   &lt;complexContent&gt;
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
 *       &lt;all&gt;
 *         &lt;element name="ThingNbr" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
 *         &lt;element name="ThingDt" type="{http://www.w3.org/2001/XMLSchema}date" minOccurs="0"/&gt;
 *       &lt;/all&gt;
 *     &lt;/restriction&gt;
 *   &lt;/complexContent&gt;
 * &lt;/complexType&gt;
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ThingType", propOrder = {

})
public class ThingType {

    @XmlElement(name = "ThingNbr")
    protected String thingNbr;
    @XmlElementRef(name = "ThingDt", namespace = "http://aaa.bbb.ccc/things", type = JAXBElement.class, required = false)
    protected JAXBElement<XMLGregorianCalendar> thingDt;

    /**
     * Gets the value of the thingNbr property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getThingNbr() {
    return thingNbr;
    }

    /**
     * Sets the value of the thingNbr property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setThingNbr(String value) {
    this.thingNbr = value;
    }

    /**
     * Gets the value of the thingDt property.
     * 
     * @return
     *     possible object is
     *     {@link JAXBElement }{@code <}{@link XMLGregorianCalendar }{@code >}
     *     
     */
    public JAXBElement<XMLGregorianCalendar> getThingDt() {
    return thingDt;
    }

    /**
     * Sets the value of the thingDt property.
     * 
     * @param value
     *     allowed object is
     *     {@link JAXBElement }{@code <}{@link XMLGregorianCalendar }{@code >}
     *     
     */
    public void setThingDt(JAXBElement<XMLGregorianCalendar> value) {
    this.thingDt = value;
    }

}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>aaa.bbb.ccc</groupId>
    <artifactId>thingtst</artifactId>
    <version>1</version>
    <packaging>jar</packaging>
    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-core</artifactId>
        <version>2.17.0</version>
        <scope>provided</scope>
    </dependency>     
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-jackson</artifactId>
        <version>2.17.0</version>
        <scope>provided</scope>               
    </dependency>      
    <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-cxf</artifactId>
        <version>2.17.0</version>
        <scope>provided</scope>              
    </dependency> 
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.6.3</version>
    </dependency>             

    </dependencies>

    <build>
    <finalName>${project.artifactId}-${project.version}</finalName>

    <resources>
        <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
        </resource>
    </resources>

    <plugins>

        <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <showDeprecation>true</showDeprecation>
        </configuration>
        </plugin> 

        <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>jaxb2-maven-plugin</artifactId>
        <version>2.3</version>
        <executions>
            <execution>
            <id>xjc</id>
            <goals>
                <goal>xjc</goal>
            </goals>
            </execution>
        </executions>        
        <configuration>
            <sources>
            <source>src/main/resources/xsd/Thing.xsd</source>
            </sources>
            <packageName>aaa.bbb.ccc.generated</packageName>                    
            <verbose default-value="false">${xjc.verbose}</verbose>
        </configuration>                
        </plugin>              

    </plugins>
    </build>
</project>

环境:

Java 1.8.x

找到修复,参考下面 Veeram 的帖子。

通过添加此依赖项来修改 pom.xml:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.6.3</version>
</dependency>

添加 binding.ejb 文件(如下) - 位置:src/main/ejb/binding.ejb:

<jxb:bindings version="2.0" 
          xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
          xmlns:xs="http://www.w3.org/2001/XMLSchema" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <jxb:bindings schemaLocation="../resources/xsd/Thing.xsd">
    <jxb:globalBindings generateElementProperty="false">
        <jxb:javaType 
        name="java.time.ZonedDateTime" 
        xmlType="xs:date" 
        parseMethod="aaa.bbb.ccc.jar.DateTimeAdapter.parseDateTime" 
        printMethod="aaa.bbb.ccc.jar.DateTimeAdapter.formatDateTime" />
    </jxb:globalBindings>
    </jxb:bindings>
</jxb:bindings>

添加日期时间适配器:

package aaa.bbb.ccc.jar;

import java.time.ZonedDateTime;

public class DateTimeAdapter {
    public static String formatDateTime(ZonedDateTime dateTime) {
    return dateTime.toString();
    }
    public static ZonedDateTime parseDateTime(String dateTime) {
    return ZonedDateTime.parse(dateTime);
    }
}

Thingtst.java 现在看起来像这样:

package aaa.bbb.ccc.jar;

import aaa.bbb.ccc.generated.*;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.*;
import java.io.IOException;

public class Thingtst {

    public static void main(String[] args) throws JsonMappingException {

    ObjectMapper om = new ObjectMapper();
    om.setPropertyNamingStrategy(new PreservePropertyNameStrategy()); //not available in jackson 2.6.3:  PropertyNamingStrategy.UPPER_CASE);  
    om.registerModule(new JavaTimeModule());          

    String jsonString = "{\"Thing\":[{\"ThingNbr\":\"33333333\",\"ThingDt\":\"2017-10-18T00:00:00.000-04:00\"}]}";

    try {                  
        ThingList tl = om.readValue(jsonString, ThingList.class);  //<== causes JsonMappingException!!!
        System.out.println("ThingNbr=" + tl.getThing().get(0).getThingNbr() + "...ThingDt=" + tl.getThing().get(0).getThingDt());            
    } catch (IOException e) {
        e.printStackTrace();
    }
    }
}

项目结构:

新的项目结构

4

1 回答 1

1

您可以尝试以下更改。

贾克斯 B 变化

1.创建日期时间适配器,将xs:date类型映射到java 8时间类

package aaa.bbb.ccc.jar;
import java.time.ZonedDateTime;

public class DateTimeAdapter {

 public static  String formatDateTime(ZonedDateTime dateTime) {
     return dateTime.toString();
 }

 public static ZonedDateTime parseDateTime(String dateTime) {
     return ZonedDateTime.parse(dateTime);
 }
}

2.添加一个xjb文件(binding.xjb)来控制类的生成,放在src/xjb下

在生成类时注册适配器以将 xsd 日期映射到 ZonedDateTime

删除 JAXBElement 包装器

<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <jxb:bindings schemaLocation="../resources/Thing.xsd">
        <jxb:globalBindings generateElementProperty="false">
          <jxb:javaType name="java.time.ZonedDateTime" xmlType="xs:date" parseMethod="aaa.bbb.ccc.jar.DateTimeAdapter.parseDateTime" printMethod="aaa.bbb.ccc.jar.DateTimeAdapter.formatDateTime" />
        </jxb:globalBindings>
    </jxb:bindings>
</jxb:bindings>

杰克逊的变化

1.注册java时间模块

JavaTimeModule module = new JavaTimeModule();
om.registerModule(module);

2.pom添加java时间模块

<dependency>
      <groupId>com.fasterxml.jackson.module</groupId>
      <artifactId>jackson-modules-java8</artifactId>
<dependency>
于 2017-10-23T17:14:59.743 回答