Java序列化 Jackson 常用方法总结

1. 常用注解

1.1 @JsonIgnore、@JsonIgnoreProperties

  • 用@JsonIgnore注释后的字段,在json序列化时将java bean中的一些属性忽略掉,序列化和反序列化都受影响。
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.io.Serializable;

public class DeptIdAndNameVO implements Serializable {

    private static final long serialVersionUID = -73277829416320393L;
    private String deptId;
    private String deptName;
    @JsonIgnore
    private String parentId;
    
}

注:@JsonIgnore可以用在当getter和setter方法上,@JsonIgnore不管注解在getters上还是setters上都会忽略对应的属性

  • 和 @JsonIgnore 的作用相同,都是告诉 Jackson 该忽略哪些属性,不同之处是 @JsonIgnoreProperties 是类级别的,并且可以同时指定多个属性。
@JsonIgnoreProperties(value = {“age”,“color”})
public class TestJackson{
    private String id;
    private String username;
    private String password;
    private Integer age;
    private String color;

}

1.2 @JsonInclude(…)

这个注解表示,如果字段值为特定条件时,则不返回,可以在类上和属性上添加这个注释,当实体类与json互相转换的时候,属性值为特定条件的不参与序列化。

条件值可选:(填入@JsonInclude的括号中)

  • JsonInclude.Include.ALWAYS 默认

  • JsonInclude.Include.NON_DEFAULT 属性为默认值不序列化

  • JsonInclude.Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化

  • JsonInclude.Include.NON_NULL 属性为NULL 不序列化

1.3 @JsonProperty

@JsonProperty注解类似于sql里字段的别名,用于序列化,使用注解字段属性,替代原字段属性

@JsonProperty("userName")
private String name;

1.4 @JsonFormat

@JsonFormat注解格式化日期格式

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date date;

1.5 @JsonTypeName @JsonTypeInfo

@JsonTypeName @JsonTypeInfo用在类上,在序列化时增加一层

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonTypeName(value = "user")
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
public class User {
    private Long id;
    @JsonProperty("userName")
    private String name;
    private Integer age;
    private Date birthday;
}

序列化结果:
{"user":{"id":1,"age":23,"birthday":1587891781603,"userName":"tom"}}

use:定义使用哪一种类型识别码,它有下面几个可选值:

1、JsonTypeInfo.Id.CLASS:使用完全限定类名做识别

2、JsonTypeInfo.Id.MINIMAL_CLASS:若基类和子类在同一包类,使用类名(忽略包名)作为识别码

3、JsonTypeInfo.Id.NAME:一个合乎逻辑的指定名称

4、JsonTypeInfo.Id.CUSTOM:自定义识别码,由@JsonTypeIdResolver对应,稍后解释

5、JsonTypeInfo.Id.NONE:不使用识别码

include(可选):指定识别码是如何被包含进去的,它有下面几个可选值:

1、JsonTypeInfo.As.PROPERTY:作为数据的兄弟属性

2、JsonTypeInfo.As.EXISTING_PROPERTY:作为POJO中已经存在的属性

3、JsonTypeInfo.As.EXTERNAL_PROPERTY:作为扩展属性

4、JsonTypeInfo.As.WRAPPER_OBJECT:作为一个包装的对象

5、JsonTypeInfo.As.WRAPPER_ARRAY:作为一个包装的数组

property(可选):制定识别码的属性名称

此属性只有当use为JsonTypeInfo.Id.CLASS(若不指定property则默认为@class)、JsonTypeInfo.Id.MINIMAL_CLASS(若不指定property则默认为@c)、JsonTypeInfo.Id.NAME(若不指定property默认为@type),include为JsonTypeInfo.As.PROPERTY、JsonTypeInfo.As.EXISTING_PROPERTY、JsonTypeInfo.As.EXTERNAL_PROPERTY时才有效

defaultImpl(可选):如果类型识别码不存在或者无效,可以使用该属性来制定反序列化时使用的默认类型

visible(可选,默认为false):是否可见

属性定义了类型标识符的值是否会通过JSON流成为反序列化器的一部分,默认为fale,也就是说,jackson会从JSON内容中处理和删除类型标识符再传递给JsonDeserializer。

1.6 @JsonRootName

通过@JsonRootName来自定义根元素名称

需要配合配置SerializationFeature.WRAP_ROOT_VALUE:是否环绕根元素,默认false,如果为true,则默认以类名作为根元素,你也可以通过@JsonRootName来自定义根元素名称。

objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE,true);

示例:

@JsonRootName("showPOJO")
public static class TestPOJO{
    private String name;

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }
}

序列化结果:
{"showPOJO":{"name":"aaaa"}}

1.7 @JsonUnwrapped

作用在属性字段或方法上,用来将子JSON对象的属性添加到封闭的JSON对象。(序列化时,父对象 中被 该注解标记的对象类型的属性 中的属性不再被这个对象包裹,而是成为父对象的属性)

示例:

public class User{
	@JsonUnwrapped
    private BaseInfo baseInfo;

    private String remake;
    
    //set 和 get 省略
}

public class BaseInfo{
	private String name;
	
	private Integer age;
	
	//set 和 get 省略
}

序列化结果:
{"name":"测试","age":12,"remake":"备注"}

在2.0+版本中@JsonUnwrapped添加了prefix和suffix属性,用来对字段添加前后缀,这在有关属性分组上比较有用,在上面的测试用例中,如果我们将TestPOJO的name属性上的@JsonUnwrapped添加前后缀配置,即

public class User{
	@JsonUnwrapped
    private BaseInfo baseInfo;

    @JsonUnwrapped(prefix = "pre_",suffix = "_suf")
    private BaseInfo baseInfo2;

    private String remark;
    
    //set 和 get 省略
}

序列化结果:
{
    "name": "测试",
    "age": 12,
    "pre_name_suf": "测试",
    "pre_age_suf": 12,
    "remark": "备注"
}

1.8 @JsonView

视图模板,作用于方法和属性上,用来指定哪些属性可以被包含在JSON视图中,在前面我们知道已经有@JsonIgnore和@JsonIgnoreProperties可以排除过滤掉不需要序列化的属性,可是如果一个POJO中有上百个属性,比如订单类、商品详情类这种属性超多,而我们可能只需要概要简单信息即序列化时只想输出其中几个或10几个属性,此时使用@JsonIgnore和@JsonIgnoreProperties就显得非常繁琐,而使用@JsonView便会非常方便,只许在你想要输出的属性(或对应的getter)上添加@JsonView即可。

示例:

@Data
@AllArgsConstructor
public class View {

    public interface View1{}

    @JsonView(View1.class)
    private String toShow;

    private String noShow;

    private String remark;
}

Controller中:

@JsonView(View.View1.class)
@GetMapping("/jackson3")
public View jackson3(){
    return new View("show", "noShow", "备注");
}

结果:

{
    "toShow": "show"
}

2. 工具类封装

package com.luqiao.cloud.security.util;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * @Author liangyixiang
 * @Description 序列化工具(基于Jackson实现)
 * @Date 2021/7/11
 * @since JDK 11
 **/
public class JsonUtil {
    // 实例化ObjectMapper对象
    private static ObjectMapper objectMapper = new ObjectMapper();

    //日志记录
    private static final Logger log = LoggerFactory.getLogger(JsonUtil.class);

    // 赋值
    static {
        objectMapper
                // 设置允许序列化空的实体类(忽略空Bean转json的错误)
                .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
                // 设置 把java.util.Date, Calendar输出为数字(时间戳)
                //.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                // 设置在遇到未知属性的时候不抛出异常
                //.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                // 强制JSON 空字符串("")转换为null对象值
                //.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)
                // 设置数字丢失精度问题
                .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
                // 设置没有引号的字段名
                .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES)
                // 设置允许单引号
                .enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES)
                // 忽略 在json字符串中存在,但是在java对象中不存在对应属性的情况。防止错误
                .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, false);

    }

    /**
     *  私有化构造器
     */
    private JsonUtil(){}

    /**
     * @Author liangyixiang
     * @Description 对象转Json格式字符串
     * @Date 2021/7/11
     * @param obj: 需序列化的对象
     * @return: java.lang.String
     **/
    public static <T> String obj2String(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.warn("Parse Object to String error : {}", e.getMessage());
            return null;
        }
    }

    /**
     * @Author liangyixiang
     * @Description 对象转Json格式字符串(格式化的Json字符串)
     * @Date 2021/7/11
     * @param obj: 需序列化的对象
     * @return: java.lang.String 美化的Json格式字符串
     **/
    public static <T> String obj2StringPretty(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.warn("Parse Object to String error : {}", e.getMessage());
            return null;
        }
    }



    /**
     * @Author liangyixiang
     * @Description 字符串转换为自定义对象
     * 调用示例: User user = JsonUtil.string2Obj(userJsonStr, User.class);
     * @Date 2021/7/11
     * @param str: 要转换的字符串
     * @param clazz: 自定义对象的class对象
     * @return: T 自定义对象
     **/
    public static <T> T string2Obj(String str, Class<T> clazz){
        if(StringUtils.isEmpty(str) || clazz == null){
            return null;
        }
        try {
            return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
        } catch (Exception e) {
            log.warn("Parse String to Object error : {}", e.getMessage());
            return null;
        }
    }


    /**
     * @Author liangyixiang
     * @Description 集合对象与Json字符串之间的转换
     * 调用示例:List<User> userListBean = JsonUtil.string2Obj(userListJson, new TypeReference<List<User>>() {});
     * @Date 2021/7/11
     * @since JDK 11
     * @param str: 要转换的字符串
     * @param typeReference: 泛型抽象类
     * @return: T
     **/
    public static <T> T string2Obj(String str, TypeReference<T> typeReference) {
        if (StringUtils.isEmpty(str) || typeReference == null) {
            return null;
        }
        try {
            return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));
        } catch (IOException e) {
            log.warn("Parse String to Object error", e);
            return null;
        }
    }

    /**
     * @Author liangyixiang
     * @Description 集合对象与Json字符串之间的转换
     * 调用示例:List<User> userListBean2 = JsonUtil.string2Obj(userListJson, List.class, User.class);
     * @Date 2021/7/11
     * @param str: 要转换的字符串
     * @param collectionClazz: 集合类型
     * @param elementClazzes: 实体类型
     * @return: T
     **/
    public static <T> T string2Obj(String str, Class<?> collectionClazz, Class<?>... elementClazzes) {
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClazz, elementClazzes);
        try {
            return objectMapper.readValue(str, javaType);
        } catch (IOException e) {
            log.warn("Parse String to Object error : {}" + e.getMessage());
            return null;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值