Custom Jackson serializers / deserializers configured with the ObjectMapper are working in Micronaut test but not working when testing with AWS SAM.
The enclosed sample is a working example generated from Micronaut Launcher that has been modified to make it easier to reproduce issue. Changes made are:
Book POJO class does not have a public constructor but the static factory method instead
@Introspected
public class Book {
...
// public Book() {
// }
...
public static Book ofName(String name) {
return new Book(name);
}
}
There is custom Book deserializer introduced
@Singleton
public class CustomBookDeserializer extends JsonDeserializer {
public CustomBookDeserializer() {
super();
}
@Override
public Book deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return Book.ofName("Mabe not Serverless");
}
}
The sample test is changed so it shows that the custom deserializer is taken to deserialize book payload
@Test
public void testHandler() throws JsonProcessingException {
final String json = "{ name: \"An old book\"}";
final ObjectMapper objectMapper = bookRequestHandler.getApplicationContext().getBean(ObjectMapper.class);
final Book book = objectMapper.readValue(json, Book.class);
see that custom Book deserializer is properly created in Micronaut context
see that JacksonMapper uses it to deserialize Book json
Configure AWS SAM locally and run enclosed cloudformation.yaml and see that it does not work anymore
Expected Behaviour
When testing with AWS SAM the standard Jackson ObjectMapper configured with custom deserialized is picked to deserialize the Book json payload.
Actual Behaviour
An error occurred during JSON parsing: java.lang.RuntimeException
java.lang.RuntimeException: An error occurred during JSON parsing
Caused by: java.io.UncheckedIOException: com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.example.Book]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: lambdainternal.util.NativeMemoryAsInputStream@61799544; line: 2, column: 3]
Caused by: com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.example.Book]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: lambdainternal.util.NativeMemoryAsInputStream@61799544; line: 2, column: 3]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1106)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:296)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:133)
at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1511)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1102)
Custom Jackson serializers / deserializers configured with the ObjectMapper are working in Micronaut test but not working when testing with AWS SAM.
The enclosed sample is a working example generated from Micronaut Launcher that has been modified to make it easier to reproduce issue. Changes made are:
@Introspected public class Book {
... // public Book() { // }
... public static Book ofName(String name) { return new Book(name); } }
There is custom Book deserializer introduced @Singleton public class CustomBookDeserializer extends JsonDeserializer {
public CustomBookDeserializer() { super(); }
@Override public Book deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { return Book.ofName("Mabe not Serverless"); }
}
The sample test is changed so it shows that the custom deserializer is taken to deserialize book payload @Test public void testHandler() throws JsonProcessingException { final String json = "{ name: \"An old book\"}"; final ObjectMapper objectMapper = bookRequestHandler.getApplicationContext().getBean(ObjectMapper.class); final Book book = objectMapper.readValue(json, Book.class);
}
Steps to Reproduce
Expected Behaviour
When testing with AWS SAM the standard Jackson ObjectMapper configured with custom deserialized is picked to deserialize the Book json payload.
Actual Behaviour
An error occurred during JSON parsing: java.lang.RuntimeException java.lang.RuntimeException: An error occurred during JSON parsing Caused by: java.io.UncheckedIOException: com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.example.Book]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?) at [Source: lambdainternal.util.NativeMemoryAsInputStream@61799544; line: 2, column: 3] Caused by: com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.example.Book]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?) at [Source: lambdainternal.util.NativeMemoryAsInputStream@61799544; line: 2, column: 3] at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1106) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:296) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:133) at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1511) at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1102)
Environment Information
Example Application
https://bitbucket.org/blazejkarmelita/micronaut-jackson-issue/src/master/