package com.kym.common.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.io.IOException;
import java.util.List;
import java.util.Set;

/**
 * @author https://blog.csdn.net/qq_44151781/article/details/113651296
 * @description Jackson自定义序列化null值处理
 * @date 2023-08-14 18:40
 */
@Configuration
public class JacksonConfig {
    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper mapper = converter.getObjectMapper();               //ObjectMapper，即jackson序列化的主类
        // 为mapper注册一个带有SerializerModifier的Factory，此modifier主要做的事情为：当序列化类型为array，list、set时，当值为空时，序列化成[]
        mapper.setSerializerFactory(mapper.getSerializerFactory().withSerializerModifier(new MyBeanSerializerModifier()));
        return converter;
    }


    /**
     * 处理数组、list、array、set类型的null值
     *
     * @version 1.0
     */
    public class MyNullArrayJsonSerializer extends JsonSerializer {
        @Override
        public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException, JsonProcessingException {
            if (value == null) {
                jsonGenerator.writeStartArray();
                jsonGenerator.writeEndArray();
            }
        }

    }

    /**
     * 处理字符串等类型的null值
     *
     * @version 1.0
     */
    public class MyNullJsonSerializer extends JsonSerializer {

        @Override
        public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException, JsonProcessingException {
            jsonGenerator.writeString("");
        }
    }

    /**
     * 处理Integer、Long为null
     *
     * @version 1.0
     * @date 2021/1/29/029 16:58
     */
    public class MyNullNumberJsonSerializer extends JsonSerializer {
        @Override
        public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException, JsonProcessingException {
            jsonGenerator.writeNull();
        }
    }

    /**
     * 处理Boolean为null，序列化为false
     */
    public class MyNullBooleanJsonSerializer extends JsonSerializer {
        @Override
        public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException, JsonProcessingException {
            jsonGenerator.writeBoolean(false);
        }
    }

    /**
     * @author skyline
     * @description 解决后端long类型返回前端精度丢失问题（前端number类型支持17为，本项目id为long19为，最后两位会变成00）
     * @date 2023-10-03 00:28
     */
    public class JsonLongSerializer extends JsonSerializer<Long> {
        @Override
        public void serialize(Long aLong, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            jsonGenerator.writeString(Long.toString(aLong));
        }
    }


    public void serialize(Long aLong, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString(Long.toString(aLong));
    }

    public class MyBeanSerializerModifier extends BeanSerializerModifier {

        /**
         * 数组类型
         */
        private JsonSerializer nullArrayJsonSerializer = new MyNullArrayJsonSerializer();
        /**
         * 字符串等类型
         */
        private JsonSerializer nullJsonSerializer = new MyNullJsonSerializer();
        /**
         * Integer、Long类型
         */
        private JsonSerializer nullNumberJsonSerializer = new MyNullNumberJsonSerializer();

        private JsonSerializer nullBooleanJsonSerializer = new MyNullBooleanJsonSerializer();

        private JsonSerializer longSerializer = new JsonLongSerializer();


        /**
         * 最重要的一个东西就是BeanPropertyWriter 这个类，这个类是由SerializerFactory 工厂进行实例化的
         * 其作用是对bean中的每个字段进行jackson操作的封装，其中封装了字段的一些元信息
         */
        @Override
        public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
                                                         List beanProperties) {
            //循环所有的beanPropertyWriter
            for (int i = 0; i < beanProperties.size(); i++) {
                BeanPropertyWriter writer = (BeanPropertyWriter) beanProperties.get(i);
                //判断字段的类型，如果是array，list，set则注册nullSerializer
                if (isArrayType(writer)) {
                    //给writer注册一个自己的nullSerializer
                    writer.assignNullSerializer(this.nullArrayJsonSerializer);
                } else if (isNumberType(writer)) {
                    writer.assignNullSerializer(this.nullNumberJsonSerializer);
                    if(isLongType(writer)){
                        writer.assignSerializer(this.longSerializer);
                    }
                } else if (isBooleanType(writer)) {
                    writer.assignNullSerializer(this.nullBooleanJsonSerializer);
                } else {
                    writer.assignNullSerializer(this.nullJsonSerializer);
                }
            }
            return beanProperties;
        }

        /**
         * 判断是数组类型
         *
         * @param writer
         * @return
         */
        protected boolean isArrayType(BeanPropertyWriter writer) {
            Class clazz = writer.getPropertyType();
            return clazz.isArray() || clazz.equals(List.class) || clazz.equals(Set.class);
        }

        /**
         * 判断是数组类型
         *
         * @param writer
         * @return
         */
        protected boolean isNumberType(BeanPropertyWriter writer) {
            Class clazz = writer.getPropertyType();
            return clazz.equals(Integer.class) || clazz.equals(Long.class);
        }

        /**
         * 判断是boolean类型
         */
        protected boolean isBooleanType(BeanPropertyWriter writer) {
            Class clazz = writer.getPropertyType();
            return clazz.equals(Boolean.class) || clazz.equals(boolean.class);
        }

        /**
         * 判断是long类型
         *
         * @param writer
         * @return
         */
        protected boolean isLongType(BeanPropertyWriter writer) {
            Class clazz = writer.getPropertyType();
            return clazz.equals(Long.class);
        }


    }


}
