'Deserializing LocalDateTime inside Spring Batch Execution Context with Jackson2ExecutionContextStringSerializer
My Spring Batch job was working prior to upgrading Spring Boot to 2.6.6 from 2.4.4. After the upgrade, I started getting errors about how my execution context could not be serialized:
Caused by: java.lang.IllegalArgumentException: Could not serialize the execution context...
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Type id handling not
implemented for type java.lang.Object (by serializer of type com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer)
(through reference chain: java.util.HashMap["test-reader.start.after"]->java.util.LinkedHashMap["CREATION_DATE"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1300)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
at com.fasterxml.jackson.databind.JsonSerializer.serializeWithType(JsonSerializer.java:160)...
After searching all over Stack Overflow, I learned it was an issue with Jackon and found several solutions involving JavaTimeModule as a module inside ObjectMapper that would go inside Jackson2ExecutionContextStringSerializer. This was my solution which was set inside the JobRepo and JobExplorer as a serializer:
private ExecutionContextSerializer getSerializer() {
ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
Jackson2ExecutionContextStringSerializer serializer = new Jackson2ExecutionContextStringSerializer(TRUSTED_CLASS_NAMES);
serializer.setObjectMapper(objectMapper);
return serializer;
}
This helped me resolve my serialization errors above and I was able to serialize my execution context to this json and it was saved in the SHORT_CONTEXT column inside the BATCH_STEP_EXECUTION table:
{"test-reader.start.after":{"CREATION_DATE":"2022-04-12T01:54:00"},"batch.taskletType":"org.springframework.batch.core.step.item.ChunkOrientedTasklet","test-reader.read.count":3,"batch.stepType":"org.springframework.batch.core.step.tasklet.TaskletStep"}
My main concern was how would it handle deserializing the LocalDateTime it serialized, would it deserialize the string back to a LocalDateTime:
{"CREATION_DATE":"2022-04-12T01:54:00"}
So I deserialized the json using the serializer above:
ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
Jackson2ExecutionContextStringSerializer serializer1 = new Jackson2ExecutionContextStringSerializer();
serializer1.setObjectMapper(objectMapper);
serializer1.deserialize(new ByteArrayInputStream("{\"test-reader.start.after\":{\"CREATION_DATE\":\"2022-04-12T01:54:00\"},\"batch.taskletType\":\"org.springframework.batch.core.step.item.ChunkOrientedTasklet\",\"scheduled-delivery-reader.read.count\":1,\"batch.stepType\":\"org.springframework.batch.core.step.tasklet.TaskletStep\"}"
.getBytes("ISO-8859-1")));
It deserialized but it did not put back into a LocalDateTime:
It left "2022-04-12T01:54:00" as a String... I'm worried there will be issues when the the Execution Context is read from the table. How can I get "2022-04-12T01:54:00" deserialized back into a LocalDateTime and not a String?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
