Victor Mikhailov
Victor Mikhailov

Reputation: 125

How to serialize Java8 LocalDateTime to json as calendar object using Jackson

Im using jackson-datatype-jsr310 module, which supports LocalDateTime serialization. but by default, it serializes date/time as "[2022,6,29,17,15,54]".

But I need to override this behaviour to serialize/deserialize it in "Calendar" format, ex. as json object

"arrivalDate": {
  "month": "JUNE",
  "dayOfWeek": "WEDNESDAY",
  "dayOfYear": 180,
  "nano": 0,
  "year": 2022,
  "monthValue": 6,
  "dayOfMonth": 29,
  "hour": 12,
  "minute": 53,
  "second": 46,
  "chronology": {
    "id": "ISO",
    "calendarType": "iso8601"
  }
}

The setting should be not global for all application, but only for specific ObjectMapper instantiation for internal purposes.

Upvotes: 0

Views: 643

Answers (1)

Introduction

Let's consider Jackson 2.13.3 as the current version.

Analysis

Such feature seems to be absent out of the box

Please, see the following piece of source code and note the comment there: jackson-databind/BeanSerializerFactory.java at jackson-databind-2.13.3 · FasterXML/jackson-databind:

    protected JsonSerializer<?> _findUnsupportedTypeSerializer(SerializerProvider ctxt,
            JavaType type, BeanDescription beanDesc)
        throws JsonMappingException
    {
        // 05-May-2020, tatu: Should we check for possible Shape override to "POJO"?
        //   (to let users force 'serialize-as-POJO'?
        final String errorMsg = BeanUtil.checkUnsupportedType(type);

Maybe, it is worth opening the appropriate GitHub issue.

Possible workaround solution

Introduce and use a custom BeanSerializerFactory implementation that will not prevent using the default Jackson bean serializers for the JSR 310 types (the java.time package) and Joda types (the org.joda.time package).

To understand the idea, please, refer to the implementation of the methods:

  • com.fasterxml.jackson.databind.ser.BeanSerializerFactory._findUnsupportedTypeSerializer().
  • com.fasterxml.jackson.databind.util.BeanUtil.checkUnsupportedType().
  • com.fasterxml.jackson.databind.util.BeanUtil.isJava8TimeClass().

CustomBeanSerializerFactory class

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig;
import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;

public final class CustomBeanSerializerFactory extends BeanSerializerFactory {
    protected CustomBeanSerializerFactory(final SerializerFactoryConfig config) {
        super(config);
    }

    @Override
    protected JsonSerializer<?> _findUnsupportedTypeSerializer(
        final SerializerProvider ctxt,
        final JavaType type,
        final BeanDescription beanDesc
    ) {
        return null;
    }
}

Schedule class

import java.time.LocalDateTime;

public final class Schedule {
    private final LocalDateTime arrivalDate;

    public Schedule(final LocalDateTime arrivalDate) {
        this.arrivalDate = arrivalDate;
    }

    public LocalDateTime getArrivalDate() {
        return arrivalDate;
    }
}

Program class

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.LocalDateTime;

public final class Program {
    public static void main(final String[] args) throws JsonProcessingException {
        final LocalDateTime localDateTime = LocalDateTime.of(
            2022, 1, 2, 3, 4, 5, 6
        );
        final Schedule schedule = new Schedule(localDateTime);

        final ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializerFactory(
            new CustomBeanSerializerFactory(null)
        );
        final String jsonString = objectMapper.writeValueAsString(schedule);
        System.out.println(jsonString);
    }
}

The program output:

{"arrivalDate":{"nano":6,"year":2022,"monthValue":1,"dayOfMonth":2,"hour":3,"minute":4,"second":5,"month":"JANUARY","dayOfWeek":"SUNDAY","dayOfYear":2,"chronology":{"id":"ISO","calendarType":"iso8601"}}}

Additional references

Upvotes: 0

Related Questions