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;
}
}
启动重试,哈哈不报错了,暂时先这么玩吧
|