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

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 实现自定义序列化和反序列化控制的5种方式

一、自定义 Serializer 和 Deserializer

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

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

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

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 来控制日期格式的序列化和反序列化:

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

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 来注册自定义的序列化器和反序列化器:

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 来实现自定义的序列化控制:

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 代码实现

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

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,需要自己实现。

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

    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中

@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());
    }

}


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
10天前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
20天前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
23天前
|
JSON 前端开发 数据格式
前端的全栈之路Meteor篇(五):自定义对象序列化的EJSON介绍 - 跨设备的对象传输
EJSON是Meteor框架中扩展了标准JSON的库,支持更多数据类型如`Date`、`Binary`等。它提供了序列化和反序列化功能,使客户端和服务器之间的复杂数据传输更加便捷高效。EJSON还支持自定义对象的定义和传输,通过`EJSON.addType`注册自定义类型,确保数据在两端无缝传递。
|
1月前
|
存储 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第9天】在Java的世界里,对象序列化是连接数据持久化与网络通信的桥梁。本文将深入探讨Java对象序列化的机制、实践方法及反序列化过程,通过代码示例揭示其背后的原理。从基础概念到高级应用,我们将一步步揭开序列化技术的神秘面纱,让读者能够掌握这一强大工具,以应对数据存储和传输的挑战。
|
1月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第3天】在Java编程的世界里,对象序列化与反序列化是实现数据持久化和网络传输的关键技术。本文将深入探讨Java序列化的原理、应用场景以及如何通过代码示例实现对象的序列化与反序列化过程。从基础概念到实践操作,我们将一步步揭示这一技术的魅力所在。
|
1月前
|
消息中间件 存储 Java
大数据-58 Kafka 高级特性 消息发送02-自定义序列化器、自定义分区器 Java代码实现
大数据-58 Kafka 高级特性 消息发送02-自定义序列化器、自定义分区器 Java代码实现
43 3
|
1月前
|
消息中间件 存储 分布式计算
大数据-61 Kafka 高级特性 消息消费02-主题与分区 自定义反序列化 拦截器 位移提交 位移管理 重平衡
大数据-61 Kafka 高级特性 消息消费02-主题与分区 自定义反序列化 拦截器 位移提交 位移管理 重平衡
22 1
|
20天前
|
存储 缓存 NoSQL
一篇搞懂!Java对象序列化与反序列化的底层逻辑
本文介绍了Java中的序列化与反序列化,包括基本概念、应用场景、实现方式及注意事项。序列化是将对象转换为字节流,便于存储和传输;反序列化则是将字节流还原为对象。文中详细讲解了实现序列化的步骤,以及常见的反序列化失败原因和最佳实践。通过实例和代码示例,帮助读者更好地理解和应用这一重要技术。
18 0
|
2月前
|
存储 XML JSON
用示例说明序列化和反序列化
用示例说明序列化和反序列化
|
2月前
|
JSON 安全 编译器
扩展类实例的序列化和反序列化
扩展类实例的序列化和反序列化
35 0