美文网首页
jackson源码分析

jackson源码分析

作者: 无聊之园 | 来源:发表于2020-06-10 14:52 被阅读0次

    背景:之前碰到序列化的问题,spring默认序列化又是jackson序列化,然后近来又爆出fastjson序列化的漏洞,所以打算看看jackson这个东西。

    假设,如果我要写 一个序列化bean成json的序列化工具,那么可以这么做:
    反射,获取一个bean的所有的成员变量名、变量类型,然后对于各种常用类型定义好序列化工具类,比如StringSerializer,ByteSerializer, IntegerSerializer,BeanSerializer,然后获取bean的不同的属性类型,选择不同的序列化工具类,把属性转成json字符串。比如,String类型,则直接转成"string",localDateTime,则根据默认的转换格式转成string,如果是bean,则递归调用。如此,自然就可以做一个json序列化。

    这里分析的代码是j'ackson-datatype 2.6.0版本,高版本会不一样。

            ObjectMapper mapper = new ObjectMapper();
            Person person = new Person();
            person.setName("Tom");
            person.setAge(40);
            person.setNow(LocalDateTime.now());
     String jsonString = mapper.writeValueAsString(person);
            System.out.println(jsonString);
    
     public String writeValueAsString(Object value)
            throws JsonProcessingException
        {        
            // alas, we have to pull the recycler directly here...
    //分段string 写入器,就是一个继承了了Writer的对象
            SegmentedStringWriter sw = new SegmentedStringWriter(_jsonFactory._getBufferRecycler());
            try {
    // 关键这里,配置和写
                _configAndWriteValue(_jsonFactory.createGenerator(sw), value);
            } catch (JsonProcessingException e) { // to support [JACKSON-758]
                throw e;
            } catch (IOException e) { // shouldn't really happen, but is declared as possibility so:
                throw JsonMappingException.fromUnexpectedIOE(e);
            }
            return sw.getAndClear();
        }
    
    protected JsonGenerator _createGenerator(Writer out, IOContext ctxt) throws IOException
        {
    // JsonGenerator是WriterBasedJsonGenerator,而且传入了SegmentedStringWriter这个writer类
            WriterBasedJsonGenerator gen = new WriterBasedJsonGenerator(ctxt,
                    _generatorFeatures, _objectCodec, out);
            if (_characterEscapes != null) {
    // 配置转义符
                gen.setCharacterEscapes(_characterEscapes);
            }
            SerializableString rootSep = _rootValueSeparator;
            if (rootSep != DEFAULT_ROOT_VALUE_SEPARATOR) {
                gen.setRootValueSeparator(rootSep);
            }
            return gen;
        }
    

    这是ObjectMapper的方法

    protected final void _configAndWriteValue(JsonGenerator g, Object value)
            throws IOException
        {
            SerializationConfig cfg = getSerializationConfig();
        //  把ObjectMapper的配置,配置到JsonGenerator中
           cfg.initialize(g); // since 2.5
    。。。
            boolean closed = false;
            try {
    // 创建和配置好serializerProvider,这里生成的是DefaultSerializerProvider的内部类,也是子类Impl,然后调用serializerProvider的serialize方法,传入JsonGenerator和序列化对象value
    // 这里会真正序列化对象
                _serializerProvider(cfg).serializeValue(g, value);
    ...
            } finally {
            ...
        }
    

    DefaultSerializerProvider的serializeValue方法

      public void serializeValue(JsonGenerator gen, Object value) throws IOException
        {
            if (value == null) {
                _serializeNull(gen);
                return;
            }
            Class<?> cls = value.getClass();
            // true, since we do want to cache root-level typed serializers (ditto for null property)
    // 找到匹配这个类型的json序列化器
            final JsonSerializer<Object> ser = findTypedValueSerializer(cls, true, null);
    

    找到匹配这个类型的json序列化器

     public JsonSerializer<Object> findTypedValueSerializer(Class<?> valueType,
                boolean cache, BeanProperty property)
            throws JsonMappingException
        {
            // 两阶段查找,先class 类hash映射,去_knownSerializers预先定义好的序列化集合中找寻是否有这个类匹配的序列化器
            // Two-phase lookups; local non-shared cache, then shared:
            JsonSerializer<Object> ser = _knownSerializers.typedValueSerializer(valueType);
            if (ser != null) {
                return ser;
            }
          // 没有,则去_serializerCache缓存中找
            // If not, maybe shared map already has it?
            ser = _serializerCache.typedValueSerializer(valueType);
            if (ser != null) {
                return ser;
            }
          // 还没有,则取组成一个
            // Well, let's just compose from pieces:
            ser = findValueSerializer(valueType, property);
    ...
            return ser;
        }
    

    构成序列化器

    public JsonSerializer<Object> findValueSerializer(Class<?> valueType, BeanProperty property)
            throws JsonMappingException
        {
          。。。这里只是在从缓存等查找了一遍
    // 如果没有,则创建一个,而且放到缓存中 
                        // If neither, must create
                        ser = _createAndCacheUntypedSerializer(valueType);
                        // Not found? Must use the unknown type serializer, which will report error later on
                        if (ser == null) {
                            ser = getUnknownTypeSerializer(valueType);
                            // Should this be added to lookups?
                            if (CACHE_UNKNOWN_MAPPINGS) {
                                _serializerCache.addAndResolveNonTypedSerializer(valueType, ser, this);
                            }
                            return ser;
                        }
                    }
                }
            }
            // at this point, resolution has occured, but not contextualization
            return (JsonSerializer<Object>) handleSecondaryContextualization(ser, property);
        }
    
    protected JsonSerializer<Object> _createUntypedSerializer(JavaType type)
            throws JsonMappingException
        {
        
            synchronized (_serializerCache) {
             // 通过序列化工厂类,这个序列化工厂类是BeanSerializerFactory构建序列化器
                return (JsonSerializer<Object>)_serializerFactory.createSerializer(this, type);
            }
        }
    
    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 define types to use...
            JavaType type = modifyTypeByAnnotation(config, beanDesc.getClassInfo(), origType);
            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);
            }
    

    BeanSerializerFactory的_createSerializer2方法,构建序列化器

    。。。这里一系列的各种找
     // Modules may provide serializers of POJO types:
    // BeanSerializerFactory里自定义的序列器中找
                for (Serializers serializers : customSerializers()) {
                    ser = serializers.findSerializer(config, type, beanDesc);
                    if (ser != null) {
                        break;
                    }
                }
    。。。
    最后找不到,就会构建一个BeanSerializer, 这个BeanSerializer里面包含了我传入的bean的属性,然后针对属性,又会构造BeanPropertyWriter ,这个BeanPropertyWriter 包含了针对属性的序列化器等,是一个只针对传入bena的一个很自定义的东西
                        ser = findBeanSerializer(prov, type, beanDesc);
    
    
    // 构建了BeanSerializer之后,就是调用它的serialize序列化方法了
                ser.serialize(value, gen, this);
    

    BeanSerializer的serialize方法

     public final void serialize(Object bean, JsonGenerator gen, SerializerProvider provider)
            throws IOException
        {
            if (_objectIdWriter != null) {
                gen.setCurrentValue(bean); // [databind#631]
                _serializeWithObjectId(bean, gen, provider, true);
                return;
            }
    // 写入"{"这个json开始字符,里面是char[]数组存储字符的
            gen.writeStartObject();
            // [databind#631]: Assign current value, to be accessible by custom serializers
            gen.setCurrentValue(bean);
            if (_propertyFilterId != null) {
                serializeFieldsFiltered(bean, gen, provider);
            } else {
    // 然后序列化各个属性
                serializeFields(bean, gen, provider);
            }
            gen.writeEndObject();
        }
    

    BeanSerializer父类BeanSerializerBase的方法

    protected void serializeFields(Object bean, JsonGenerator gen, SerializerProvider provider)
            throws IOException, JsonGenerationException
        {
           ...
            try {
    //遍历各个属性,然后分别序列化属性,如果属性是常用类型,自然就序列化器会直接序列化,如果是pojo,则属性序列化器是BeanSerializer,又会递归序列化
                for (final int len = props.length; i < len; ++i) {
                    BeanPropertyWriter prop = props[i];
                    if (prop != null) { // can have nulls in filtered list
                        prop.serializeAsField(bean, gen, provider);
                    }
                }
    ...
        }
    

    到此:大概的整个序列化流程就是这样,当然,里面有很多细节,可以遇到具体问题具体来细节分析某一个模块。

    前面的代码

            ObjectMapper mapper = new ObjectMapper();
            Person person = new Person();
            person.setName("Tom");
            person.setAge(40);
            person.setNow(LocalDateTime.now());
     String jsonString = mapper.writeValueAsString(person);
            System.out.println(jsonString);
    

    输出是:

    {"name":"Tom","age":40,"now":{"month":"JUNE","year":2020,"dayOfMonth":10,"hour":11,"minute":3,"monthValue":6,"nano":432000000,"second":30,"dayOfWeek":"WEDNESDAY","dayOfYear":162,"chronology":{"id":"ISO","calendarType":"iso8601"}}}
    

    为什么LocalDateTime属性会被序列化成这样呢,原因是,LocalDateTime没有找到属于它的序列化器,使用的是BeanSerializer,所以,会把LocalDateTime的所有的成员递归序列,自然就序列成这样了。

    代码大概分析完了。
    然后,来看几个问题。
    既然,LocalDateTime被档成bean序列化了,那么自然就考虑如果序列化成:xxxx-xx-xx xx:xx:xx的格式了。
    注册JavaTimeModule

            JavaTimeModule javaTimeModule = new JavaTimeModule();
            mapper.registerModule(javaTimeModule);
    

    首先可以看到,JavaTimeModule的构造方法里,就已经添加了各种时间的序列化、反序列化器。保存在变量_deserializers中。

     public JavaTimeModule()
        {
            super(PackageVersion.VERSION);
    
            // First deserializers
    
            // // Instant variants:
            addDeserializer(Instant.class, InstantDeserializer.INSTANT);
            addDeserializer(OffsetDateTime.class, InstantDeserializer.OFFSET_DATE_TIME);
            addDeserializer(ZonedDateTime.class, InstantDeserializer.ZONED_DATE_TIME);
    
            // // Other deserializers
            addDeserializer(Duration.class, DurationDeserializer.INSTANCE);
            addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
            addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE);
            addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE);
            addDeserializer(MonthDay.class, JSR310StringParsableDeserializer.MONTH_DAY);
            addDeserializer(OffsetTime.class, OffsetTimeDeserializer.INSTANCE);
            addDeserializer(Period.class, JSR310StringParsableDeserializer.PERIOD);
            addDeserializer(Year.class, YearDeserializer.INSTANCE);
            addDeserializer(YearMonth.class, YearMonthDeserializer.INSTANCE);
            addDeserializer(ZoneId.class, JSR310StringParsableDeserializer.ZONE_ID);
            addDeserializer(ZoneOffset.class, JSR310StringParsableDeserializer.ZONE_OFFSET);
    。。。
    
        public ObjectMapper registerModule(Module module){
         。。。
      module.setupModule(new Module.SetupContext()
            {
                // // // Accessors
    。。。
                
                @Override
                public void addDeserializers(Deserializers d) {
                    DeserializerFactory df = mapper._deserializationContext._factory.withAdditionalDeserializers(d);
                    mapper._deserializationContext = mapper._deserializationContext.with(df);
                }
    
                @Override
                public void addKeyDeserializers(KeyDeserializers d) {
                    DeserializerFactory df = mapper._deserializationContext._factory.withAdditionalKeyDeserializers(d);
                    mapper._deserializationContext = mapper._deserializationContext.with(df);
                }
    
                @Override
                public void addSerializers(Serializers s) {
                    mapper._serializerFactory = mapper._serializerFactory.withAdditionalSerializers(s);
                }
    
                @Override
                public void addKeySerializers(Serializers s) {
                    mapper._serializerFactory = mapper._serializerFactory.withAdditionalKeySerializers(s);
                }
    ...
            });
            return this;
        }
    
    }
    
     @Override
        public void setupModule(SetupContext context) {
            super.setupModule(context);
    

    可以看到,最终会回调Module.SetupContext的add*等方法,也就是,mapper._serializerFactory.withAdditionalSerializers()方法。最终,javaTimeModile里面的所有序列化器,都添加到序列化工厂类serializerFactory里面了。

     @Override
        public void setupModule(SetupContext context)
        {
            if (_serializers != null) {
                context.addSerializers(_serializers);
            }
            if (_deserializers != null) {
                context.addDeserializers(_deserializers);
            }
            if (_keySerializers != null) {
                context.addKeySerializers(_keySerializers);
            }
            if (_keyDeserializers != null) {
                context.addKeyDeserializers(_keyDeserializers);
            }
            if (_abstractTypes != null) {
                context.addAbstractTypeResolver(_abstractTypes);
    

    然后回过头来看找寻序列化器的代码,可以看到,会遍历_factoryConfig之前添加的所有序列化类,然后找寻序列化器,自然,localDateTime会在这里找到javaTimeModule里添加的序列化器。

    for (Serializers serializers : customSerializers()) {
                   ser = serializers.findSerializer(config, type, beanDesc);
                   if (ser != null) {
                       break;
                   }
               }
    @Override
       protected Iterable<Serializers> customSerializers() {
           return _factoryConfig.serializers();
       }
       
    

    至此,也就分析完了注册javaTimeModule解决localDateTime序列化问题的代码。

            JavaTimeModule javaTimeModule = new JavaTimeModule();
            mapper.registerModule(javaTimeModule);
    

    但是,如下代码,序列化后的结果是:
    也就是说localDateTime被序列化成数组了。

    {"name":"Tom","age":40,"now":[2020,6,10,14,30,37,527000000]}
    

    为什么呢?查看JavaTimeModule里面添加的LocalDateTimeSerializer的序列化方法。

     @Override
        public void serialize(LocalDateTime dateTime, JsonGenerator generator, SerializerProvider provider)
                throws IOException
        {
    // 当配置文件里使用了时间搓,默认会进入这里
            if (useTimestamp(provider)) {
    // 这里通过方法名就可以看到,这里是写入数组,也就是默认这个序列化器就是会把localDateTime序列化成数组的
                generator.writeStartArray();
                generator.writeNumber(dateTime.getYear());
                generator.writeNumber(dateTime.getMonthValue());
                generator.writeNumber(dateTime.getDayOfMonth());
                generator.writeNumber(dateTime.getHour());
                generator.writeNumber(dateTime.getMinute());
                if(dateTime.getSecond() > 0 || dateTime.getNano() > 0)
                {
                    generator.writeNumber(dateTime.getSecond());
                    if(dateTime.getNano() > 0)
                    {
                        if(provider.isEnabled(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS))
                            generator.writeNumber(dateTime.getNano());
                        else
                            generator.writeNumber(dateTime.get(ChronoField.MILLI_OF_SECOND));
                    }
                }
                generator.writeEndArray();
            } else {
    // 如果配置禁用了时间戳,则走入这里,那么会使用事先指定的_formatter格式化,默认new LocalDateTimeSerializer没有指定。
                String str = (_formatter == null) ? dateTime.toString() : dateTime.format(_formatter);
                generator.writeString(str);
            }
        }
    

    可以看一下,如果我们禁用SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)属性,就会使用指定了的格式化器格式化。

    protected boolean useTimestamp(SerializerProvider provider) {
            if (_useTimestamp != null) {
                return _useTimestamp.booleanValue();
            }
            // assume that explicit formatter definition implies use of textual format
            if (_formatter != null) { 
                return false;
            }
            return provider.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        }
    

    禁用掉。

    输出,默认格式未ISO类型的。因为默认没有指定formatter,所以调用的是LocalDateTime的tostring方法,所以会序列化成iso类型。

    {"name":"Tom","age":40,"now":"2020-06-10T14:39:41.615"}
    

    那么我们可以指定formatter吗?可以看到,LocalDateTimeSerializer的所有的构造方法都是protected,只提供一个INSTANCE 使用,所以,想通过自带的LocalDateTimeSerializer指定formatter是不可能的。

    public class LocalDateTimeSerializer extends JSR310FormattedSerializerBase<LocalDateTime>
    {
        private static final long serialVersionUID = 1L;
    
        public static final LocalDateTimeSerializer INSTANCE = new LocalDateTimeSerializer();
    
        protected LocalDateTimeSerializer() {
            super(LocalDateTime.class);
        }
    
        private LocalDateTimeSerializer(LocalDateTimeSerializer base,
                Boolean useTimestamp, DateTimeFormatter dtf) {
            super(base, useTimestamp, dtf);
        }
    

    只能自己定义LocalDateTimeSerializer,把它们的LocalDateTimeSerializer照抄,然后改一下dateTimeFormatter。

    public class LocalDateTimeSerializer  extends JsonSerializer<LocalDateTime> {
    
        private DateTimeFormatter dateTimeFormatter;
    
        public LocalDateTimeSerializer(DateTimeFormatter dateTimeFormatter){
            this.dateTimeFormatter = dateTimeFormatter;
        }
        @Override
        public void serialize(LocalDateTime localDateTime, JsonGenerator generator, SerializerProvider serializerProvider) throws IOException {
            String str = (dateTimeFormatter == null) ? localDateTime.toString() : localDateTime.format(dateTimeFormatter);
            generator.writeString(str);
        }
    }
    

    然后添加到javaTimeModule中,因为javaTimeModule里使用的是hash映射,所以add相同的LocalDateTime.class,会覆盖原有的。

     LocalDateTimeSerializer LocalDateTimeSerializer = new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            javaTimeModule.addSerializer(LocalDateTime.class, LocalDateTimeSerializer);
    

    至此, 终于序列化好了LocalDateTime

    {"name":"Tom","age":40,"now":"2020-06-10 14:48:04"}
    

    其实,低版本的jackson才需要自己定义序列化器,高版本不需要,比如2.9.9版本,就可以直接指定formater。

            javaTimeModule.addSerializer(LocalDateTime.class,
                    new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    

    相关文章

      网友评论

          本文标题:jackson源码分析

          本文链接:https://www.haomeiwen.com/subject/gbsutktx.html