Class com.fasterxml.jackson.datatype.joda.deser.DateTimeDeserializer has no default (no arg) constructor
Asked Answered
S

2

7

I am getting an error - 'Class com.fasterxml.jackson.datatype.joda.deser.DateTimeDeserializer has no default (no arg) constructor' while I am trying to call restangular for post request. When I call the method it goes in the error block.

Restangular.all('tests').post($scope.test).then(function (data) {
                    $scope.test.id = data.id;
                    $location.path($location.path() + data.id).replace();
                }, function (error) {
                    $scope.exceptionDetails = validationMapper(error);
                });

I am using jackson-datatype-joda - 2.6.5

The entity class used in this method as follows -

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@Entity
@Table(name = "Test")
@EqualsAndHashCode(of = "id", callSuper = false)
@ToString(exclude = {"keywords", "relevantObjectIds"})
public class Test {
    @Id
    @Column(unique = true, length = 36)
    private String id;

    @NotBlank
    @NotNull
    private String name;

    @Transient
    private List<Testabc> Testabcs = new ArrayList<>();

}

The entity class used in above entity Testabc class as follows

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@Slf4j
@Entity
@Table(name = "Test_abc")
@EqualsAndHashCode(of = "id", callSuper = false)
public class Testabc{
    @Id
    @Column(unique = true, length = 36)
    @NotNull
    private String id = UUID.randomUUID().toString();

 @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    @JsonDeserialize(using = DateTimeDeserializer.class)
    @JsonSerialize(using = DateTimeSerializer.class)
    private DateTime createdOn;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "Id")
    @NotNull
    private t1 pid;

    private long originalSize;
}

Finally resource class where I am requesting to create test data -

@ApiOperation(value = "Create new Test", notes = "Create a new Test and return with its unique id", response = Test.class)
    @POST
    @Timed
    public Test create(Test newInstance) {
        return super.create(newInstance);
    }

I have tried to add this @JsonIgnoreProperties(ignoreUnknown = true) annotation on entity class, but it doesn't work.

Can anyone help to resolve this problem?

Semela answered 18/7, 2016 at 9:42 Comment(5)
Possible duplicate of joda.time.DateTime deserialization errorGolconda
No there is no duplicacySemela
Does this mean that the explanation from the answer for the linked question and the suggested solution of mapper.registerModule(new JodaModule()); don't work for you?Golconda
This link (#36795651) suggests to use either annotation or above mentioned help , and I want to do this work with annotation only. do I need to use mapper.registerModule(new JodaModule()); with annotation?Semela
Both the solutions state that DateTimeDeserializer does not have a no-arg constructor, which is indeed your problem. If you want to use only annotations, you can simply extend the it yourself and add a no-arg constructor which calls super with the necessary parameters.Golconda
G
5

Looking at the latest sources of DateTimeDeserializer you can easily see that it does not have a no-arg constructor, which seems to be required by the framework. This is also indicated in both the linked questions: joda.time.DateTime deserialization error & Jackson, Retrofit, JodaTime deserialization

Since you want to use only an annotation based solution, a possible workaround would be to create your own deserializer which extends the DateTimeDeserializer and provides a nor-arg constructor.

1) MyDateTimeSerializer

import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig;
import com.fasterxml.jackson.datatype.joda.deser.DateTimeDeserializer;
import org.joda.time.DateTime;

public class MyDateTimeDeserializer extends DateTimeDeserializer {
    public MyDateTimeDeserializer() {
        // no arg constructor providing default values for super call
        super(DateTime.class, FormatConfig.DEFAULT_DATETIME_PARSER);
    }
}

2) AClass using the custom deserializer

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.joda.ser.DateTimeSerializer;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

public class AClass {

    @JsonSerialize(using = DateTimeSerializer.class) // old serializer
    @JsonDeserialize(using = MyDateTimeDeserializer.class) // new deserializer
    private DateTime createdOn = DateTime.now(DateTimeZone.UTC); // some dummy data for the sake of brevity

    public DateTime getCreatedOn() {
        return createdOn;
    }

    public void setCreatedOn(DateTime createdOn) {
        this.createdOn = createdOn;
    }
}

3) Unit test

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;

public class ATest {
    @Test
    public void testSomeMethod() throws Exception {
        // Jackson object mapper to test serialization / deserialization
        ObjectMapper objectMapper = new ObjectMapper();

        // our object
        AClass initialObject = new AClass();

        // serialize it
        String serializedObject = objectMapper.writeValueAsString(initialObject);

        // deserialize it
        AClass deserializedObject = objectMapper.readValue(serializedObject, AClass.class);

        // check that the dates are equal (no equals implementation on the class itself...)
        assertThat(deserializedObject.getCreatedOn(), is(equalTo(initialObject.getCreatedOn())));
    }
}
Golconda answered 18/7, 2016 at 15:52 Comment(6)
Thanks, but Its doesn't work, Still getting same errorSemela
@Geetanjali While it's possible, it's very unlikely you'd get the same exception after you changed something, because it would mean your modification had no impact whatsoever. Can you please clean your workspace/output folder, rebuild your app, then retry and share the exception message and the stacktrace?Golconda
Thanks for response, but I have tried your suggestion and make sure that I have build and clean app. One more thing is that I don't have any stack trace because the code breaks before even going to the java code, it just calls the error block of Restangular i.e 'Class com.fasterxml.jackson.datatype.joda.deser.DateTimeDeserializer has no default (no arg) constructor'.Semela
@Geetanjali If you've replaced DateTimeDeserializer with MyDateTimeDeserializer in your entity and you're getting the same exception, then the problem must be somewhere else. Under the circumstances, could you share a SSCCE of the backend on github or similar?Golconda
Sorry but I can't share my code as it is client code.Semela
@Geetanjali of course, that is a normal and understandable. Nonetheless, this is not what a SSCCE implies. On the contrary, it means creating from scratch the simplest example possible to reproduce your issue while leaving out any sensitive information. This way we can debug and spot anything out of the ordinary which you may have missed. Otherwise we can only keep guessing what it it that may have gone wrong, making things very difficult.Golconda
H
1

This deserializer was never meant to be used by annotations; and as others have mentioned, cannot. In general you really should just add/register JodaModule and serializer/deserializer gets added as expected.

I am not sure why you would not want to go that route; it might be worth expanding on why this solution (or registering deserializer you get by DateTimeDeserializer.forType(ReadableDateTime.class) through your custom module) is not applicable.

Hallerson answered 16/3, 2022 at 23:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.