Spring填坑日志(1)——Jackson序列化报错

问题描述

今天编码的时候遇到一个报错:

org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for class XXX and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class XXX and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)

大概意思就是在序列化的时候对于类 XXX 没有找到序列化器,并且没有发现有相应的属性来创建BeanSerializer序列化器。

出现原因

类XXX中忘记加@Getter注解,也就是没有生成Getter方法,其实这个问题到这里就可以结束了,但是我还处于知其然不知其所以然的情况中,所以我决定继续学习源码,为了了解问题更深层次的原因!这与JackSon序列化的过程有关系:

public void serializeAsField(Object bean, JsonGenerator gen,
        SerializerProvider prov) throws Exception {
    // inlined 'get()'
    final Object value = (_accessorMethod == null) ? _field.get(bean)
            : _accessorMethod.invoke(bean, (Object[]) null); 

    // Null handling is bit different, check that first
    if (value == null) {
        if (_nullSerializer != null) {
            gen.writeFieldName(_name);
            _nullSerializer.serialize(null, gen, prov);
        }
        return;
    }
    // then find serializer to use
    JsonSerializer<Object> ser = _serializer;
    if (ser == null) {
        Class<?> cls = value.getClass();
        PropertySerializerMap m = _dynamicSerializers;
        ser = m.serializerFor(cls);
        if (ser == null) {
            ser = _findAndAddDynamic(m, cls, prov);
        }
    }
    // and then see if we must suppress certain values (default, empty)
    if (_suppressableValue != null) {
        if (MARKER_FOR_EMPTY == _suppressableValue) {
            if (ser.isEmpty(prov, value)) {
                return;
            }
        } else if (_suppressableValue.equals(value)) {
            return;
        }
    }
    // For non-nulls: simple check for direct cycles
    if (value == bean) {
        // three choices: exception; handled by call; or pass-through
        if (_handleSelfReference(bean, gen, prov, ser)) {
            return;
        }
    }
    gen.writeFieldName(_name);
    if (_typeSerializer == null) {
        // 这边是没有找到序列化器走的分支(1)
        ser.serialize(value, gen, prov);
    } else {
        ser.serializeWithType(value, gen, prov, _typeSerializer);
    }
}
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException
{
    // 判断一下 SerializationFeature.FAIL_ON_EMPTY_BEANS(2)
    // 27-Nov-2009, tatu: As per [JACKSON-201] may or may not fail...
    if (provider.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)) {
        // 抛出异常(3)
        failForEmpty(provider, value);
    }
    // But if it's fine, we'll just output empty JSON Object:
    gen.writeStartObject();
    gen.writeEndObject();
}
protected void failForEmpty(SerializerProvider prov, Object value)
        throws JsonMappingException {
    prov.reportMappingProblem("No serializer found for class %s and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)",
            value.getClass().getName());
}

其中序列化器为类BeanPropertyWriter的属性。

/**
 * If property being serialized needs type information to be included this
 * is the type serializer to use. Declared type (possibly augmented with
 * annotations) of property is used for determining exact mechanism to use
 * (compared to actual runtime type used for serializing actual state).
 */
protected TypeSerializer _typeSerializer;

解决方案

在类XXX中增加注解,问题得到解决:
在这里插入图片描述
如果确实想生成一个空的Bean,异常中也给出了一个解决方案就是禁用SerializationFeature.FAIL_ON_EMPTY_BEANS,这个属性默认是true,可以在SpringCloud的全局配置文件application.yml中加入了如下配置:

spring:
  jackson:
    serialization:
      FAIL_ON_EMPTY_BEANS: false

这样则不会抛异常,最终序列化出来的结果是{}

参考

Jackson序列化没有get, Set方法的POJO
No serializer found for class 类名 and no properties discovered to create BeanSerializer
spring boot 是如何利用jackson进行序列化的?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章