jackson序列化优先级和注解顺序

Posted by hcy on April 19, 2022

jackson序列化优先级和注解顺序

先说结论: 序列化时getter方法优先于字段,注解添加到字段上或添加在getter方法上同样生效。

1. 创建serializerProvider调用serializeValue方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected final void _writeValueAndClose(JsonGenerator g, Object value)
    throws IOException
{
    SerializationConfig cfg = getSerializationConfig();
    if (cfg.isEnabled(SerializationFeature.CLOSE_CLOSEABLE) && (value instanceof Closeable)) {
        _writeCloseable(g, value, cfg);
        return;
    }
    try {
        _serializerProvider(cfg).serializeValue(g, value);
    } catch (Exception e) {
        ClassUtil.closeOnFailAndThrowAsIOE(g, e);
        return;
    }
    g.close();
}

2. 获取JsonSerializer,并使用它进行序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void serializeValue(JsonGenerator gen, Object value) throws IOException
{
    _generator = gen;
    if (value == null) {
        _serializeNull(gen);
        return;
    }
    final Class<?> cls = value.getClass();
    // true, since we do want to cache root-level typed serializers (ditto for null property)
    final JsonSerializer<Object> ser = findTypedValueSerializer(cls, true, null);
    PropertyName rootName = _config.getFullRootName();
    if (rootName == null) { // not explicitly specified
        if (_config.isEnabled(SerializationFeature.WRAP_ROOT_VALUE)) {
            _serialize(gen, value, ser, _config.findRootName(cls));
            return;
        }
    } else if (!rootName.isEmpty()) {
        _serialize(gen, value, ser, rootName);
        return;
    }
    _serialize(gen, value, ser);
}

3. 此方法核心在第二行,会创建BeanDescription

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public JsonSerializer<Object> createSerializer(SerializerProvider prov,
            JavaType origType)
        throws JsonMappingException
    {
        // Very first thing, let's check if there is explicit serializer annotation:
        final SerializationConfig config = prov.getConfig();
        BeanDescription beanDesc = config.introspect(origType);
        JsonSerializer<?> ser = findSerializerFromAnnotation(prov, beanDesc.getClassInfo());
        if (ser != null) {
            return (JsonSerializer<Object>) ser;
        }
        boolean staticTyping;
        // Next: we may have annotations that further indicate actual type to use (a super type)
        final AnnotationIntrospector intr = config.getAnnotationIntrospector();
        JavaType type;

        if (intr == null) {
            type = origType;
        } else {
            try {
                type = intr.refineSerializationType(config, beanDesc.getClassInfo(), origType);
            } catch (JsonMappingException e) {
                return prov.reportBadTypeDefinition(beanDesc, e.getMessage());
            }
        }
        if (type == origType) { // no changes, won't force static typing
            staticTyping = false;
        } else { // changes; assume static typing; plus, need to re-introspect if class differs
            staticTyping = true;
            if (!type.hasRawClass(origType.getRawClass())) {
                beanDesc = config.introspect(type);
            }
        }
        // Slight detour: do we have a Converter to consider?
        Converter<Object,Object> conv = beanDesc.findSerializationConverter();
        if (conv == null) { // no, simple
            return (JsonSerializer<Object>) _createSerializer2(prov, type, beanDesc, staticTyping);
        }
        JavaType delegateType = conv.getOutputType(prov.getTypeFactory());
        
        // One more twist, as per [databind#288]; probably need to get new BeanDesc
        if (!delegateType.hasRawClass(type.getRawClass())) {
            beanDesc = config.introspect(delegateType);
            // [#359]: explicitly check (again) for @JsonSerializer...
            ser = findSerializerFromAnnotation(prov, beanDesc.getClassInfo());
        }
        // [databind#731]: Should skip if nominally java.lang.Object
        if (ser == null && !delegateType.isJavaLangObject()) {
            ser = _createSerializer2(prov, delegateType, beanDesc, true);
        }
        return new StdDelegatingSerializer(conv, delegateType, ser);
    }

4. BeanDescription内的findProperties方法,

此方法触发时将对class进行解析,解析过程如下,这里就解释了注解加在字段上或方法上同样生效的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void collectAll()
{
    LinkedHashMap<String, POJOPropertyBuilder> props = new LinkedHashMap<String, POJOPropertyBuilder>();

    //使用反射获取字段
    _addFields(props); 

    //使用反射获取getter,setter方法
    _addMethods(props);

    //合并注解,此处会将方法上的注解和字段上的注解进行合并在一起,这就解释了注解加在字段和方法上同样有效
    for (POJOPropertyBuilder property : props.values()) {
        property.mergeAnnotations(_forSerialization);
    }
    _properties = props;
    _collected = true;
}

5. 为何方法优于字段

在BeanSerializerFactory方法中存在下面方法,会从BeanPropertyDefinition中构建AnnotatedMember,而getAccessor()方法是优先检测getter方法再检测field,故序列化时方法优先于字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
protected List<BeanPropertyWriter> findBeanProperties(SerializerProvider prov,
            BeanDescription beanDesc, BeanSerializerBuilder builder)
        throws JsonMappingException
    {
        List<BeanPropertyDefinition> properties = beanDesc.findProperties();
        final SerializationConfig config = prov.getConfig();

        // ignore specified types
        removeIgnorableTypes(config, beanDesc, properties);
        
        // and possibly remove ones without matching mutator...
        if (config.isEnabled(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS)) {
            removeSetterlessGetters(config, beanDesc, properties);
        }
        
        // nothing? can't proceed (caller may or may not throw an exception)
        if (properties.isEmpty()) {
            return null;
        }
        // null is for value type serializer, which we don't have access to from here (ditto for bean prop)
        boolean staticTyping = usesStaticTyping(config, beanDesc, null);
        PropertyBuilder pb = constructPropertyBuilder(config, beanDesc);
        
        ArrayList<BeanPropertyWriter> result = new ArrayList<BeanPropertyWriter>(properties.size());
        for (BeanPropertyDefinition property : properties) {
            final AnnotatedMember accessor = property.getAccessor();
            // Type id? Requires special handling:
            if (property.isTypeId()) {
                if (accessor != null) {
                    builder.setTypeId(accessor);
                }
                continue;
            }
            // suppress writing of back references
            AnnotationIntrospector.ReferenceProperty refType = property.findReferenceType();
            if (refType != null && refType.isBackReference()) {
                continue;
            }
            if (accessor instanceof AnnotatedMethod) {
                result.add(_constructWriter(prov, property, pb, staticTyping, (AnnotatedMethod) accessor));
            } else {
                result.add(_constructWriter(prov, property, pb, staticTyping, (AnnotatedField) accessor));
            }
        }
        return result;
    }


    public AnnotatedMember getAccessor(){
        AnnotatedMember m = getGetter();
        if (m == null) {
            m = getField();
        }
        return m;
    }


转载请注明出处:https://www.huangchaoyu.com/2022/04/19/jackson序列化优先级和注解顺序/