前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实现自定义序列化和反序列化控制的5种方式

实现自定义序列化和反序列化控制的5种方式

作者头像
码到三十五
修改2024-03-21 08:54:18
5090
修改2024-03-21 08:54:18
举报
文章被收录于专栏:JAVA核心JAVA核心

在 Jackson 中,你可以通过多种方式来实现自定义的序列化和反序列化控制,以下是一些常用的方式。

一、自定义 Serializer 和 Deserializer

你可以编写自定义的序列化器(Serializer)和反序列化器(Deserializer),并将它们应用到特定的类或属性上。通过实现 JsonSerializer 和 JsonDeserializer 接口,你可以完全控制序列化和反序列化过程中的行为,包括如何读取属性、生成 JSON 或者解析 JSON 等。

当你需要对特定的类或属性进行自定义的序列化和反序列化控制时,可以通过编写自定义的序列化器(Serializer)和反序列化器(Deserializer)来实现。这样你可以完全控制序列化和反序列化过程中的行为。

以下是一个示例,展示如何使用自定义序列化器和反序列化器来控制日期格式的序列化和反序列化:

代码语言:javascript
复制
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class CustomDateSerializationExample {

    public static class DateSerializer extends JsonSerializer<Date> {
        private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

        @Override
        public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            String formattedDate = DATE_FORMAT.format(value);
            gen.writeString(formattedDate);
        }
    }

    public static class DateDeserializer extends JsonDeserializer<Date> {
        private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

        @Override
        public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            String dateString = p.getText();
            try {
                return DATE_FORMAT.parse(dateString);
            } catch (Exception e) {
                throw new IOException("Failed to parse date: " + dateString, e);
            }
        }
    }

    public static class Person {
        private String name;
        private Date birthDate;

        // 省略构造函数和getter/setter方法
    }

    public static void main(String[] args) throws Exception {
        SimpleModule module = new SimpleModule();
        module.addSerializer(Date.class, new DateSerializer());
        module.addDeserializer(Date.class, new DateDeserializer());

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(module);

        // 序列化示例
        Person person = new Person("John Doe", new SimpleDateFormat("yyyy-MM-dd").parse("2000-01-01"));
        String json = objectMapper.writeValueAsString(person);
        System.out.println(json);  // 输出结果:{"name":"John Doe","birthDate":"2000-01-01"}

        // 反序列化示例
        String jsonInput = "{\"name\":\"Jane Smith\",\"birthDate\":\"1990-12-31\"}";
        Person deserializedPerson = objectMapper.readValue(jsonInput, Person.class);
        System.out.println(deserializedPerson.getBirthDate());  // 输出结果:Sat Dec 31 00:00:00 GMT 1990
    }
}
  • 我们定义了两个自定义的序列化器 DateSerializer 和反序列化器 DateDeserializer,分别用于将 Date 类型的属性序列化为指定的日期格式字符串和将日期格式字符串反序列化为 Date 对象。
  • 然后,我们使用 SimpleModule 创建一个模块,并在该模块中注册我们的自定义序列化器和反序列化器。最后,将该模块注册到 ObjectMapper 中。
  • 在序列化示例中,我们创建了一个 Person 对象,其中包含了一个 birthDate 属性,然后使用 ObjectMapper 将该对象序列化为 JSON 字符串。由于我们注册了自定义的序列化器,所以 birthDate 属性会以指定的日期格式进行序列化。
  • 在反序列化示例中,我们提供了一个 JSON 字符串作为输入,然后使用 ObjectMapper 将其反序列化为 Person 对象。由于我们注册了自定义的反序列化器,所以 birthDate 属性会根据指定的日期格式进行反序列化。

通过编写自定义的序列化器和反序列化器,你可以实现更加灵活和精确的控制,以满足特定的序列化和反序列化需求。你可以根据具体的情况,编写适合的自定义序列化器和反序列化器来处理不同的类或属性。

二、使用 Mix-in Annotations

Mix-in Annotations 允许你在不修改原始类的情况下,为其添加自定义的序列化和反序列化逻辑。你可以创建一个独立的 Mix-in 类,并在该类中为原始类添加自定义的注解,然后将 Mix-in 类与原始类关联起来。

以下是一个示例,展示如何使用 Mix-in Annotations 来控制日期格式的序列化和反序列化:

代码语言:javascript
复制
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class CustomDateSerializationExample {

    public static class Person {
        private String name;

        @JsonSerialize(using = DateSerializer.class)
        @JsonDeserialize(using = DateDeserializer.class)
        @JsonFormat(pattern = "yyyy-MM-dd")
        private Date birthDate;

        // 省略构造函数和getter/setter方法
    }

    public static class DateSerializer extends JsonSerializer<Date> {
        private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

        @Override
        public void serialize(Date value, JsonGenerator gen, com.fasterxml.jackson.databind.SerializerProvider serializers) throws IOException {
            String formattedDate = DATE_FORMAT.format(value);
            gen.writeString(formattedDate);
        }
    }

    public static class DateDeserializer extends JsonDeserializer<Date> {
        private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

        @Override
        public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            String dateString = p.getText();
            try {
                return DATE_FORMAT.parse(dateString);
            } catch (Exception e) {
                throw new IOException("Failed to parse date: " + dateString, e);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();

        // 注册 Mix-in Annotations
        objectMapper.addMixIn(Person.class, PersonMixin.class);

        // 序列化示例
        Person person = new Person("John Doe", new SimpleDateFormat("yyyy-MM-dd").parse("2000-01-01"));
        String json = objectMapper.writeValueAsString(person);
        System.out.println(json);  // 输出结果:{"name":"John Doe","birthDate":"2000-01-01"}

        // 反序列化示例
        String jsonInput = "{\"name\":\"Jane Smith\",\"birthDate\":\"1990-12-31\"}";
        Person deserializedPerson = objectMapper.readValue(jsonInput, Person.class);
        System.out.println(deserializedPerson.getBirthDate());  // 输出结果:Sat Dec 31 00:00:00 GMT 1990
    }

    // Mix-in Annotations 类
    abstract class PersonMixin {
        @JsonSerialize(using = DateSerializer.class)
        @JsonDeserialize(using = DateDeserializer.class)
        @JsonFormat(pattern = "yyyy-MM-dd")
        abstract Date getBirthDate();
    }
}
  • 我们定义了一个 Person 类,其中包含了一个 birthDate 属性。通过在该属性上使用 @JsonSerialize、@JsonDeserialize 和 @JsonFormat 注解,我们指定了自定义的序列化器、反序列化器和日期格式。
  • 然后,我们创建了一个名为 PersonMixin 的 Mix-in Annotations 类,其中包含了与 Person 类中的 birthDate 属性相关的注解。通过将 PersonMixin 注册到 Person 类上,我们实现了对 birthDate 属性的自定义序列化和反序列化控制,而无需修改原始的 Person 类。
  • 在示例的主方法中,我们创建了一个 ObjectMapper 对象,并通过 addMixIn 方法将 PersonMixin 注册到 Person 类上。然后,我们可以使用 ObjectMapper 进行序列化和反序列化操作,自定义的序列化器和反序列化器会被应用于 birthDate 属性。

通过使用 Mix-in Annotations,你可以在不修改原始类的情况下,为其添加自定义的序列化和反序列化逻辑。这种方法非常灵活,适用于需要对多个类或属性进行自定义序列化和反序列化控制的场景。

三、使用注解

Jackson 提供了多个注解,如 @JsonSerialize 和 @JsonDeserialize,它们可以直接应用于类或属性上,用来指定自定义的序列化器和反序列化器。这样你可以针对特定的类或属性,指定自定义的序列化和反序列化逻辑。

使用 @JsonSerialize 和 @JsonDeserialize 注解时,你可以为特定属性指定自定义的序列化器和反序列化器。下面是一个更简化的示例,演示如何在类中直接使用这两个注解来实现自定义的序列化和反序列化控制:

代码语言:javascript
复制
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonFormat;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class CustomDateSerializationExample {

    public static class Person {
        private String name;

        @JsonSerialize(using = DateSerializer.class)
        @JsonDeserialize(using = DateDeserializer.class)
        @JsonFormat(pattern = "yyyy-MM-dd")
        private Date birthDate;

        // 省略构造函数和getter/setter方法
    }

    public static class DateSerializer extends JsonSerializer<Date> {
        private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

        @Override
        public void serialize(Date value, JsonGenerator gen, com.fasterxml.jackson.databind.SerializerProvider serializers) throws IOException {
            String formattedDate = DATE_FORMAT.format(value);
            gen.writeString(formattedDate);
        }
    }

    public static class DateDeserializer extends JsonDeserializer<Date> {
        private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

        @Override
        public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            String dateString = p.getText();
            try {
                return DATE_FORMAT.parse(dateString);
            } catch (Exception e) {
                throw new IOException("Failed to parse date: " + dateString, e);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();

        // 序列化示例
        Person person = new Person("John Doe", new SimpleDateFormat("yyyy-MM-dd").parse("2000-01-01"));
        String json = objectMapper.writeValueAsString(person);
        System.out.println(json);  // 输出结果:{"name":"John Doe","birthDate":"2000-01-01"}

        // 反序列化示例
        String jsonInput = "{\"name\":\"Jane Smith\",\"birthDate\":\"1990-12-31\"}";
        Person deserializedPerson = objectMapper.readValue(jsonInput, Person.class);
        System.out.println(deserializedPerson.getBirthDate());  // 输出结果:Sat Dec 31 00:00:00 GMT 1990
    }
}
  • 我们直接在 Person 类的 birthDate 属性上使用了 @JsonSerialize 和 @JsonDeserialize 注解,并分别指定了自定义的序列化器 DateSerializer 和反序列化器 DateDeserializer。
  • 此外,我们还使用了 @JsonFormat 注解来指定日期格式。

通过这种方式,你可以直接在属性上指定自定义的序列化器和反序列化器,从而实现对该属性的序列化和反序列化控制。这种方式非常简洁,适用于只需要对少量属性进行自定义序列化和反序列化控制的场景。

四、使用 ObjectMapper

通过配置 ObjectMapper,你可以注册自定义的模块或者处理器,比如 SimpleModule 或者 HandlerInstantiator,来实现更高级的自定义序列化和反序列化控制。这些方法可以让你在全局范围内对序列化和反序列化行为进行定制。

下面是一个简单的示例,演示如何使用 SimpleModule 和自定义的 HandlerInstantiator 来注册自定义的序列化器和反序列化器:

代码语言:javascript
复制
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.module.SimpleAbstractTypeResolver;
import com.fasterxml.jackson.databind.module.SimpleDeserializers;
import com.fasterxml.jackson.databind.module.SimpleSerializers;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class CustomDateSerializationExample {

    public static class Person {
        private String name;
        private Date birthDate;

        // 省略构造函数和getter/setter方法
    }

    public static class DateSerializer extends JsonSerializer<Date> {
        private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

        @Override
        public void serialize(Date value, JsonGenerator gen, com.fasterxml.jackson.databind.SerializerProvider serializers) throws IOException {
            String formattedDate = DATE_FORMAT.format(value);
            gen.writeString(formattedDate);
        }
    }

    public static class DateDeserializer extends JsonDeserializer<Date> {
        private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

        @Override
        public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            String dateString = p.getText();
            try {
                return DATE_FORMAT.parse(dateString);
            } catch (ParseException e) {
                throw new IOException("Failed to parse date: " + dateString, e);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();

        // 创建自定义模块
        SimpleModule customModule = new SimpleModule();

        // 注册自定义的序列化器和反序列化器
        customModule.addSerializer(Date.class, new DateSerializer());
        customModule.addDeserializer(Date.class, new DateDeserializer());

        // 注册自定义模块到ObjectMapper
        objectMapper.registerModule(customModule);

        // 序列化示例
        Person person = new Person("John Doe", new SimpleDateFormat("yyyy-MM-dd").parse("2000-01-01"));
        String json = objectMapper.writeValueAsString(person);
        System.out.println(json);  // 输出结果:{"name":"John Doe","birthDate":"2000-01-01"}

        // 反序列化示例
        String jsonInput = "{\"name\":\"Jane Smith\",\"birthDate\":\"1990-12-31\"}";
        Person deserializedPerson = objectMapper.readValue(jsonInput, Person.class);
        System.out.println(deserializedPerson.getBirthDate());  // 输出结果:Sat Dec 31 00:00:00 GMT 1990
    }
}
  • 我们创建了一个自定义的 SimpleModule,并在其中注册了自定义的序列化器和反序列化器。
  • 然后,我们将该自定义模块注册到 ObjectMapper 中,从而实现了对日期属性的自定义序列化和反序列化控制。

除了使用 SimpleModule,你还可以通过实现自定义的 HandlerInstantiator 类来提供更复杂的定制化逻辑,以满足更高级的序列化和反序列化需求。HandlerInstantiator 可以用于创建自定义的序列化器、反序列化器、值处理器等。

五、使用 BeanSerializerModifier

这个接口允许你在序列化过程中动态地修改要应用的序列化器。通过实现这些接口,你可以根据特定的条件或者属性来动态地改变序列化器的行为。

这些方法提供了灵活的方式来实现自定义的序列化和反序列化控制,你可以根据具体的需求选择最适合的方式来实现自定义行为。

  • BeanSerializerModifier 是一个抽象类,用于修改 BeanSerializer 的行为。
  • 你可以通过继承 BeanSerializerModifier 类,并重写其中的方法来实现自定义的序列化控制。

下面是一个简单的示例,演示如何使用 BeanSerializerModifier 来实现自定义的序列化控制:

代码语言:javascript
复制
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;

import java.util.List;

public class CustomSerializationExample {

    public static class Person {
        private String name;
        private String email;

        // 省略构造函数和getter/setter方法
    }

    public static class UpperCaseSerializerModifier extends BeanSerializerModifier {
        @Override
        public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
            for (BeanPropertyWriter writer : beanProperties) {
                if (writer.getName().equals("email")) {
                    writer.assignSerializer(new UpperCaseStringSerializer());
                }
            }
            return beanProperties;
        }
    }

    public static class UpperCaseStringSerializer extends JsonSerializer<String> {
        @Override
        public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeString(value.toUpperCase());  // 自定义字符串序列化为大写形式
        }
    }

    public static void main(String[] args) {
        SimpleModule module = new SimpleModule("CustomModule");
        module.setSerializerModifier(new UpperCaseSerializerModifier());

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(module);
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);

        Person person = new Person("John Doe", "john@example.com");

        try {
            String json = objectMapper.writeValueAsString(person);
            System.out.println(json);  // 输出结果:{"name":"John Doe","email":"JOHN@EXAMPLE.COM"}
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}
  • 我们创建了一个自定义的 BeanSerializerModifier 类,即 UpperCaseSerializerModifier。在 changeProperties 方法中,我们检查属性名称是否为 “email”,如果是的话,就将其序列化器指定为自定义的 UpperCaseStringSerializer,以将 email 字段的值序列化为大写形式。
  • 然后,我们将这个自定义的 BeanSerializerModifier 实例设置到 SimpleModule 中,并将该模块注册到 ObjectMapper 中。最后,我们使用 ObjectMapper 将 Person 对象序列化为 JSON 字符串,并打印输出结果。

六、 使用案例:枚举、字典数据的自动转化

实际使用场景:java返回对象中关于枚举、字典数据的自动转化

6.1 实现思路
  • 1、通过自定义注解 对需要转化的字段进行标记,注解中可定义枚举类型,若没有定义枚举则从数据字典获取。
  • 2、自定义对象的BeanSerializerModifier,对做了标记的字段设置自定义的JsonSerializer。
  • 3、自定义JsonSerializer的实现。
  • 4、自定义MappingJackson2HttpMessageConverter,并设置自定义的BeanSerializerModifier为默认处理方式。
  • 5、将自定义的MappingJackson2HttpMessageConverter加入到HttpMessageConverters中,可以通过重写WebMvcConfigurationSupport.extendMessageConverters的方式实现。
6.2 代码实现

以下是具体的代码实现,有些地方需要用户根据实际情况自己实现,比如从字典获取数据等。

代码语言:javascript
复制
import java.lang.annotation.*;

@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Dict {
    static enum Void {}
    Class<? extends Enum<?>> enumType() default Void.class;
    /**
     * 默认值,获取不到字典则使用默认值
     */
    String defaultValue() default "";
}

自定义BeanSerializerModifier,以下代码中DictConstants.getDictCacheKey(valueStr)只是自定义key,需要自己实现。

代码语言:javascript
复制
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.hg.dcm.commons.core.HGBusinessException;
import com.hg.dcm.commons.core.SpringContextUtil;
import com.hg.energy.service.RedisService;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

@Slf4j
public class DictSerializerModifier extends BeanSerializerModifier {
    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
        for (BeanPropertyWriter beanProperty : beanProperties) {
            Dict dict = beanProperty.getAnnotation(Dict.class);
            if (dict != null) {
                beanProperty.assignSerializer(new DictSerializer(dict));
            }
        }
        return beanProperties;
    }

    /**
     * 字典自定义序列化
     */
    static class DictSerializer extends JsonSerializer<Object> {
        /**
         * 生成序列化字段后缀
         */
        private static final String LABEL_SUFFIX = "Desc";
        /**
         * 字典配置信息
         */
        private final Dict dict;

        /**
         * 枚举获取key方法
         */
        private static final String[] KEY_METHODS = {"getValue", "getCode", "getStatus", "name"};
        /**
         * 获取枚举描述方法
         */
        private static final String[] DESC_METHODS = {"getDesc"};

        /**
         * 构造方法
         *
         * @param dict 字典描述
         */
        public DictSerializer(Dict dict) {
            this.dict = dict;
        }

        /**
         * Method that can be called to ask implementation to serialize
         * values of type this serializer handles.
         *
         * @param value    Value to serialize; can <b>not</b> be null.
         * @param gen      Generator used to output resulting Json content
         * @param provider Provider that can be used to get serializers for
         *                 serializing Objects value contains, if any.
         */
        @Override
        public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            provider.defaultSerializeValue(value, gen);
            // 添加转换之后的字段:xxxDesc
            String fieldName = gen.getOutputContext().getCurrentName();
            gen.writeStringField(fieldName.concat(LABEL_SUFFIX), value != null ? this.getDesc(dict, value) : null);
        }


        /**
         * 获取字典信息
         * TODO
         *
         * @param dict  字典对象
         * @param value 字典值
         * @return
         */
        private String getDesc(Dict dict, Object value) {
            try {
                // 先查询是否是枚举类型,查到则返回
                String enumDesc = this.getEnumDesc(dict, value);
                if (enumDesc != null) {
                    return enumDesc;
                }
                String valueStr = Objects.toString(value);
                //获取缓存key,可以自定义
                String key = DictConstants.getDictCacheKey(valueStr);
                // Redis 缓存操作类 这里建议优先使用本地缓存, 本地缓存 -> redis -> Db
                RedisService redis = SpringContextUtil.getBean(RedisService.class);
                if (redis.exists(key)) {
                    return redis.get(key);
                }
                // 数据库字典操作类

                //redis.setEx(key, desc, 1, TimeUnit.HOURS);
                return "字典数据";
            } catch (Exception e) {
                log.error("字典转换:获取字典描述异常,使用默认值:{},key:{}, dict:{}, 异常:{}", dict.defaultValue(), value, dict.enumType(), e.getMessage(), e);
                return dict.defaultValue();
            }
        }


        /**
         * 获取枚举类型的描述信息
         *
         * @param dict  字典
         * @param value 值
         * @return 枚举desc字段
         */
        private String getEnumDesc(Dict dict, Object value) throws InvocationTargetException, IllegalAccessException {
            if (dict == null || value == null) {
                return null;
            }
            Class<? extends Enum<?>> et = dict.enumType();
            if (Dict.Void.class.equals(et)) {
                return null;
            }

            Enum<?>[] enums = et.getEnumConstants();
            Method keyMethod = this.getMethod(et, KEY_METHODS);
            if (keyMethod == null) {
                // 自定义业务异常
                throw new HGBusinessException(String.format("字典转换:枚举:%s,没有方法:%s", et.getName(), Arrays.toString(KEY_METHODS)));
            }
            Method descMethod = this.getMethod(et, DESC_METHODS);
            if (descMethod == null) {
                throw new HGBusinessException(String.format("字典转换:枚举:%s,没有方法:%s", et.getName(), Arrays.toString(DESC_METHODS)));
            }
            for (Enum<?> e : enums) {
                if (value.equals(keyMethod.invoke(e))) {
                    return Objects.toString(descMethod.invoke(e));
                }
            }
            log.error("字典转换:通过枚举转换失败,枚举:{},值:{},KeyMethod:{},DescMethod:{}", et.getName(), value, Arrays.toString(KEY_METHODS), Arrays.toString(DESC_METHODS));
            throw new HGBusinessException(String.format("字典转换失败,枚举:%s,值:%s", et.getName(), value));
        }

        /**
         * 获取读方法
         *
         * @param enumType    枚举类
         * @param methodNames 方法名称
         * @return Method
         */
        private Method getMethod(Class<? extends Enum<?>> enumType, String... methodNames) {
            for (String methodName : methodNames) {
                try {
                    return enumType.getMethod(methodName);
                } catch (NoSuchMethodException e) {
                }
            }
            return null;
        }
    }
}

自定义MappingJackson2HttpMessageConverter

代码语言:javascript
复制
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        SimpleModule simpleModule = new SimpleModule().setSerializerModifier(new DictSerializerModifier());
        builder.modules(simpleModule);
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        return new MappingJackson2HttpMessageConverter(builder.build());
    }

将自定义的MappingJackson2HttpMessageConverter加入到HttpMessageConverters中

代码语言:javascript
复制
@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {


    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(0,mappingJackson2HttpMessageConverter());
    }


    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        SimpleModule simpleModule = new SimpleModule().setSerializerModifier(new DictSerializerModifier());
        builder.modules(simpleModule);
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        return new MappingJackson2HttpMessageConverter(builder.build());
    }

}

术因分享而日新,每获新知,喜溢心扉。 诚邀关注公众号 码到三十五 ,获取更多技术资料。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-03-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、自定义 Serializer 和 Deserializer
  • 二、使用 Mix-in Annotations
  • 三、使用注解
  • 四、使用 ObjectMapper
  • 五、使用 BeanSerializerModifier
  • 六、 使用案例:枚举、字典数据的自动转化
    • 6.1 实现思路
      • 6.2 代码实现
      相关产品与服务
      云数据库 Redis
      腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档