Jackson Date

1. Prehľad

V tomto tutoriáli budeme serializovať dátumy s Jacksonom. Začneme serializáciou jednoduchého súboru java.util.Dátum, potom Joda-Time a tiež Java 8 Dátum Čas.

2. Serializujte Dátum do časovej pečiatky

Po prvé - pozrime sa, ako serializovať jednoduchý java.util.Date s Jacksonom.

V nasledujúcom príklade - budeme serializovať inštanciu „Udalosť”Ktorý má a Dátum lúka "dátum udalosti“:

@Test public void whenSerializingDateWithJackson_thenSerializedToTimestamp () hodí JsonProcessingException, ParseException {SimpleDateFormat df = new SimpleDateFormat ("dd-MM-rrrr hh: mm"); df.setTimeZone (TimeZone.getTimeZone ("UTC")); Dátum dátum = df.parse ("01-01-1970 01:00"); Udalosť udalosti = nová udalosť („párty“, dátum); ObjectMapper mapovač = nový ObjectMapper (); mapper.writeValueAsString (udalosť); }

Dôležité je tu to, že Jackson bude štandardne serializovať dátum do formátu časovej pečiatky (počet milisekúnd od 1. januára 1970, UTC).

Skutočný výstup „udalosť”Serializácia je:

{"name": "party", "eventDate": 3600000}

3. Serializujte Dátum podľa ISO-8601

Serializácia do tohto stručného formátu časovej pečiatky nie je optimálna. Poďme teraz serializovať Dátum do ISO-8601 formát:

@ Test public void whenSerializingDateToISO8601_thenSerializedToText () vyvolá JsonProcessingException, ParseException {SimpleDateFormat df = new SimpleDateFormat ("dd-MM-rrrr hh: mm"); df.setTimeZone (TimeZone.getTimeZone ("UTC")); Reťazec toParse = "01.01.1970 02:30"; Dátum dátum = df.parse (toParse); Udalosť udalosti = nová udalosť („párty“, dátum); ObjectMapper mapovač = nový ObjectMapper (); mapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // StdDateFormat je ISO8601 od jacksona 2.9 mapper.setDateFormat (nový StdDateFormat (). WithColonInTimeZone (true)); Výsledok reťazca = mapper.writeValueAsString (udalosť); assertThat (result, containsString ("1970-01-01T02: 30: 00.000 + 00: 00")); }

Všimnite si, ako je teraz znázornenie dátumu oveľa čitateľnejšie.

4. Konfigurovať ObjectMapperFormát dátumu

Predchádzajúcim riešeniam stále chýba úplná flexibilita výberu presného formátu, ktorý predstavuje java.util.Date inštancie.

Poďme sa teraz pozrieť na konfiguráciu, ktorá nám to umožní nastavte naše formáty na reprezentáciu dátumov:

@Test public void whenSettingObjectMapperDateFormat_thenCorrect () hodí JsonProcessingException, ParseException {SimpleDateFormat df = new SimpleDateFormat ("dd-MM-rrrr hh: mm"); Reťazec toParse = "20-12-2014 02:30"; Dátum dátum = df.parse (toParse); Udalosť udalosti = nová udalosť („párty“, dátum); ObjectMapper mapovač = nový ObjectMapper (); mapper.setDateFormat (df); Výsledok reťazca = mapper.writeValueAsString (udalosť); assertThat (result, containsString (toParse)); }

Upozorňujeme, že aj keď sme teraz flexibilnejší, pokiaľ ide o formát dátumu, stále používame globálnu konfiguráciu na úrovni celého ObjectMapper.

5. Použite @JsonFormat do formátu Dátum

Ďalej sa pozrime na @JsonFormat anotácia k kontrolovať formát dátumu v jednotlivých triedach namiesto globálne pre celú aplikáciu:

public class Event {public Názov reťazca; @JsonFormat (shape = JsonFormat.Shape.STRING, pattern = "dd-MM-rrrr hh: mm: ss") public Date eventDate; }

Teraz - otestujme to:

@Test public void whenUsingJsonFormatAnnotationToFormatDate_thenCorrect () vyvolá JsonProcessingException, ParseException {SimpleDateFormat df = new SimpleDateFormat ("dd-MM-rrrr hh: mm: ss"); df.setTimeZone (TimeZone.getTimeZone ("UTC")); String toParse = "20-12-2014 02:30:00"; Dátum dátum = df.parse (toParse); Udalosť udalosti = nová udalosť („párty“, dátum); ObjectMapper mapovač = nový ObjectMapper (); Výsledok reťazca = mapper.writeValueAsString (udalosť); assertThat (result, containsString (toParse)); }

6. Vlastné Dátum Serializátor

Ďalej - aby sme získali úplnú kontrolu nad výstupom, využijeme vlastný serializátor pre Dátumy:

verejná trieda CustomDateSerializer rozširuje StdSerializer {private SimpleDateFormat formatter = nový SimpleDateFormat ("dd-MM-rrrr hh: mm: ss"); public CustomDateSerializer () {this (null); } public CustomDateSerializer (trieda t) {super (t); } @Override public void serialize (hodnota dátumu, JsonGenerator gen, SerializerProvider arg2) hodí IOException, JsonProcessingException {gen.writeString (formatter.format (hodnota)); }}

Ďalej - použijeme ho ako serializátor nášho „dátum udalosti" lúka:

public class Event {public Názov reťazca; @JsonSerialize (using = CustomDateSerializer.class) public Date eventDate; }

Nakoniec - otestujme to:

@Test public void whenUsingCustomDateSerializer_thenCorrect () vyvolá JsonProcessingException, ParseException {SimpleDateFormat df = new SimpleDateFormat ("dd-MM-rrrr hh: mm: ss"); String toParse = "20-12-2014 02:30:00"; Dátum dátum = df.parse (toParse); Udalosť udalosti = nová udalosť („párty“, dátum); ObjectMapper mapovač = nový ObjectMapper (); Výsledok reťazca = mapper.writeValueAsString (udalosť); assertThat (result, containsString (toParse)); }

7. Serializujte Joda-Time s Jacksonom

Dátumy nie sú vždy príkladom java.util.Date; vlastne - čoraz viac ich reprezentuje nejaká iná trieda - a tou bežnou je samozrejme Dátum Čas implementácia z knižnice Joda-Time.

Pozrime sa, ako môžeme serializovať Dátum Čas s Jacksonom.

Využijeme jackson-datatype-joda modul pre out-of-the-box podporu Joda-Time:

 com.fasterxml.jackson.datatype jackson-datatype-joda 2.9.7 

A teraz môžeme jednoducho zaregistrovať JodaModule a urobte:

@Test public void whenSerializingJodaTime_thenCorrect () throws JsonProcessingException {DateTime date = new DateTime (2014, 12, 20, 2, 30, DateTimeZone.forID ("Europe / London")); ObjectMapper mapovač = nový ObjectMapper (); mapper.registerModule (nový JodaModule ()); mapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); Výsledok reťazca = mapper.writeValueAsString (dátum); assertThat (result, containsString ("2014-12-20T02: 30: 00.000Z")); }

8. Serializuj Jodu Dátum Čas S vlastným serializátorom

Ak nechceme extra závislosť od Joda-Time Jacksona - môžeme tiež využiť vlastný serializátor (podobne ako predchádzajúce príklady) získať Dátum Čas inštancie čisto serializované:

verejná trieda CustomDateTimeSerializer rozširuje StdSerializer {private static DateTimeFormatter formatter = DateTimeFormat.forPattern ("rrrr-MM-dd HH: mm"); public CustomDateTimeSerializer () {this (null); } public CustomDateTimeSerializer (trieda t) {super (t); } @Override public void serialize (hodnota DateTime, JsonGenerator gen, SerializerProvider arg2) hodí IOException, JsonProcessingException {gen.writeString (formatter.print (hodnota)); }}

Ďalej - využime to ako svoje vlastníctvo “dátum udalosti”Serializátor:

public class Event {public Názov reťazca; @JsonSerialize (using = CustomDateTimeSerializer.class) public DateTime eventDate; }

Na záver - dajme všetko dohromady a otestujme:

@Test public void whenSerializingJodaTimeWithJackson_thenCorrect () hodí JsonProcessingException {DateTime date = new DateTime (2014, 12, 20, 2, 30); Udalosť udalosti = nová udalosť („párty“, dátum); ObjectMapper mapovač = nový ObjectMapper (); Výsledok reťazca = mapper.writeValueAsString (udalosť); assertThat (result, containsString ("2014-12-20 02:30")); }

9. Serializujte Javu 8 Dátum S Jacksonom

Ďalej - pozrime sa, ako serializovať Java 8 Dátum Čas - v tomto príklade LocalDateTime - pomocou Jacksona. Môžeme využiť jackson-datatype-jsr310 modul:

 com.fasterxml.jackson.datatype jackson-datatype-jsr310 2.9.7 

Všetko, čo musíme urobiť, je zaregistrovať JavaTimeModule (Modul JSR310 je zastaraný) a o zvyšok sa postará Jackson:

@Test public void whenSerializingJava8Date_thenCorrect () hodí JsonProcessingException {LocalDateTime date = LocalDateTime.of (2014, 12, 20, 2, 30); ObjectMapper mapovač = nový ObjectMapper (); mapper.registerModule (nový JavaTimeModule ()); mapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); Výsledok reťazca = mapper.writeValueAsString (dátum); assertThat (result, containsString ("2014-12-20T02: 30")); }

10. Serializujte Javu 8 Dátum Bez akejkoľvek ďalšej závislosti

Ak nechcete ďalšiu závislosť, môžete kedykoľvek použiť vlastný serializátor na zápis Java 8 Dátum Čas spoločnosti JSON:

public class CustomLocalDateTimeSerializer rozširuje StdSerializer {private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern ("rrrr-MM-dd HH: mm"); public CustomLocalDateTimeSerializer () {this (null); } public CustomLocalDateTimeSerializer (trieda t) {super (t); } @Override public void serialize (hodnota LocalDateTime, JsonGenerator gen, SerializerProvider arg2) hodí IOException, JsonProcessingException {gen.writeString (formatter.format (hodnota)); }}

Ďalej - použijeme serializátor pre našu „dátum udalosti" lúka:

public class Event {public Názov reťazca; @JsonSerialize (using = CustomLocalDateTimeSerializer.class) public LocalDateTime eventDate; }

Teraz - otestujme to:

@Test public void whenSerializingJava8DateWithCustomSerializer_thenCorrect () hodí JsonProcessingException {LocalDateTime date = LocalDateTime.of (2014, 12, 20, 2, 30); Udalosť udalosti = nová udalosť („párty“, dátum); ObjectMapper mapovač = nový ObjectMapper (); Výsledok reťazca = mapper.writeValueAsString (udalosť); assertThat (result, containsString ("2014-12-20 02:30")); }

11. Deserializovať Dátum

Ďalej - pozrime sa, ako deserializovať a Dátum s Jackson. V nasledujúcom príklade - deserializujeme „Udalosť”Inštancia obsahujúca dátum:

@Test public void whenDeserializingDateWithJackson_thenCorrect () hodí JsonProcessingException, IOException {String json = "{" name ":" party "," eventDate ":" 20-12-2014 02:30:00 "}"; SimpleDateFormat df = nový SimpleDateFormat ("dd-MM-rrrr hh: mm: ss"); ObjectMapper mapovač = nový ObjectMapper (); mapper.setDateFormat (df); Udalosť event = mapper.readerFor (Event.class) .readValue (json); assertEquals ("20-12-2014 02:30:00", df.format (event.eventDate)); }

12. Deserializujte Jodu ZonedDateTime So zachovaným časovým pásmom

Vo svojej predvolenej konfigurácii upravuje Jackson časové pásmo Jody ZonedDateTime do časového pásma miestneho kontextu. Pretože predvolene nie je časové pásmo miestneho kontextu nastavené a je potrebné ho nakonfigurovať manuálne, upraví Jackson časové pásmo na GMT:

@Test public void whenDeserialisingZonedDateTimeWithDefaults_thenNotCorrect () hodí IOException {ObjectMapper objectMapper = new ObjectMapper (); objectMapper.findAndRegisterModules (); objectMapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); ZonedDateTime now = ZonedDateTime.now (ZoneId.of ("Európa / Berlín")); Reťazec prevedený = objectMapper.writeValueAsString (teraz); ZonedDateTime obnovení = objectMapper.readValue (prevedené, ZonedDateTime.class); System.out.println ("serializované:" + teraz); System.out.println ("obnovený:" + obnovený); assertThat (teraz je (obnovený)); }

Tento testovací prípad zlyhá s výstupom:

serializované: 2017-08-14T13: 52: 22.071 + 02: 00 [Európa / Berlín] obnovené: 2017-08-14T11: 52: 22.071Z [UTC]

Našťastie existuje toto rýchle a jednoduché riešenie tohto zvláštneho predvoleného správania: Musíme len povedať Jacksonovi, aby neupravoval časové pásmo.

Môžete to urobiť tak, že do vyššie uvedeného testovacieho prípadu pridáte nasledujúci riadok kódu:

objectMapper.disable (DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

Upozorňujeme, že aby sme zachovali časové pásmo, musíme tiež zakázať predvolené správanie serializácie dátumu na časovú pečiatku.

13. Vlastné Dátum Deserializátor

Pozrime sa tiež, ako sa používa zvyk Dátum deserializátor; napíšeme vlastný deserializátor pre nehnuteľnosť “dátum udalosti“:

verejná trieda CustomDateDeserializer rozširuje StdDeserializer {private SimpleDateFormat formatter = nový SimpleDateFormat ("dd-MM-rrrr hh: mm: ss"); public CustomDateDeserializer () {this (null); } public CustomDateDeserializer (Class vc) {super (vc); } @Override public Date deserialize (JsonParser jsonparser, DeserializationContext kontext) vyvolá IOException, JsonProcessingException {String date = jsonparser.getText (); skus {vratit formatter.parse (date); } catch (ParseException e) {throw new RuntimeException (e); }}}

Ďalej - použijeme to ako „dátum udalosti”Deserializátor:

public class Event {public Názov reťazca; @JsonDeserialize (using = CustomDateDeserializer.class) public Date eventDate; }

A na záver - otestujme to:

@ Test public void whenDeserializingDateUsingCustomDeserializer_thenCorrect () vyvolá JsonProcessingException, IOException {String json = "{" name ":" party "," eventDate ":" 20-12-2014 02:30:00 "}"; SimpleDateFormat df = nový SimpleDateFormat ("dd-MM-rrrr hh: mm: ss"); ObjectMapper mapovač = nový ObjectMapper (); Udalosť event = mapper.readerFor (Event.class) .readValue (json); assertEquals ("20-12-2014 02:30:00", df.format (event.eventDate)); }

14. Upevnenie InvalidDefinitionVýnimka

Pri vytváraní a LocalDate napríklad môžeme naraziť na výnimku:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Nie je možné vytvoriť inštanciu `java.time.LocalDate` (neexistujú žiadni tvorcovia, ako je predvolená konštrukcia): žiadna konštruktér / továrenská metóda argumentu reťazca na deserializáciu z hodnoty reťazca ('2014 -12-20 ') o [Zdroj: (String) „2014-12-20“; riadok: 1, stĺpec: 1]

Tento problém sa vyskytuje, pretože JSON nemá natívne formát dátumu, takže predstavuje dátumy ako String.

The String reprezentácia dátumu nie je to isté ako objekt typu LocalDate v pamäti, takže na načítanie tohto poľa z a potrebujeme externý deserializátor Stringa serializátor na vykreslenie dátumu na String formát.

Tieto metódy platia aj pre LocalDateTime - jedinou zmenou je použitie ekvivalentnej triedy pre LocalDateTime.

14.1. Jacksonova závislosť

Jackson nám umožňuje opraviť to niekoľkými spôsobmi. Najskôr sa musíme uistiť, že jsr310 závislosť je v našom pom.xml:

 com.fasterxml.jackson.datatype jackson-datatype-jsr310 2.11.0 

14.2. Serializácia na objekt s jedným dátumom

Aby sme to zvládli LocalDate, musíme zaregistrovať JavaTimeModule s našim ObjectMapper.

Funkciu tiež deaktivujeme WRITE_DATES_AS_TIMESTAMPS v ObjectMapper ako zabrániť Jacksonovi v pridávaní časových číslic do výstupu JSON:

@ Test public void whenSerializingJava8DateAndReadingValue_thenCorrect () vyvolá IOException {String stringDate = "\" 20.12.2014 \ ""; ObjectMapper mapovač = nový ObjectMapper (); mapper.registerModule (nový JavaTimeModule ()); mapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); Výsledok LocalDate = mapper.readValue (stringDate, LocalDate.class); assertThat (result.toString (), containsString ("2014-12-20")); }

Tu sme použili Jacksonovu natívnu podporu pre serializáciu a deserializáciu dátumov.

14.3. Anotácia v POJO

Ďalším spôsobom, ako sa vysporiadať s týmto problémom, je použitie LocalDateDeserializer a JsonFormat anotácie na úrovni entity:

verejná trieda EventWithLocalDate {@JsonDeserialize (using = LocalDateDeserializer.class) @JsonSerialize (using = LocalDateSerializer.class) @JsonFormat (shape = JsonFormat.Shape.STRING, pattern = "dd-MM-rrrr") public LocalDate eventDate }

The @JsonDeserialize anotácia sa používa na zadanie vlastného deserializátora na zrušenie zaradenia objektu JSON. Podobne @JsonSerialize označuje vlastný serializátor, ktorý sa má použiť pri zaraďovaní entity.

Okrem toho anotácia @JsonFormat nám umožňuje určiť formát, do ktorého budeme serializovať hodnoty dátumu. Preto je možné tento POJO použiť na čítanie a zápis JSON:

@ Test public void whenSerializingJava8DateAndReadingFromEntity_thenCorrect () vyvolá IOException {String json = "{\" name \ ": \" party \ ", \" eventDate \ ": \" 20-12-2014 \ "}"; ObjectMapper mapovač = nový ObjectMapper (); EventWithLocalDate result = mapper.readValue (json, EventWithLocalDate.class); assertThat (result.getEventDate (). toString (), containsString ("2014-12-20")); }

Aj keď tento prístup vyžaduje viac práce ako použitie JavaTimeModule predvolené hodnoty, je oveľa prispôsobiteľnejšie.

15. Záver

V tomto rozsiahlom Dátum článku sme sa pozreli na niekoľko spôsobov Jackson môže pomôcť zaradiť a zrušiť rande s JSON pomocou rozumného formátu máme kontrolu nad.

Ako vždy, príkladový kód nájdete na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found