Explain Codes LogoExplain Codes Logo

Java 8 LocalDate Jackson format

java
date-formatting
jackson-serialization
localdate
Anton ShumikhinbyAnton Shumikhin·Oct 22, 2024
TLDR

To format LocalDate fields using Jackson, leverage the @JsonFormat annotation with the desired pattern. Remember to register the JavaTimeModule to handle Java 8 dates efficiently.

@JsonFormat(pattern = "yyyy-MM-dd") // Remember this pattern! It's kinda like a secret passcode. private LocalDate date;

Register the JavaTimeModule with your ObjectMapper and disable timestamps:

ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); // plug-in for our 3D Java 8 date-time printer objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // No digits, no problem. We don't need 'em.

Get rid of timezone troubles

Timezones can be quiet little troublemakers. Jackson operates in UTC by default. Let your DateTimeFormatter save you from the twilight zone.

@JsonFormat(pattern = "yyyy-MM-dd", timezone = "UTC") // We're on universal time. VERY universal. private LocalDate date;

Custom formats: breaking the mould

If ISO is too mainstream for you, custom serializer and deserializer can make your day:

// Custom serializer public class CustomLocalDateSerializer extends StdSerializer<LocalDate> { private static final DateTimeFormatter MY_FANCY_FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); public CustomLocalDateSerializer() { super(LocalDate.class); } @Override public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider sp) throws IOException { gen.writeString(value.format(MY_FANCY_FORMATTER)); // See how fancy that is? Top-hat level fancy. } } // Custom deserializer public class CustomLocalDateDeserializer extends StdDeserializer<LocalDate> { private static final DateTimeFormatter MY_FANCY_FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); public CustomLocalDateDeserializer(){ super(LocalDate.class); } @Override public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { return LocalDate.parse(p.getText(), MY_FANCY_FORMATTER); // This JSON is so fancy, it's monocled. } } @JsonSerialize(using = CustomLocalDateSerializer.class) @JsonDeserialize(using = CustomLocalDateDeserializer.class) private LocalDate date;

Unravel common issues

Facing issues? Just like in a mystery novel, check if all characters (dependencies) are trustworthy:

  • Is your version of jackson-databind getting along with jackson-datatype-jsr310?
  • If we're in Spring Boot town, the built-in dependency management might be your Sherlock.

And if things get 'elementary' (read: hard), enabling TRACE logging for com.fasterxml.jackson or even trying out JAXB annotations might yield some clues.

Under the hood: more on configurations

Be prepared to handle occasional plot-twists. Challenges can arise through:

  • Serialization of nulls: Jackson can serialize them as null or "", or even skip null fields - all depending on your configuration.
  • Arrays and Collections: Make sure JavaTimeModule is handy while serializing LocalDate within List or Array.
  • Different Locales: Expedition in different locales can give different results. Be ready with necessary configurations and travel guides (formatters).

Making peace with older systems

When dealing with older systems, consider:

  • Legacy Date Support: Configure Jackson to smoothly translate between LocalDate and older Date.
  • Non-standard Patterns: Have an unconventional date pattern? Use DateTimeFormatter inline with @JsonFormat.
  • Mixing Date Types: If your JSON is a cocktail of date types (LocalDate, LocalDateTime, etc.), ensure each has its format or drinks responsibly (custom serializer/deserializer).