高复用的Jackson序列化和反序列

这篇博客介绍了如何使用Jackson库进行高效且可复用的序列化和反序列化操作。首先,通过ObjectMapper配置序列化和反序列化的属性以解决常见问题。接着,封装了序列化和反序列化方法。针对反序列化时遇到的多泛型处理问题,文章提出了使用TypeReference或javaType的解决方案。最后,展示了完成后的高复用Jackson工具类封装,适用于日志记录等场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇博客使用的POM:

<dependency>
  <groupId>org.codehaus.jackson</groupId>
  <artifactId>jackson-mapper-asl</artifactId>
  <version>1.9.12</version>
</dependency>

 

一.    首先通过ObjectMapper 设置序列化和反序列化时候的属性(非常重要!!!,能够填大多数序列化和反序列化时候的坑)

         

private static ObjectMapper objectMapper = new ObjectMapper();

static {
    //该属性设置主要是将对象的所有字段全部列入,若有特殊需求,可以进入JsonSerialize.Inclusion该枚举类查看
    objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS);

    //该属性设置主要是取消将对象的时间默认转换timesstamps(时间戳)形式
    objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);

    //该属性设置主要是将忽略空bean转json错误
    objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);

    //忽略在json字符串中存在,在java类中不存在字段,防止错误。
    objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    //所有日期都统一为以下样式:yyyy-MM-dd HH:mm:ss,这里可以不用我的DateTimeUtil.DATE_FORMAT,手动添加
    objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtil.DATE_FORMAT));
}

二.    封装序列化方法

public static <T> String objToJson(T obj) {
    if (obj == null) {
        return null;
    }

    try {
        return obj instanceof String ? (String)obj : objectMapper.writeValueAsString(obj);
    } catch (Exception e) {
        log.warn("obj To json is error", e);
        return null;
    }
}

三.    封装反序列化方法

public stat
<think>我们参考用户提供的引用内容,特别是引用[1]引用[3]中提到的自定义注解自定义序列化器的思路,结合引用[2]中提到的@JsonComponent方式,来为特定字段定制Jackson序列化规则。在SpringBoot中,为特定字段设置自定义序列化规则主要有两种方式:1.使用`@JsonSerialize`注解在字段上,并指定自定义的序列化器(如引用[3]所示)2.使用`@JsonComponent`注解定义全局的序列化器,并配合条件判断(如引用[2]所示)下面我们分别介绍这两种方式:###方法一:使用`@JsonSerialize`注解(字段级定制)####步骤1:创建自定义注解(可选,用于更灵活的配置)如果希望有更丰富的控制(比如根据注解参数执行不同的序列化逻辑),可以创建一个自定义注解,并在注解上使用`@JsonSerialize`指定序列化器。```javaimportcom.fasterxml.jackson.databind.annotation.JsonSerialize;importjava.lang.annotation.*;@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@JsonSerialize(using=CustomFieldSerializer.class)//指定序列化器public@interfaceCustomSerialize{//可以定义一些参数,比如处理型Stringtype()default"default";}```####步骤2:实现自定义序列化器创建继承自`JsonSerializer`的序列化器。```javaimportcom.fasterxml.jackson.core.JsonGenerator;importcom.fasterxml.jackson.databind.JsonSerializer;importcom.fasterxml.jackson.databind.SerializerProvider;importjava.io.IOException;publicclassCustomFieldSerializerextendsJsonSerializer<Object>{@Overridepublicvoidserialize(Objectvalue,JsonGeneratorgen,SerializerProviderprovider)throwsIOException{//这里实现自定义序列化逻辑//例如:将字段值转换为大写字符串StringtransformedValue=value.toString().toUpperCase();gen.writeString(transformedValue);}}```####步骤3:在实体字段上使用注解```javapublicclassUser{privateStringname;@CustomSerialize(type="uppercase")//使用自定义注解privateStringnickname;//或者直接使用@JsonSerialize@JsonSerialize(using=CustomFieldSerializer.class)privateStringaddress;//gettersandsetters}```###方法二:使用`@JsonComponent`注解(全局注册,按条件处理)这种方式下,我们创建一个全局的序列化器,它会自动被Jackson注册,然后我们在序列化器内部判断字段是否需要特殊处理(比如通过字段型、字段上的注解等)。####步骤1:创建自定义序列化器(继承`JsonSerializer`)```javaimportcom.fasterxml.jackson.core.JsonGenerator;importcom.fasterxml.jackson.databind.JsonSerializer;importcom.fasterxml.jackson.databind.SerializerProvider;importjava.io.IOException;publicclassCustomFieldSerializerextendsJsonSerializer<Object>{@Overridepublicvoidserialize(Objectvalue,JsonGeneratorgen,SerializerProviderprovider)throwsIOException{//自定义逻辑gen.writeString(value.toString().toUpperCase());}}```####步骤2:使用`@JsonComponent`将序列化器注册为SpringBean```javaimportcom.fasterxml.jackson.core.JsonGenerator;importcom.fasterxml.jackson.databind.*;importcom.fasterxml.jackson.databind.ser.std.StdSerializer;importorg.springframework.boot.jackson.JsonComponent;importjava.io.IOException;@JsonComponent//自动注册publicclassCustomSerializerComponent{//专门处理String型的字段publicstaticclassStringSerializerextendsStdSerializer<String>{publicStringSerializer(){super(String.class);}@Overridepublicvoidserialize(Stringvalue,JsonGeneratorgen,SerializerProviderprovider)throwsIOException{//这里可以判断字段上的注解或其他条件//由于没有直接获取字段信息,此方式适用于特定型的所有字段gen.writeString(value.toUpperCase());}}//或者更通用的方式:处理所有标记了特定注解的字段//需要重写BeanSerializerModifier,见下面的扩展部分}```但是,`@JsonComponent`方式默认是按型处理的,无法直接针对字段上的注解。如果想根据字段注解来处理,需要结合`BeanSerializerModifier`(如引用[1]所述)。###扩展:通过`BeanSerializerModifier`实现字段注解的全局处理(推荐)引用[1]中提到的思路,我们可以自定义`BeanSerializerModifier`来修改序列化行为,为带有特定注解的字段设置自定义序列化器。####步骤1:自定义注解(同上)```java@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public@interfaceCustomSerialize{Stringtype()default"default";}```####步骤2:自定义序列化器(同上)####步骤3:自定义`BeanSerializerModifier````javaimportcom.fasterxml.jackson.databind.ser.BeanSerializerModifier;importcom.fasterxml.jackson.databind.*;importjava.util.List;importjava.util.Iterator;publicclassCustomSerializerModifierextendsBeanSerializerModifier{@OverridepublicList<BeanPropertyWriter>changeProperties(SerializationConfigconfig,BeanDescriptionbeanDesc,List<BeanPropertyWriter>beanProperties){//遍历所有属性for(BeanPropertyWriterwriter:beanProperties){//检查字段是否有CustomSerialize注解if(writer.getAnnotation(CustomSerialize.class)!=null){//设置自定义序列化器writer.assignSerializer(newCustomFieldSerializer());}}returnbeanProperties;}}```####步骤4:创建自定义`Jackson2ObjectMapperBuilderCustomizer`配置`BeanSerializerModifier````javaimportorg.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassJacksonConfig{@BeanpublicJackson2ObjectMapperBuilderCustomizeraddCustomSerializer(){returnbuilder->{builder.serializerByType(YourBeanType.class,newCustomFieldSerializer());//按型全局序列化(可选)builder.serializers(newCustomFieldSerializer());//注册全局序列化器(按型)//使用BeanSerializerModifierbuilder.modifiers(newCustomSerializerModifier());};}}```或者,直接配置`ObjectMapper`:```java@BeanpublicObjectMapperobjectMapper(){ObjectMappermapper=newObjectMapper();//注册模块,并设置BeanSerializerModifierSimpleModulemodule=newSimpleModule();module.setSerializerModifier(newCustomSerializerModifier());mapper.registerModule(module);returnmapper;}```###总结-**字段级定制**:直接在字段上使用`@JsonSerialize(using=...)`或自定义注解(推荐用于单个字段的特定处理)。-**全局按型定制**:使用`@JsonComponent`定义针对特定型的序列化器(适用于处理整个型的字段)。-**全局按注解定制**:通过自定义`BeanSerializerModifier`,扫描字段上的注解并设置对应的序列化器(推荐用于需要注解标记的全局处理)。###示例验证假设我们有一个用户对象,其中`nickname`字段标记了`@CustomSerialize`注解:```javapublicclassUser{privateStringname;@CustomSerializeprivateStringnickname;//gettersandsetters}```当序列化时,`nickname`字段会经过`CustomFieldSerializer`处理,而其他字段正常序列化。###相关问题1.如何在Jackson自定义序列化器中获取字段注解的参数?2.如何为Jackson自定义枚举型的序列化反序列化?3.在SpringBoot中如何配置Jackson同时支持日期格式自定义序列化器?</think>在 Spring Boot 中为特定字段定制 Jackson 序列化规则,可以通过以下四种方法实现,其中注解驱动方式最为灵活精准: ### 一、字段级注解驱动(推荐) 通过 `@JsonSerialize` 注解直接绑定自定义序列化器到特定字段: ```java // 1. 创建自定义序列化器 public class MaskSerializer extends JsonSerializer<String> { @Override public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException { if (value != null && value.length() > 4) { // 示例:手机号脱敏处理 gen.writeString(value.substring(0, 3) + "****" + value.substring(7)); } else { gen.writeString(value); } } } // 2. 在实体字段上应用注解 public class User { private String name; @JsonSerialize(using = MaskSerializer.class) // 绑定自定义序列化器 private String phone; // getters/setters } ``` ### 二、自定义注解+序列化器(高阶) 实现更灵活的字段标记参数化处理: ```java // 1. 定义自定义注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @JsonSerialize(using = MaskRuleSerializer.class) // 关联序列化器 public @interface MaskRule { String pattern() default "PHONE"; // 可配置的脱敏规则 } // 2. 实现参数化序列化器 public class MaskRuleSerializer extends JsonSerializer<String> { @Override public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException { MaskRule annotation = provider.getAnnotation(MaskRule.class); if (annotation != null) { switch (annotation.pattern()) { case "PHONE": gen.writeString(value.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")); break; case "ID_CARD": gen.writeString(value.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1**********$2")); break; } } } } // 3. 在实体中使用 public class User { @MaskRule(pattern = "PHONE") private String phone; @MaskRule(pattern = "ID_CARD") private String idCard; } ``` ### 三、全局注册 + 条件处理(`@JsonComponent`) 通过 `@JsonComponent` 自动注册全局处理器: ```java @JsonComponent public class CustomSerializers { // 处理所有String型字段 public static class MaskingSerializer extends JsonSerializer<String> { @Override public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException { // 可通过射检查字段注解 if (gen.getCurrentValue() instanceof User) { gen.writeString("*****" + value.substring(5)); } else { gen.writeString(value); } } } } ``` ### 四、`BeanSerializerModifier` 动态注入(批量处理) 批量处理标记了特定注解的字段: ```java // 1. 创建序列化修改器 public class MaskingModifier extends BeanSerializerModifier { @Override public List<BeanPropertyWriter> changeProperties( SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { for (BeanPropertyWriter writer : beanProperties) { if (writer.getAnnotation(MaskRule.class) != null) { writer.assignSerializer(new MaskRuleSerializer()); } } return beanProperties; } } // 2. 注册到ObjectMapper @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.setSerializerModifier(new MaskingModifier()); mapper.registerModule(module); return mapper; } ``` ### 关键选择建议 | **场景** | **推荐方案** | **优势** | |------------------------------|---------------------------|----------------------------------| | 单个字段特殊处理 | `@JsonSerialize` 注解 | 简单直接,无需全局配置 | | 多字段共享逻辑+参数化 | 自定义注解 + 序列化器 | 高复用性,支持差异化配置 | | 需要访问整个对象的上下文 | `@JsonComponent` | 可获取序列化上下文信息 | | 批量处理特定注解标记的字段 | `BeanSerializerModifier` | 集中管理,避免字段级重复配置 | ### 验证示例 ```java @Test public void testPhoneMasking() throws JsonProcessingException { User user = new User("张三", "13800138000"); String json = new ObjectMapper().writeValueAsString(user); // 应输出: {"name":"张三","phone":"138****8000"} assertTrue(json.contains("138****8000")); } ``` ### 常见问题解决 1. **序列化器不生效**: - 检查是否在字段上正确添加了 `@JsonSerialize` 注解 - 确保自定义序列化器已通过 `@JsonComponent` 注册或通过模块配置 2. **需要访问字段注解**: ```java // 在序列化器中获取字段注解 MaskRule annotation = field.getAnnotation(MaskRule.class); ``` 3. **处理静态最终字段**: Jackson 默认忽略 `static final` 字段,需添加 `@JsonProperty` 注解: ```java @JsonProperty @MaskRule private static final String TYPE = "USER"; ``` > 通过组合使用这些技术,可以实现从简单字段处理到复杂业务逻辑的全方位定制[^1][^2][^3]。 --- ### 相关问题 1. 如何在 Jackson 序列化器中访问其他字段的值? 2. Spring Boot 中如何为枚举型配置自定义序列化规则? 3. 如何实现 Jackson 的多层级嵌套对象序列化定制?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值