3

I have a RestEasyClient that has to deserialize an object that has a java.time.Instant inside. I tried to register the new JavaTimeModule from jsr310 but still got errors:

    ObjectMapper mapper = new ObjectMapper()
            .registerModule(new JavaTimeModule());

    ResteasyClient client = new ResteasyClientBuilder()
            .register(mapper)
            .build();
    ResteasyWebTarget target = client.target(UriBuilder.fromPath(SERVICE_URL + "/api"));

Error:

Can not construct instance of java.time.Instant: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)

After modifying Rest Server to properly serialize the Instant class (ex: "fromTime": 1525681860)

New Error:

Can not construct instance of java.time.Instant: no double/Double-argument constructor/factory method to deserialize from Number value (1.52568186E9)

I managed to simulate this:

    ObjectMapper deserializer = new ObjectMapper()
            .registerModule(new JavaTimeModule());

    Instant probe = deserializer.readValue("1525681860", Instant.class);
    System.out.println(probe);

If I remove the "registerModule" line, I get the same error.

Therefore, the conclusion is that RestEasyClient not registering the module. I am definitely doing something wrong.

kellyfj
  • 6,586
  • 12
  • 45
  • 66
Mircea Stanciu
  • 3,675
  • 3
  • 34
  • 37

1 Answers1

4

You could define a ContextResolver for ObjectMapper:

public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

    private final ObjectMapper mapper;

    public ObjectMapperContextResolver() {
        this.mapper = createObjectMapper();
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }

    private ObjectMapper createObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        return mapper;
    }
}

And then register the resolver in your client instance:

ResteasyClient client = new ResteasyClientBuilder()
    .register(ObjectMapperContextResolver.class).build();

Alternatively you could register an instance of JacksonJsonProvider. This class is the basic implementation of JAX-RS abstractions (MessageBodyReader and MessageBodyWriter) needed for binding JSON content to and from Java objects.

You can use the constructor that accepts an ObjectMapper instance.

cassiomolin
  • 124,154
  • 35
  • 280
  • 359
  • 1
    Thank's so much. I was pulling my hair yesterday night making on rest api to serialise correctly and another module to consume correctly. I was missing the registering of the resolver in a proper way. Had the Context Resolver in the producer and worked well, but my deserialisation was not done because Jackson didn't know how to construct the object – Mircea Stanciu May 07 '18 at 21:27