जैक्सन JSON मैपर के साथ धारावाहिक / deserialize जावा 8 जावा


221

मैं Java 8 LocalDateTime के साथ जैक्सन JSON मैपर का उपयोग कैसे करूँ?

org.codehaus.jackson.map.JsonMappingException: JSON स्ट्रिंग से [साधारण प्रकार, वर्ग java.time.LocalDateTime] प्रकार के मूल्य को तत्काल नहीं कर सकता; कोई एकल स्ट्रिंग निर्माता / फैक्टरी विधि (संदर्भ श्रृंखला के माध्यम से: MyDTO ["field1"] -> SubDTO ["तिथि"]]


4
क्या आप सुनिश्चित हैं कि आप JSD पर लोकल डेटाइम मैप करना चाहते हैं? जहाँ तक मुझे पता है, JSon के पास तारीखों के लिए कोई प्रारूप नहीं है, हालाँकि जावास्क्रिप्ट ISO-8601 का उपयोग करता है। समस्या यह है कि, LocalDateTime का कोई समय क्षेत्र नहीं है ... इसलिए, यदि आप दिनांक / समय की जानकारी भेजने के लिए माध्यम के रूप में JSON का उपयोग करते हैं, तो आपको परेशानी हो सकती है कि क्या ग्राहक समय क्षेत्र की कमी को डिफ़ॉल्ट UTC (या अपने स्वयं के रूप में व्याख्या करेगा) समय क्षेत्र)। यदि आप ऐसा करना चाहते हैं, तो निश्चित रूप से यह ठीक है। लेकिन अगर आपने ZonedDateTime का उपयोग करने पर विचार किया है, तो बस चेक करें
arcuri82

जवाबों:


276

यहां कस्टम सीरियलाइजर्स / डीसेरिएलाइज़र का उपयोग करने की आवश्यकता नहीं है। जैक्सन-मॉड्यूल- java8 के डेटाइम मॉड्यूल का उपयोग करें :

जैक्सन 8 जावा डेट और टाइम एपीआई डेटा प्रकार (JSR-310) को पहचानने के लिए डेटाटाइप मॉड्यूल।

यह मॉड्यूल काफी कुछ वर्गों के लिए समर्थन जोड़ता है:

  • समयांतराल
  • तुरंत
  • LocalDateTime
  • LOCALDATE
  • स्थानीय समय
  • मासिक दिन
  • OffsetDateTime
  • OffsetTime
  • अवधि
  • साल
  • वर्ष माह
  • ZonedDateTime
  • ZoneId
  • ZoneOffset

59
अरे हाँ! हालांकि मैं यह काम नहीं कर रहा था क्योंकि मुझे एहसास नहीं था कि किसी को मैपर ऑब्जेक्ट के लिए इन अनुकूलन में से एक करना होगा: registerModule(new JSR310Module())या findAndRegisterModules()Github.com/FasterXML/jackson-datatype-jsr310 देखें और यहां देखें कि कैसे आप अपने मैपर ऑब्जेक्ट को कस्टमाइज़ करें यदि आप स्प्रिंग फ्रेमवर्क का उपयोग करते हैं: stackoverflow.com/questions/7854030/…
अलेक्जेंडर

10
मेरे साथ कोशिश की गई सबसे सरल के साथ काम नहीं करता है,OffsetDateTime @Test public void testJacksonOffsetDateTimeDeserializer() throws IOException { ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()); String json = "\"2015-10-20T11:00:00-8:30\""; mapper.readValue(json, OffsetDateTime.class); }
अभिजीत सरकार

9
यदि आप हाल ही में स्प्रिंग फ्रेमवर्क का उपयोग करते हैं, तो अपने आप को अनुकूलित करने के लिए अब और कोई आवश्यकता नहीं है, जैसे कि जैक्सन मॉड्यूल जैसे कि यह अब स्वचालित रूप से पंजीकृत है यदि वे क्लासपाथ पर पाए जाते हैं: spring.io/blog/2014/12/02/…
vorburger

37
JSR310Module पहले से ही थोड़ा पुराना है, इसके बजाय JavaTimeModule
याकूब

17
@MattBall मैं यह जोड़ने का सुझाव दूंगा कि, जैक्सन-डेटाटाइप-jsr310 का उपयोग करने के अलावा, आपको अपने ऑब्जेक्ट मैपर के साथ JavaTimeModule को पंजीकृत करने की आवश्यकता है objectMapper.registerModule(new JavaTimeModule());:। क्रमबद्धता और अस्मितावाद दोनों।
ग्रैंडआमिरल

76

अद्यतन: ऐतिहासिक कारणों से इस उत्तर को छोड़ना, लेकिन मैं इसकी अनुशंसा नहीं करता। कृपया स्वीकृत उत्तर ऊपर देखें।

जैक्सन को अपने कस्टम [डी] क्रमांकन वर्गों का उपयोग करके मानचित्र बताएं:

@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime ignoreUntil;

कस्टम कक्षाएं प्रदान करें:

public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
    @Override
    public void serialize(LocalDateTime arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException {
        arg1.writeString(arg0.toString());
    }
}

public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
    @Override
    public LocalDateTime deserialize(JsonParser arg0, DeserializationContext arg1) throws IOException {
        return LocalDateTime.parse(arg0.getText());
    }
}

यादृच्छिक तथ्य: यदि मैं कक्षाओं के ऊपर घोंसला बनाता हूं और उन्हें स्थिर नहीं बनाता, तो त्रुटि संदेश अजीब है: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported


इस लेखन के रूप में, अन्य उत्तर पर यहाँ केवल लाभ फ़ास्टरएक्सएमएल पर निर्भर नहीं है, जो कुछ भी है।
अलेक्जेंडर टेलर

4
FasterXML है जैक्सन। fastxml.com github.com/fasterxml/jackson
मैट बॉल

4
ओह मैं समझा। परियोजना में बहुत सारी प्राचीन पोम प्रविष्टियाँ मैं पर काम कर रहा हूँ। इतना अधिक org.codehaus नहीं, अब यह सब com.fasterxml है। धन्यवाद!
अलेक्जेंडर टेलर

2
इसके अलावा, मैं बिल्ट-इन एक का उपयोग करने में असमर्थ था क्योंकि मुझे फॉर्मेटर ISO_DATE_TIME को पास करने की आवश्यकता थी। सुनिश्चित नहीं है कि JSR310Module का उपयोग करते समय ऐसा करना संभव है।
isaac.hazan

स्प्रिंग के साथ इसका उपयोग करके मुझे दोनों का बीन बनाना था LocalDateTimeSerializerऔरLocalDateTimeDeserializer
BenR

53

यदि आप FastMml के ObjectMapper वर्ग का उपयोग कर रहे हैं, तो डिफ़ॉल्ट रूप से ObjectMapper LocalDateTime वर्ग को नहीं समझता है, इसलिए, आपको अपनी श्रेणी / मैवेन में एक और निर्भरता जोड़ने की आवश्यकता है:

compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.7.3'

अब आपको इस लायब्रेरी द्वारा दिए गए डेटाटाइप समर्थन को ऑब्जेक्टमैपर ऑब्जेक्ट में पंजीकृत करने की आवश्यकता है, यह निम्नलिखित द्वारा किया जा सकता है:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();

अब, अपने jsonString में, आप आसानी से अपने java.LocalDateTime क्षेत्र को निम्नानुसार रख सकते हैं:

{
    "user_id": 1,
    "score": 9,
    "date_time": "2016-05-28T17:39:44.937"
}

यह सब करने से, जावा ऑब्जेक्ट रूपांतरण के लिए आपकी Json फ़ाइल ठीक काम करेगी, आप फ़ाइल को निम्न द्वारा पढ़ सकते हैं:

objectMapper.readValue(jsonString, new TypeReference<List<User>>() {
            });

4
findAndRegisterModules()एक महत्वपूर्ण टुकड़ा था जो मेरे लिए याद कर रहा थाObjectMapper
Xaero Degreaz

2
तुरंत के बारे में क्या?
पाउडर 366

1
मैंने इस पंक्ति को भी जोड़ा: objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
जेनेट

यह आवश्यक पूर्ण कोड है: ObjectMapper objectMapper = new ObjectMapper (); objectMapper.findAndRegisterModules (); objectMapper.configure (सीरियलाइजेशन फ़ीचर .RITE_Dates_AS_TIMESTAMPS, गलत);
कुश डिक

42

यह मावेन निर्भरता आपकी समस्या का समाधान करेगी:

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

एक बात जो मैंने संघर्ष की है, वह यह है कि ZonedDateTime समयक्षेत्र के लिए डीज़ेरिएशन के दौरान GMT में बदल दिया जा रहा है। यह पता चला कि डिफ़ॉल्ट रूप से जैकसन इसे संदर्भ से एक के साथ बदल देता है .. ज़ोन रखने के लिए किसी को इस 'सुविधा' को अक्षम करना होगा

Jackson2ObjectMapperBuilder.json()
    .featuresToDisable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)

5
DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE संकेत के लिए बहुत धन्यवाद।
आंद्रेई उर्वन्त्सेव

5
अक्षम होने के साथ-साथ DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONEमुझे SerializationFeature.WRITE_DATES_AS_TIMESTAMPSहर उस चीज़ के लिए भी अक्षम करना पड़ा जिस तरह से काम करना शुरू करना चाहिए।
मैट वॉटसन

16

स्प्रिंग बूट का उपयोग करते समय मुझे इसी तरह की समस्या थी । स्प्रिंग बूट 1.5.1 के साथ। मुझे केवल इतना करना है कि निर्भरता जोड़ना है:

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

7

यदि आप जर्सी का उपयोग कर रहे हैं, तो आपको मावेन निर्भरता (जैकसन-डेटाटाइप-जेएसआर 310) को जोड़ने की जरूरत है क्योंकि अन्य लोगों ने सुझाव दिया है और अपनी वस्तु मैपर उदाहरण को पंजीकृत करें:

@Provider
public class JacksonObjectMapper implements ContextResolver<ObjectMapper> {

  final ObjectMapper defaultObjectMapper;

  public JacksonObjectMapper() {
    defaultObjectMapper = createDefaultMapper();
  }

  @Override
  public ObjectMapper getContext(Class<?> type) {
    return defaultObjectMapper;
  }

  private static ObjectMapper createDefaultMapper() {
    final ObjectMapper mapper = new ObjectMapper();    
    mapper.registerModule(new JavaTimeModule());
    return mapper;
  }
}

अपने संसाधनों में जैक्सन को पंजीकृत करते समय, आपको इस तरह के मैपर को जोड़ना होगा:

final ResourceConfig rc = new ResourceConfig().packages("<your package>");
rc
  .register(JacksonObjectMapper.class)
  .register(JacksonJaxbJsonProvider.class);

6

आप उपयोग नहीं कर सकते jackson-modules-java8जो कुछ कारणों के लिए आप (डी) को क्रमानुसार कर सकते हैं के रूप में तत्काल क्षेत्र longका उपयोग कर @JsonIgnoreऔर @JsonGetterऔर @JsonSetter:

public class MyBean {

    private Instant time = Instant.now();

    @JsonIgnore
    public Instant getTime() {
        return this.time;
    }

    public void setTime(Instant time) {
        this.time = time;
    }

    @JsonGetter
    private long getEpochTime() {
        return this.time.toEpochMilli();
    }

    @JsonSetter
    private void setEpochTime(long time) {
        this.time = Instant.ofEpochMilli(time);
    }
}

उदाहरण:

@Test
public void testJsonTime() throws Exception {
    String json = new ObjectMapper().writeValueAsString(new MyBean());
    System.out.println(json);
    MyBean myBean = new ObjectMapper().readValue(json, MyBean.class);
    System.out.println(myBean.getTime());
}

पैदावार

{"epochTime":1506432517242}
2017-09-26T13:28:37.242Z

यह एक बहुत ही साफ-सुथरा तरीका है और आपकी कक्षा के उपयोगकर्ताओं को जो चाहे जिस तरह से उपयोग करने की अनुमति देता है।
अशर हसन

3

मैं इस समय प्रारूप का उपयोग करता हूं: "{birthDate": "2018-05-24T13:56:13Z}" java से java.time में deserialize करने के लिए। Instant (स्क्रीनशॉट देखें)

यहां छवि विवरण दर्ज करें


3

यह केवल एक उदाहरण है कि यूनिट टेस्ट में इसका उपयोग कैसे किया जाए जो मैंने इस मुद्दे को डीबग करने के लिए हैक किया था। प्रमुख तत्व हैं

  • mapper.registerModule(new JavaTimeModule());
  • मावेन की निर्भरता <artifactId>jackson-datatype-jsr310</artifactId>

कोड:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.IOException;
import java.io.Serializable;
import java.time.Instant;

class Mumu implements Serializable {
    private Instant from;
    private String text;

    Mumu(Instant from, String text) {
        this.from = from;
        this.text = text;
    }

    public Mumu() {
    }

    public Instant getFrom() {
        return from;
    }

    public String getText() {
        return text;
    }

    @Override
    public String toString() {
        return "Mumu{" +
                "from=" + from +
                ", text='" + text + '\'' +
                '}';
    }
}
public class Scratch {


    @Test
    public void JacksonInstant() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());

        Mumu before = new Mumu(Instant.now(), "before");
        String jsonInString = mapper.writeValueAsString(before);


        System.out.println("-- BEFORE --");
        System.out.println(before);
        System.out.println(jsonInString);

        Mumu after = mapper.readValue(jsonInString, Mumu.class);
        System.out.println("-- AFTER --");
        System.out.println(after);

        Assert.assertEquals(after.toString(), before.toString());
    }

}

2

आप इसे अपनी application.ymlफ़ाइल में इंस्टेंट समय को हल करने के लिए सेट कर सकते हैं , जो कि java8 में तारीख एपीआई है:

spring.jackson.serialization.write-dates-as-timestamps=false

2

यदि आप स्प्रिंग बूट का उपयोग कर रहे हैं और इस समस्या को ऑफसेटसेटेट के साथ रखते हैं, तो @Mreperror (13 मई को 28 मई 16 को उत्तर दिया गया है) के रूप में ऊपर दिए गए तरीके से registerModules का उपयोग करने की आवश्यकता है लेकिन ध्यान दें कि एक अंतर है। उल्लेख की गई निर्भरता को जोड़ने की आवश्यकता नहीं है क्योंकि मैं अनुमान लगा रहा हूं कि वसंत बूट पहले से ही है। मैं इस मुद्दे को स्प्रिंग बूट के साथ रख रहा था और इस निर्भरता को जोड़े बिना मेरे लिए यह काम कर रहा था।


1

स्प्रिंग बूट 2.x का उपयोग करने वालों के लिए

उपरोक्त में से कोई भी करने की आवश्यकता नहीं है - Java 8 LocalDateTime बॉक्स से क्रमबद्ध / de-serialized है। मुझे 1.x में उपरोक्त सभी करना था, लेकिन बूट 2.x के साथ, यह मूल रूप से काम करता है।

स्प्रिंग बूट में इस संदर्भ को भी JSON Java 8 LocalDateTime प्रारूप देखें


1

अगर किसी को भी उपयोग करते समय समस्या है SpringBoot को यहाँ मैंने नई निर्भरता को जोड़े बिना इस मुद्दे को कैसे तय किया।

में Spring 2.1.3जैक्सन दिनांक स्ट्रिंग को उम्मीद है 2019-05-21T07:37:11.000इस में yyyy-MM-dd HH:mm:ss.SSSमें de-क्रमानुसार करने प्रारूप LocalDateTime। मेक यकीन तारीख तार के साथ दिनांक और समय अलग करती है Tनहीं के साथ space। सेकंड ( ss) और मिलीसेकंड ( SSS) को ommitted किया जा सकता है।

@JsonProperty("last_charge_date")
public LocalDateTime lastChargeDate;

1

यदि आप जैक्सन सीरियलिज़र का उपयोग कर रहे हैं , तो यहां दिनांक मॉड्यूल का उपयोग करने का एक तरीका है:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.apache.kafka.common.serialization.Serializer;

public class JacksonSerializer<T> implements Serializer<T> {

    private final ObjectMapper mapper = new ObjectMapper()
            .registerModule(new ParameterNamesModule())
            .registerModule(new Jdk8Module())
            .registerModule(new JavaTimeModule());

    @Override
    public byte[] serialize(String s, T object) {
        try {
            return mapper.writeValueAsBytes(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

0

यदि आप फास्टजसन का उपयोग करने पर विचार करते हैं, तो आप अपनी समस्या को हल कर सकते हैं, संस्करण पर ध्यान दें

 <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.56</version>
 </dependency>

0

यदि आप ग्राफ़िकल जावा टूल्स के कारण इस समस्या को उठा रहे हैं और एक जावा को मार्शल करने की कोशिश कर रहे हैं Instant डेट स्ट्रिंग से , तो आपको कुछ कॉन्फ़िगरेशन के साथ एक ObjectMapper का उपयोग करने के लिए अपने स्कीमापार को सेटअप करने की आवश्यकता है:

अपने GraphQLSchemaBuilder वर्ग में, ObjectMapper को इंजेक्ट करें और इस मॉड्यूल को जोड़ें:

        ObjectMapper objectMapper = 
    new ObjectMapper().registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

और इसे विकल्पों में जोड़ें:

final SchemaParserOptions options = SchemaParserOptions.newOptions()
            .objectMapperProvider(fieldDefinition -> objectMapper)
            .typeDefinitionFactory(new YourTypeDefinitionFactory())
            .build();

Https://github.com/graphql-java-kickstart/graphql-spring-boot/issues/32 देखें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.