Spring ConversionFailedException无法序列化为JSON

时间:2019-07-12 09:42:48

标签: java spring spring-boot jackson log4j2

我将Log4J2的JSON layout logging用于基于Spring Boot(2.1.6)的Web应用程序。

我在Converters中验证请求的传入参数。

如果参数无效,则抛出IllegalArgumentException。那个包裹在ConversionFailedException中,而包裹又包裹在MethodArgumentTypeMismatchException中。

现在,当尝试使用JSON记录器记录此异常时,Jackson序列化会遇到无限循环:

ERROR StatusLogger com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: org.apache.logging.log4j.core.impl.Log4jLogEvent["message"]->java.util.LinkedHashMap["exception"]->org.springframework.web.method.annotation.MethodArgumentTypeMismatchException["cause"]->org.springframework.core.convert.ConversionFailedException["sourceType"]->org.springframework.core.convert.TypeDescriptor["resolvableType"]->org.springframework.core.ResolvableType["componentType"]->org.springframework.core.ResolvableType["componentType"])
 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: org.apache.logging.log4j.core.impl.Log4jLogEvent["message"]->java.util.LinkedHashMap["exception"]->org.springframework.web.method.annotation.MethodArgumentTypeMismatchException["cause"]->org.springframework.core.convert.ConversionFailedException["sourceType"]->org.springframework.core.convert.TypeDescriptor["resolvableType"]->org.springframework.core.ResolvableType["componentType"]->org.springframework.core.ResolvableType["componentType"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
    at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._handleSelfReference(BeanPropertyWriter.java:944)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:721)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
...

该错误似乎归结为TypeDescriptor中的ConversionFailedException不能序列化为JSON的事实。

要复制:

val illegalArgumentException = java.lang.IllegalArgumentException("your value is bad")
val conversionFailedException = org.springframework.core.convert.ConversionFailedException(TypeDescriptor.valueOf(String.javaClass), TypeDescriptor.valueOf(String.javaClass), "some bad value", illegalArgumentException)
val mapper = com.fasterxml.jackson.databind.ObjectMapper()

mapper.writeValueAsString(conversionFailedException)

或者,如果您想将问题缩小到最小的单位:

com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(org.springframework.core.convert.TypeDescriptor.valueOf(String.javaClass))

解决此问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

您收到的错误是因为org.springframework.core.ResolvableType具有对自身的引用:componentType会创建无限循环。

避免这种情况的一种方法是在全局范围内将org.springframework.core.ResolvableType从JSON序列化/反序列化中排除。您可以通过使用Jackson的mixins来做到这一点:

@JsonIgnoreType
public class MyMixInForIgnoreType {}

现在,在配置类中创建一个自定义对象映射器:

 @Bean
 @Primary 
 public ObjectMapper objectMapper () {
    ObjectMapper mapper = new Log4jJsonObjectMapper();
    mapper.addMixIn(org.springframework.core.ResolvableType.class, MyMixInForIgnoreType.class);
    return mapper;
}