irpas技术客

Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Mo

未知 8034

Caused by: org.springframework.messaging.converter.MessageConversionException: Could not write JSON: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.ir.mq.model.message.receive.GenerateDutyMQMessage["createTime"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.ir.mq.model.message.receive.GenerateDutyMQMessage["createTime"]) at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertToInternal(MappingJackson2MessageConverter.java:273) at org.springframework.messaging.converter.AbstractMessageConverter.toMessage(AbstractMessageConverter.java:201) at org.springframework.messaging.converter.CompositeMessageConverter.toMessage(CompositeMessageConverter.java:96) at org.springframework.messaging.core.AbstractMessageSendingTemplate.doConvert(AbstractMessageSendingTemplate.java:181) at org.apache.rocketmq.spring.core.RocketMQTemplate.doConvert(RocketMQTemplate.java:985) at org.apache.rocketmq.spring.core.RocketMQTemplate.createRocketMqMessage(RocketMQTemplate.java:1025) at org.apache.rocketmq.spring.core.RocketMQTemplate.sendAndReceive(RocketMQTemplate.java:238) ... 115 common frames omitted Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.ir.mq.model.message.receive.GenerateDutyMQMessage["createTime"]) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1276) at com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer.serialize(UnsupportedTypeSerializer.java:35) at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770) at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319) at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:3126) at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertToInternal(MappingJackson2MessageConverter.java:255) ... 121 common frames omitted

springboot 对象转json报错,原因很简单jackson不支持LocalDateTime需要额外引入依赖

<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.13.0</version> </dependency>

引入后依旧报错。

源码跟踪

com.fasterxml.jackson.databind.ser.BeanSerializerFactory#_findUnsupportedTypeSerializer protected JsonSerializer<?> _findUnsupportedTypeSerializer(SerializerProvider ctxt, JavaType type, BeanDescription beanDesc) throws JsonMappingException { // 05-May-2020, tatu: Should we check for possible Shape override to "POJO"? // (to let users force 'serialize-as-POJO'? final String errorMsg = BeanUtil.checkUnsupportedType(type); if (errorMsg != null) { // 30-Sep-2020, tatu: [databind#2867] Avoid checks if there is a mix-in // which likely providers a handler... if (ctxt.getConfig().findMixInClassFor(type.getRawClass()) == null) { return new UnsupportedTypeSerializer(type, errorMsg); } } return null; }

在BeanSerializerFactory这个类中获取JsonSerializer时会检查不支持的类。

com.fasterxml.jackson.databind.util.BeanUtil#checkUnsupportedType public static String checkUnsupportedType(JavaType type) { final String className = type.getRawClass().getName(); String typeName, moduleName; if (isJava8TimeClass(className)) { // [modules-java8#207]: do NOT check/block helper types in sub-packages, // but only main-level types (to avoid issues with module) if (className.indexOf('.', 10) >= 0) { return null; } typeName = "Java 8 date/time"; moduleName = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"; } else if (isJodaTimeClass(className)) { typeName = "Joda date/time"; moduleName = "com.fasterxml.jackson.datatype:jackson-datatype-joda"; } else { return null; } return String.format("%s type %s not supported by default: add Module \"%s\" to enable handling", typeName, ClassUtil.getTypeDescription(type), moduleName); }

从源码上面看Java8的date/time和joda的date/time是不支持的。

回到com.fasterxml.jackson.databind.ser.BeanSerializerFactory#_findUnsupportedTypeSerializer方法中,如果存在错误errorMsg,则会去SerializerProvider类的SerializationConfig配置中寻找_mixIns

。。。。。后面就不知道怎么玩了。手动哭笑

然后继续百度,在GitHub的问题中找到了思路。

Springboot 2.5.0 - Regression - Swagger3 RuntimeException: Could not write JSON · Issue #3829 · springfox/springfox · GitHub

其中有这句话Tried opening a SpringBoot issue, but it seems this is internal springfox issue, as explained to me here:

然后想到我其他实体类中的LocalDateTime是能正常转换的。于是开始看rocketMQ的json配置源码,

@Configuration @ConditionalOnMissingBean(RocketMQMessageConverter.class) class MessageConverterConfiguration { @Bean public RocketMQMessageConverter createRocketMQMessageConverter() { return new RocketMQMessageConverter(); } } public RocketMQMessageConverter() { List<MessageConverter> messageConverters = new ArrayList<>(); ByteArrayMessageConverter byteArrayMessageConverter = new ByteArrayMessageConverter(); byteArrayMessageConverter.setContentTypeResolver(null); messageConverters.add(byteArrayMessageConverter); messageConverters.add(new StringMessageConverter()); if (JACKSON_PRESENT) { messageConverters.add(new MappingJackson2MessageConverter()); } if (FASTJSON_PRESENT) { try { messageConverters.add( (MessageConverter)ClassUtils.forName( "com.alibaba.fastjson.support.spring.messaging.MappingFastJsonMessageConverter", ClassUtils.getDefaultClassLoader()).newInstance()); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException ignored) { //ignore this exception } } messageConverter = new CompositeMessageConverter(messageConverters); }

从源码来看支持四种convert分别是字节、String、JackSon、fastJson。

org.springframework.messaging.converter.AbstractMessageConverter#toMessage(java.lang.Object, org.springframework.messaging.MessageHeaders, java.lang.Object) public final Message<?> toMessage(Object payload, @Nullable MessageHeaders headers, @Nullable Object conversionHint) { if (!canConvertTo(payload, headers)) { return null; } Object payloadToUse = convertToInternal(payload, headers, conversionHint); if (payloadToUse == null) { return null; } MimeType mimeType = getDefaultContentType(payloadToUse); if (headers != null) { MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(headers, MessageHeaderAccessor.class); if (accessor != null && accessor.isMutable()) { if (mimeType != null) { accessor.setHeaderIfAbsent(MessageHeaders.CONTENT_TYPE, mimeType); } return MessageBuilder.createMessage(payloadToUse, accessor.getMessageHeaders()); } } MessageBuilder<?> builder = MessageBuilder.withPayload(payloadToUse); if (headers != null) { builder.copyHeaders(headers); } if (mimeType != null) { builder.setHeaderIfAbsent(MessageHeaders.CONTENT_TYPE, mimeType); } return builder.build(); } // 只有jackson和fastjson才能canConvertTo,由于jackson的顺序在前面,就优先走了jackson

猜测,rocketMQ的MappingJackson2MessageConverter的objectMapper与springboot默认的不是一个对象,而rocketMQ的没有注册JavaTimeModule。

重写rocketMQ的json配置试一下

@Configuration public class RocketConfig { @Bean public RocketMQMessageConverter createRocketMQMessageConverter() { RocketMQMessageConverter converter = new RocketMQMessageConverter(); CompositeMessageConverter compositeMessageConverter = (CompositeMessageConverter) converter.getMessageConverter(); List<MessageConverter> messageConverterList = compositeMessageConverter.getConverters(); /*for (int i = 0; i < messageConverterList.size(); i++) { // rocketMQ SpringBoot jackson转换LocalDate报错 暂时使用fastJson if (messageConverterList.get(i) instanceof MappingJackson2MessageConverter) { messageConverterList.remove(messageConverterList.get(i)); i = i - 1; } }*/ for (MessageConverter messageConverter : messageConverterList) { if (messageConverter instanceof MappingJackson2MessageConverter) { MappingJackson2MessageConverter jackson2MessageConverter = (MappingJackson2MessageConverter) messageConverter; ObjectMapper objectMapper = jackson2MessageConverter.getObjectMapper(); objectMapper.registerModules(new JavaTimeModule()); } } return converter; } }

启动重试,哈哈不报错了,暂时先这么玩吧


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #JAVA #8 #DATETIME #type #not #Supported #by