Hitesh Kirtane
Hitesh Kirtane

Reputation: 83

How to implement Java 8 LocalTimeDeserializer?

I have been looking for implementing a custom deserializer using LocalTimeDeserializer class of Jackson API.

However, I am getting below error while actually deserializing properties using this class.

com.fasterxml.jackson.databind.JsonMappingException: Class com.dspim.api.common.LocalTimeWithStringDeserializer has no default (no arg) constructor

I am using the custom implementation as below for deserializing inside the bean class.

@JsonProperty @JsonDeserializer(using=LocalTimeWithStringDeserializer.class) private LocalTime packaging_time; //It will hold value for time i.e. 13:24 (01:24 PM).

I have implemented the deserializer class as follows.

package com.testapp.test;

import java.io.IOException;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;

public class LocalTimeWithStringDeserializer extends com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer{
    
    public LocalTimeWithStringDeserializer(DateTimeFormatter formatter) {
        super(formatter);
    }

    private static final long serialVersionUID = 1L;
    
    @Override
    public LocalTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
            JsonProcessingException {
        
        return LocalTime.parse(jp.getText());
    }

}

The default constructor (with no arguments) in the parent class is private, thus I cannot add a default constructor (with no arguments) to my class implementation as I get compile time error.

Please suggest a solution for this issue.

Please Note: I have two different projects (having dependency on each other added to the classpath) of a client in which I cannot use the built in Jackson deserializer due to dependency version conflicts, that's why I have been compelled to use custom deserializer.

Upvotes: 0

Views: 755

Answers (3)

Sacky San
Sacky San

Reputation: 1672

I use LocalTime deserializer in my project and link it for the JSOG/JSON to deserialize when API layer gets called. I declare it using an annotation in the model layer above the field i want to deserialize. I use jackson.databind.JsonDeserializer and it works well for me`.

Here is the code I use:

import java.io.IOException;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

public class CustomJacksonLocalTimeDeserializer extends JsonDeserializer<LocalTime> {

    @Override
    public LocalTime deserialize(JsonParser jsonparser, DeserializationContext context)
            throws IOException, JsonProcessingException {
        String dateAsString = jsonparser.getText();
        try {
            return LocalTime.parse(dateAsString, DateTimeFormatter.ISO_LOCAL_TIME);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

You also need to annotate it on the field as follows:

@JsonDeserialize(using = CustomJacksonLocalTimeDeserializer.class)
@JsonSerialize(using = CustomJacksonLocalTimeSerializer.class)
@Column(columnDefinition = "TIMESTAMP")
private LocalTime origHardScheduledTime;

I know, you did not ask for it, but for the completion's sake, a serializer would also look similar.

import java.io.IOException;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class CustomJacksonLocalTimeSerializer extends JsonSerializer<LocalTime> {
    
    @Override
    public void serialize(LocalTime date, JsonGenerator jsonGenerator, SerializerProvider serializers)
            throws IOException, JsonProcessingException {       
        jsonGenerator.writeString(date.format(DateTimeFormatter.ISO_LOCAL_TIME));
    }
}

Upvotes: 0

Michael Gantman
Michael Gantman

Reputation: 7808

Maybe you don't need your own deserializer. All you need to do is to anotate your LocalTime member with the following anotation:

static class Entity {
    LocalTime time;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss")
    public LocalTime getTime() {
        return time;
    }
}

This should work. See the answer to this question: Spring Data JPA - ZonedDateTime format for json serialization

Upvotes: 0

tucuxi
tucuxi

Reputation: 17955

If the parent class has a private no-args constructor, that does not prohibit you from having a no-args constructor yourself:

public class LocalTimeWithStringDeserializer extends com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer{

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");

    public LocalTimeWithStringDeserializer() {
        super(formatter);
    }

    // ...
}

Upvotes: 3

Related Questions