Jackson randevú

1. Áttekintés

Ebben az oktatóanyagban sorosítjuk a dátumokat Jackson-szal. Kezdjük egy egyszerű java.util sorosításával.Dátum, majd a Joda-Time, valamint a Java 8 Dátum idő.

2. Sorosítson Dátum az Időbélyegzőhöz

Először - nézzük meg, hogyan sorosíthatunk egy egyszerűt java.util.Dátum Jacksonnal.

A következő példában - sorosítjuk a „Esemény”Amelynek van Dátum terület "esemény dátum“:

@Test public void whenSerializingDateWithJackson_thenSerializedToTimestamp () dobja a JsonProcessingException, ParseException {SimpleDateFormat df = new SimpleDateFormat ("dd-MM-éééé hh: mm"); df.setTimeZone (TimeZone.getTimeZone ("UTC")); Dátum dátum = df.parse ("1970-01-01 01:00"); Esemény esemény = új esemény ("party", dátum); ObjectMapper mapper = új ObjectMapper (); mapper.writeValueAsString (esemény); }

Ami itt fontos, hogy Jackson a Dátumot alapértelmezés szerint időbélyeg formátumba sorolja (ezredmásodpercek száma 1970. január 1. óta, UTC).

A „esemény”A sorosítás:

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

3. Sorosítson Dátum az ISO-8601 szerint

Erre a rövid időbélyeg-formátumra való sorosítás nem optimális. Sorosítsuk most a Dátum hoz ISO-8601 formátum:

@Test public void whenSerializingDateToISO8601_thenSerializedToText () dobja a JsonProcessingException, ParseException {SimpleDateFormat df = new SimpleDateFormat ("dd-MM-éééé hh: mm"); df.setTimeZone (TimeZone.getTimeZone ("UTC")); String toParse = "1970-01-01 02:30"; Dátum dátum = df.parse (toParse); Esemény esemény = új esemény ("party", dátum); ObjectMapper mapper = új ObjectMapper (); mapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // Az StdDateFormat ISO8601, mivel a jackson 2.9 mapper.setDateFormat (új StdDateFormat (). WithColonInTimeZone (true)); Karakterlánc eredménye = mapper.writeValueAsString (esemény); assertThat (eredmény, tartalmazzaString ("1970-01-01T02: 30: 00.000 + 00: 00")); }

Vegye figyelembe, hogy a dátum ábrázolása hogyan olvashatóbb.

4. Konfigurálja ObjectMapperDátum formátum

A korábbi megoldások még mindig nem rendelkeznek teljes rugalmassággal a pontos formátum kiválasztására az ábrázoláshoz java.util.Dátum példányok.

Most nézzünk meg egy konfigurációt, amely lehetővé teszi számunkra állítsa be a dátumokat ábrázoló formátumunkat:

@Test public void whenSettingObjectMapperDateFormat_thenCorrect () dobja a JsonProcessingException, ParseException {SimpleDateFormat df = new SimpleDateFormat ("dd-MM-yyyy hh: mm"); String toParse = "2014.12.20. 02:30"; Dátum dátum = df.parse (toParse); Esemény esemény = új esemény ("party", dátum); ObjectMapper mapper = új ObjectMapper (); mapper.setDateFormat (df); Karakterlánc eredménye = mapper.writeValueAsString (esemény); assertThat (eredmény, tartalmazzaString (toParse)); }

Vegye figyelembe, hogy annak ellenére, hogy mostanra rugalmasabbak vagyunk a dátumformátum tekintetében - továbbra is globális konfigurációt használunk az egész szintjén ObjectMapper.

5. Használja @JsonFormat a Formázáshoz Dátum

Ezután vessünk egy pillantást a @JsonFormat annotáció a ellenőrizheti a dátum formátumát az egyes osztályokban globálisan, a teljes alkalmazás esetében:

public class Esemény {public String name; @JsonFormat (shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh: mm: ss") public Date eventDate; }

Most - teszteljük:

@Test public void whenUsingJsonFormatAnnotationToFormatDate_thenCorrect () dobja a JsonProcessingException, ParseException {SimpleDateFormat df = new SimpleDateFormat ("dd-MM-éééé hh: mm: ss"); df.setTimeZone (TimeZone.getTimeZone ("UTC")); String toParse = "2014.12.20. 02:30:00"; Dátum dátum = df.parse (toParse); Esemény esemény = új esemény ("party", dátum); ObjectMapper mapper = új ObjectMapper (); Karakterlánc eredménye = mapper.writeValueAsString (esemény); assertThat (eredmény, tartalmazzaString (toParse)); }

6. Egyedi Dátum Serializer

Következő - a kimenet teljes ellenőrzése érdekében a Dates egyedi sorosítóját használjuk:

public class A CustomDateSerializer kiterjeszti a StdSerializer {privát SimpleDateFormat formázó = új SimpleDateFormat ("dd-MM-éééé óó: pp: ss"); public CustomDateSerializer () {this (null); } public CustomDateSerializer (t osztály) {super (t); } @Orride public void serialize (Dátumérték, JsonGenerator gen, SerializerProvider arg2) dobja az IOException, JsonProcessingException {gen.writeString (formatter.format (érték)); }}

Következő - használjuk „esemény dátum" terület:

public class Esemény {public String name; @JsonSerialize (using = CustomDateSerializer.class) public Date eventDate; }

Végül - teszteljük:

@Test public void whenUsingCustomDateSerializer_thenCorrect () dobja a JsonProcessingException, ParseException {SimpleDateFormat df = új SimpleDateFormat ("dd-MM-yyyy hh: mm: ss"); String toParse = "2014.12.20. 02:30:00"; Dátum dátum = df.parse (toParse); Esemény esemény = új esemény ("party", dátum); ObjectMapper mapper = új ObjectMapper (); Karakterlánc eredménye = mapper.writeValueAsString (esemény); assertThat (eredmény, tartalmazzaString (toParse)); }

7. Serializálja a Joda-Time-ot Jacksonnal

A dátumok nem mindig jelennek meg java.util.Dátum; valójában - egyre inkább képviseli őket valamilyen más osztály - és egy közös természetesen az Dátum idő megvalósítás a Joda-Time könyvtárból.

Lássuk, hogyan tudunk sorosítani Dátum idő Jacksonnal.

Ki fogjuk használni a jackson-adattípus-joda modul a dobozon kívüli Joda-Time támogatáshoz:

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

És most egyszerűen regisztrálhatjuk a JodaModule és kész:

@Test public void whenSerializingJodaTime_thenCorrect () dobja a JsonProcessingException {DateTime date = new DateTime (2014, 12, 20, 2, 30, DateTimeZone.forID ("Európa / London")); ObjectMapper mapper = új ObjectMapper (); mapper.registerModule (új JodaModule ()); mapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); Karakterlánc eredménye = mapper.writeValueAsString (dátum); assertThat (eredmény, tartalmazzaString ("2014-12-20T02: 30: 00.000Z")); }

8. Serializálja a Jodát Dátum idő Egyéni Serializerrel

Ha nem akarunk extra Joda-Time Jackson-függőséget - használhatjuk is egyedi sorosító (hasonlóan a korábbi példákhoz) Dátum idő tisztán sorosított példányok:

public class A CustomDateTimeSerializer kiterjeszti az StdSerializer {private static DateTimeFormatter formatter = DateTimeFormat.forPattern ("éééé-hh-nn ÓÓ: mm"); public CustomDateTimeSerializer () {this (null); } public CustomDateTimeSerializer (t osztály) {super (t); } @Orride public void serialize (DateTime value, JsonGenerator gen, SerializerProvider arg2) dobja az IOException, JsonProcessingException {gen.writeString (formatter.print (érték)); }}

Következő - használjuk tulajdonként ”esemény dátum”Sorosító:

public class Esemény {public String name; @JsonSerialize (using = CustomDateTimeSerializer.class) public DateTime eventDate; }

Végül - rakjunk össze mindent és teszteljük:

@Test public void whenSerializingJodaTimeWithJackson_thenCorrect () dobja a JsonProcessingException {DateTime date = new DateTime (2014, 12, 20, 2, 30); Esemény esemény = új esemény ("party", dátum); ObjectMapper mapper = új ObjectMapper (); Karakterlánc eredménye = mapper.writeValueAsString (esemény); assertThat (eredmény, tartalmazzaString ("2014-12-20 02:30")); }

9. Serialize Java 8 Dátum Jacksonnal

Következő - lássuk, hogyan kell sorosítani a Java 8-at Dátum idő - ebben a példában LocalDateTime - Jackson segítségével. Használhatjuk a jackson-datatípus-jsr310 modul:

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

Most csak annyit kell tennünk, hogy regisztráljuk a JavaTimeModule (JSR310Modul elavult) és Jackson gondoskodik a többiről:

@Test public void whenSerializingJava8Date_thenCorrect () dobja a JsonProcessingException {LocalDateTime date = LocalDateTime.of (2014, 12, 20, 2, 30); ObjectMapper mapper = új ObjectMapper (); mapper.registerModule (új JavaTimeModule ()); mapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); Karakterlánc eredménye = mapper.writeValueAsString (dátum); assertThat (eredmény, tartalmazzaString ("2014-12-20T02: 30")); }

10. Serializálja a Java 8-at Dátum Minden különös függőség nélkül

Ha nem akarja az extra függőséget, mindig használhatja egyedi sorosító a Java 8 kiírására Dátum idő JSON-nak:

public class CustomLocalDateTimeSerializer kiterjeszti a StdSerializer {private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern ("éééé-hh-nn ÓÓ: mm"); public CustomLocalDateTimeSerializer () {this (null); } public CustomLocalDateTimeSerializer (t osztály) {super (t); } @Orride public void serialize (LocalDateTime érték, JsonGenerator gen, SerializerProvider arg2) dobja az IOException, JsonProcessingException {gen.writeString (formatter.format (érték)); }}

Következő - használjuk a sorosítót aesemény dátum" terület:

public class Esemény {public String name; @JsonSerialize (using = CustomLocalDateTimeSerializer.class) public LocalDateTime eventDate; }

Most - teszteljük:

@Test public void whenSerializingJava8DateWithCustomSerializer_thenCorrect () dobja a JsonProcessingException {LocalDateTime date = LocalDateTime.of (2014, 12, 20, 2, 30); Esemény esemény = új esemény ("party", dátum); ObjectMapper mapper = új ObjectMapper (); Karakterlánc eredménye = mapper.writeValueAsString (esemény); assertThat (eredmény, tartalmazzaString ("2014-12-20 02:30")); }

11. Deserializáljon Dátum

Következő - nézzük meg, hogyan lehet deserializálni a Dátum val vel Jackson. A következő példában - deserializálunk egy „Esemény”Dátumot tartalmazó példány:

@Test public void whenDeserializingDateWithJackson_thenCorrect () dobja a JsonProcessingException, IOException {String json = "{" name ":" party "," eventDate ":" 2014-12-20 02:30:00 "}"; SimpleDateFormat df = új SimpleDateFormat ("éééé-hh-éééé óó: pp: ss"); ObjectMapper mapper = új ObjectMapper (); mapper.setDateFormat (df); Esemény esemény = mapper.readerFor (Event.class) .readValue (json); assertEquals ("2014.12.20. 02:30:00", df.format (event.eventDate)); }

12. Dezerializálja Jodát ZonedDateTime Megőrzött időzónával

Alapértelmezés szerint Jackson beállítja a Joda időzónáját ZonedDateTime a helyi kontextus időzónájához. Mivel alapértelmezés szerint a helyi kontextus időzónája nincs beállítva, és manuálisan kell konfigurálni, Jackson az időzónát GMT-re állítja:

@Test public void whenDeserialisingZonedDateTimeWithDefaults_thenNotCorrect () dobja az IOException {ObjectMapper objectMapper = new ObjectMapper (); objectMapper.findAndRegisterModules (); objectMapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); ZonedDateTime now = ZonedDateTime.now (ZoneId.of ("Európa / Berlin")); Karakterlánc átalakítva = objectMapper.writeValueAsString (most); ZonedDateTime helyreállítva = objectMapper.readValue (konvertálva, ZonedDateTime.class); System.out.println ("sorosítva:" + most); System.out.println ("helyreállítva:" + visszaállítva); assertThat (most van (visszaállítva)); }

Ez a tesztesemény meghiúsul a kimenettel:

sorosítva: 2017-08-14T13: 52: 22.071 + 02: 00 [Európa / Berlin] visszaállítva: 2017-08-14T11: 52: 22.071Z [UTC]

Szerencsére van egy gyors és egyszerű javítás erre a furcsa alapértelmezett viselkedésre: csak el kell mondanunk Jacksonnak, hogy ne állítsuk be az időzónát.

Ez úgy tehető meg, hogy az alábbi kódsort hozzáadja a fenti tesztesethez:

objectMapper.disable (DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

Ne feledje, hogy az időzóna megőrzése érdekében le kell tiltanunk a dátum időbélyegzővé történő sorosításának alapértelmezett viselkedését is.

13. Egyedi Dátum Deserializer

Lássuk azt is, hogyan kell használni szokás Dátum deserializer; írunk egy egyedi deserializer-t az ingatlanhoz “esemény dátum“:

public class CustomDateDeserializer kiterjeszti a StdDeserializer {privát SimpleDateFormat formázó = új SimpleDateFormat ("dd-MM-éééé óó: pp: ss"); public CustomDateDeserializer () {this (null); } public CustomDateDeserializer (vc osztály) {super (vc); } @Orride public Date deserialize (JsonParser jsonparser, DeserializationContext context) dobja az IOException, JsonProcessingException {String date = jsonparser.getText (); próbáld ki a {return formatter.parse (dátum); } catch (ParseException e) {dobjon új RuntimeException (e); }}}

Következő - használjuk „esemény dátumDeserializer:

public class Esemény {public String name; @JsonDeserialize (using = CustomDateDeserializer.class) public Date eventDate; }

És végül - teszteljük:

@Test public void whenDeserializingDateUsingCustomDeserializer_thenCorrect () dobja a JsonProcessingException, IOException {String json = "{" name ":" party "," eventDate ":" 2014-12-20 02:30:00 "}"; SimpleDateFormat df = új SimpleDateFormat ("éééé-hh-éééé óó: pp: ss"); ObjectMapper mapper = új ObjectMapper (); Esemény esemény = mapper.readerFor (Event.class) .readValue (json); assertEquals ("2014.12.20. 02:30:00", df.format (event.eventDate)); }

14. Rögzítés InvalidDefinitionKivétel

A LocalDate Például találkozhatunk egy kivétellel:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Nem lehet elkészíteni a `java.time.LocalDate` példányát (nincsenek alkotók, mint például az alapértelmezett konstrukció): nincs String-argumentum konstruktor / gyári módszer a String értékből deserializálni ('2014 -12-20 ') a [Forrás: (String) "2014-12-20"; sor: 1, oszlop: 1]

Ez a probléma azért merül fel, mert a JSON-nak nincs natív dátumformátuma, ezért a dátumokat mint Húr.

A Húr a dátum ábrázolása nem azonos típusú objektummal LocalDate a memóriában, ezért szükségünk van egy külső deserializátorra, hogy leolvassuk azt a mezőt a-ból Húr, és egy sorosítót a dátum visszaadásához Húr formátum.

Ezek a módszerek a következőkre is vonatkoznak LocalDateTime - az egyetlen változás az egyenértékű osztály használata a LocalDateTime.

14.1. Jackson-függőség

Jackson lehetővé teszi számunkra, hogy ezt néhány módon kijavítsuk. Először is meg kell győződnünk a jsr310 függőség a mi pom.xml:

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

14.2. Sorosítás egyetlen dátumú objektumra

Annak érdekében, hogy kezelni tudja LocalDate, regisztrálnunk kell a JavaTimeModule velünk ObjectMapper.

A funkciót is letiltjuk WRITE_DATES_AS_TIMESTAMPS ban ben ObjectMapper megakadályozni, hogy Jackson időszámokat adjon a JSON kimenethez:

@Test public void whenSerializingJava8DateAndReadingValue_thenCorrect () dobja az IOException {String stringDate = "\" 2014-12-20 \ ""; ObjectMapper mapper = új ObjectMapper (); mapper.registerModule (új JavaTimeModule ()); mapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); LocalDate eredmény = mapper.readValue (stringDate, LocalDate.class); assertThat (eredmény.toString (), tartalmazzaString ("2014-12-20")); }

Itt felhasználtuk Jackson natív támogatását a dátumok sorosításához és dezerializálásához.

14.3. Megjegyzés a POJO-ban

A probléma kezelésének másik módja a LocalDateDeserializer és JsonFormat jelölések entitás szinten:

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

A @JsonDeserialize annotációval megadható egy egyedi deserializer a JSON objektum széthúzásához. Hasonlóképpen, @JsonSerialize az entitás marsallálásakor használandó egyedi sorosítót jelöl.

Ezen felül az annotáció @JsonFormat lehetővé teszi számunkra, hogy meghatározzuk a dátumértékek sorosítási formátumát. Ezért ez a POJO használható a JSON beolvasására és megírására:

@Test public void whenSerializingJava8DateAndReadingFromEntity_thenCorrect () IOException {String json = "{\" name \ ": \" party \ ", \" eventDate \ ": \" 20-12-2014 \ "}"; ObjectMapper mapper = új ObjectMapper (); EventWithLocalDate eredmény = mapper.readValue (json, EventWithLocalDate.class); assertThat (result.getEventDate (). toString (), tartalmazString ("2014-12-20")); }

Bár ez a megközelítés több munkát igényel, mint a JavaTimeModule alapértelmezés szerint sokkal testreszabhatóbb.

15. Következtetés

Ebben a kiterjedt Dátum cikket, többféleképpen is megvizsgáltuk Jackson segíthet a marsallnak és a marhának a JSON-ra való randevúban egy értelmes formátum használatával, amely felett rendelkezünk.

Mint mindig, a példakód megtalálható a GitHubon.


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