I'm doing a quite usual task to integrate a remote JSON service in a spring application, what it seems to happen is that the ObjectMapper set into a ResteasyJackson2Provider behave differently from the same ObjectMapper used "manually":
@Service
public class MyService {
@Autowired
ObjectMapper objectMapper;
public MyItem getItemById(Long itemId) {
MyServiceClient client = getMyServiceClient("http://localhost:8888/myservice");
//Not Working
MyItem item = client.getItem(itemId);
//Working
String itemJson = client.getItemJson(itemId);
MyItem itemFromJson = objectMapper.readValue(itemJson, MyItem.class);
return item;
}
private MyServiceClient getMyServiceClient(String serviceUrl) {
ResteasyJackson2Provider resteasyJacksonProvider = new ResteasyJackson2Provider();
resteasyJacksonProvider.setMapper(objectMapper);
ResteasyClient client = new ResteasyClientBuilder().register(resteasyJacksonProvider).build();
ResteasyWebTarget target = client
.target(UriBuilder.fromPath(serviceUrl));
MyServiceClient proxy = target.proxy(MyServiceClient.class);
return proxy;
}
}
When delegating the deserialisation to the proxy i get this error:
java.lang.reflect.InaccessibleObjectException: Unable to make field private final int java.time.LocalDate.year accessible: module java.base does not "opens java.time" to unnamed module @13e39c73
And from unit tests I made, this error happens when not including " .registerModule(new JavaTimeModule());" in object mapper.
But when I manually call the objectMapper.readValue() this does not happens, and the object is correctly deserialised.
here the code of the proxy interface methods:
@Path("/api")
public interface MyServiceClient {
@GET
@Path("/items/{id}")
MyItem getItem(@PathParam("id") Long id);
@GET
@Path("/items/{id}")
String getItemJson(@PathParam("id") Long id);
}
After other tests I did today, the problem is not the objectmapper itself, but is related to the resteasyJacksonProvider and its registration into the client builder.
Since, still don't know why, there's already a module registered of same class in the ResteasyClientBuilder, that second registration is being ignored.
So the instance used for data reading is an empty default mapper.