eventuate-foundation / eventuate-common

Other
11 stars 20 forks source link

JSonMapper InvalidDefinitionException on java.time.Instant #50

Closed bendeguz-szatmari closed 4 years ago

bendeguz-szatmari commented 4 years ago

Hi,

I am using Eventuate Tram and Sagas framework (0.26.1.RELEASE and 0.15.2.RELEASE). When the framework is trying to deserialize an object containing a java.time.Instant it throws com.fasterxml.jackson.databind.exc.InvalidDefinitionException.

Full stacktrace: java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance ofjava.time.Instant(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)"{"id":1,"status":"PENDING","startTime":{"nano":287862800,"epochSecond":1603712811},"log":"","details":{"id":1,"phase":"CALIBRATION_INIT","erdmDeviceCode":"wlm01","locomotive":"v43","fromDate":{"nano":0,"epochSecond":1603666800},"toDate":{"nano":0,"epochSecond":1603666800}}}"; line: 1, column: 41] (through reference chain: com.eilabs.calibration.gatewayapi.domain.CalibrationOrder["startTime"]) at io.eventuate.common.json.mapper.JSonMapper.fromJson(JSonMapper.java:37) at io.eventuate.tram.sagas.orchestration.SagaDataSerde.deserializeSagaData(SagaDataSerde.java:24) at io.eventuate.tram.sagas.orchestration.SagaManagerImpl.handleReply(SagaManagerImpl.java:173) at io.eventuate.tram.sagas.orchestration.SagaManagerImpl.handleMessage(SagaManagerImpl.java:155) at io.eventuate.tram.consumer.common.DecoratedMessageHandlerFactory.lambda$decorate$0(DecoratedMessageHandlerFactory.java:33) at io.eventuate.tram.consumer.common.PrePostHandlerMessageHandlerDecorator.accept(PrePostHandlerMessageHandlerDecorator.java:25) at io.eventuate.tram.consumer.common.PrePostHandlerMessageHandlerDecorator.accept(PrePostHandlerMessageHandlerDecorator.java:10) at io.eventuate.tram.consumer.common.MessageHandlerDecoratorChainBuilder.lambda$buildChain$0(MessageHandlerDecoratorChainBuilder.java:38) at io.eventuate.tram.consumer.common.DuplicateDetectingMessageHandlerDecorator.lambda$accept$0(DuplicateDetectingMessageHandlerDecorator.java:13) at io.eventuate.tram.consumer.common.NoopDuplicateMessageDetector.doWithMessage(NoopDuplicateMessageDetector.java:12) at io.eventuate.tram.consumer.common.DuplicateDetectingMessageHandlerDecorator.accept(DuplicateDetectingMessageHandlerDecorator.java:13) at io.eventuate.tram.consumer.common.DuplicateDetectingMessageHandlerDecorator.accept(DuplicateDetectingMessageHandlerDecorator.java:3) at io.eventuate.tram.consumer.common.MessageHandlerDecoratorChainBuilder.lambda$buildChain$0(MessageHandlerDecoratorChainBuilder.java:38) at io.eventuate.tram.spring.optimisticlocking.OptimisticLockingDecorator.accept(OptimisticLockingDecorator.java:20) at io.eventuate.tram.spring.optimisticlocking.OptimisticLockingDecorator.accept(OptimisticLockingDecorator.java:12) at io.eventuate.tram.spring.optimisticlocking.OptimisticLockingDecorator$$FastClassBySpringCGLIB$$be528231.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) at io.eventuate.tram.spring.optimisticlocking.OptimisticLockingDecorator$$EnhancerBySpringCGLIB$$e6064acd.accept(<generated>) at io.eventuate.tram.consumer.common.MessageHandlerDecoratorChainBuilder.lambda$buildChain$0(MessageHandlerDecoratorChainBuilder.java:38) at io.eventuate.tram.consumer.common.PrePostReceiveMessageHandlerDecorator.accept(PrePostReceiveMessageHandlerDecorator.java:24) at io.eventuate.tram.consumer.common.PrePostReceiveMessageHandlerDecorator.accept(PrePostReceiveMessageHandlerDecorator.java:10) at io.eventuate.tram.consumer.common.MessageHandlerDecoratorChainBuilder.lambda$buildChain$0(MessageHandlerDecoratorChainBuilder.java:38) at io.eventuate.tram.consumer.common.MessageConsumerImpl.lambda$subscribe$0(MessageConsumerImpl.java:39) at io.eventuate.tram.consumer.kafka.EventuateTramKafkaMessageConsumer.lambda$subscribe$0(EventuateTramKafkaMessageConsumer.java:29) at io.eventuate.messaging.kafka.consumer.MessageConsumerKafkaImpl.handle(MessageConsumerKafkaImpl.java:74) at io.eventuate.messaging.kafka.consumer.MessageConsumerKafkaImpl.lambda$null$0(MessageConsumerKafkaImpl.java:44) at io.eventuate.messaging.kafka.consumer.SwimlaneDispatcher.processQueuedMessage(SwimlaneDispatcher.java:72) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance ofjava.time.Instant(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)"{"id":1,"status":"PENDING","startTime":{"nano":287862800,"epochSecond":1603712811},"log":"","details":{"id":1,"phase":"CALIBRATION_INIT","erdmDeviceCode":"wlm01","locomotive":"v43","fromDate":{"nano":0,"epochSecond":1603666800},"toDate":{"nano":0,"epochSecond":1603666800}}}"; line: 1, column: 41] (through reference chain: com.eilabs.calibration.gatewayapi.domain.CalibrationOrder["startTime"]) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1592) at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1058) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1302) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129) at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4218) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3214) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3182) at io.eventuate.common.json.mapper.JSonMapper.fromJson(JSonMapper.java:35)

The exception points to the JSonMapper class which holds custom ObjectMapper implementation, which I cannot override from Spring context.

Suggestion: add jackson-datatype-jsr310 to dependencies and apply .registerModule(new JavaTimeModule()) on the objectMapper object.

Best Regards, Bendegúz

bendeguz-szatmari commented 4 years ago

possible fix: #52

cer commented 4 years ago

The ObjectMapper's field is public so you can customize it:

https://github.com/eventuate-foundation/eventuate-common/blob/a691ea45909ff74f9c19d527402c0859931752ce/eventuate-common-json-mapper/src/main/java/io/eventuate/common/json/mapper/JSonMapper.java#L14