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進行序列化的?

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