Jackson与ObjectMapper

1、Jackson可以轻松地将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象;

2、ObjectMapper类是Jackson库的主要类。它称为ObjectMapper的原因是因为它将JSON映射为Java对象(序列化),或将Java对象映射到JSON(序列化)。

ObjectMapper是线程安全的,应尽可能重用。=====> 统一配置

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class ObjectMapperConfig {

    @Bean
    @Primary
    public ObjectMapper objectMapper(){
        ObjectMapper mapper = new ObjectMapper(); // new 的过程比较耗时
        // 忽略json字符串中不识别的字段
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        // 其他需求,按需配置
        return mapper;
    }

}

Jackson中的常用注解

@JsonIgnore 标注在字段上,序列化时忽略的字段

@JsonProperty 标注在字段上,序列化时按自定义的字段序列化

@JsonFormat 标注在时间类型(Date)字段上,序列化时按指定的日期格式序列化

@JsonInclude 标注在类上,序列化时按自定义的特性处理

@JsonIgnoreProperties 标注在类上,序列化时要忽略的类的属性字段,支持多个

@JsonSerialize

枚举类定义

package coupon;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum CouponEnum {

    USABLE("可用的", 0),
    USED("已使用", 1);

    private String desc;
    private Integer code;
}

类定义

package coupon;

import com.fasterxml.jackson.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_NULL)  // 不允许序列化的值为null
@JsonIgnoreProperties({"couponCode"})
public class Coupon {

    @JsonIgnore
    private Long id;

    @JsonProperty("user_id")
    private Long userId;

    private String couponCode;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy/MM/dd hh:mm:ss")
    private Date assignTime;

    private CouponEnum couponEnum;

    private CouponTemplate couponTemplate;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    public static class CouponTemplate{

        private String name;

        private String logo;
    }

    public static Coupon fake(){
        return new Coupon(
                1L, 100L, "Merchant_01", new Date(),
                CouponEnum.USED,
                new CouponTemplate("全品券", "All_used")
        );
    }
}

测试

pom里引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
package com.insight.cloudeureka;

import com.fasterxml.jackson.databind.ObjectMapper;
import coupon.Coupon;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;


@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class JsonAnnoTest {

    @Autowired
    private ObjectMapper mapper;

    @Test
    public void testJacksonAnno() throws Exception{
        Coupon coupon = Coupon.fake();
        coupon.setCouponTemplate(null);

        // {"assignTime":"2021/07/18 05:11:20","couponEnum":"USED","user_id":100}
        log.info("ObjectMapper se Coupon: {}", mapper.writeValueAsString(coupon));
    }
}

ObjectMapper 反序列化用readValue方法 

测试结果 

 实现JsonSerializer<T>

package coupon;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.text.SimpleDateFormat;

public class CouponSerialize extends JsonSerializer<Coupon> {

    @Override
    public void serialize(Coupon coupon, JsonGenerator generator, SerializerProvider serializerProvider) throws IOException {

        // 开始序列化
        generator.writeStartObject();

        generator.writeStringField("id", String.valueOf(coupon.getId()));
        generator.writeStringField("userId", coupon.getUserId().toString());
        generator.writeStringField("couponCode", coupon.getCouponCode());
        generator.writeStringField("assignTime", new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(coupon.getAssignTime()));
        generator.writeStringField("couponEnum",coupon.getCouponEnum().getDesc());
        generator.writeStringField("name", coupon.getCouponTemplate().getName());
        generator.writeStringField("logo", coupon.getCouponTemplate().getLogo());

        // 结束序列化
        generator.writeEndObject();
    }
}

 如果自己实现序列化,那么需要将类上的注解&字段上的JSON注解去掉

一个注解完成多个注解的功能。

不去掉类的相关JSON注解,会输出,与上对比可知,自己实现的接口,并没有起作用!

{"assignTime":"2021/07/18 06:53:29","couponEnum":"USED","couponTemplate":{"name":"全品券","logo":"All_used"},"user_id":100}

JSON工具(格式化、JSONObject转对象)

public class JsonUtil {

    public static <T> BaseRet<T> convert2BaseRet(String json, Class... classes) {
        ParameterizedTypeImpl beforeType = null;
        if (classes.length != 0) {
            //支持多级泛型的解析
            for (int i = classes.length - 1; i > 0; i--) {
                beforeType = new ParameterizedTypeImpl(new Type[]{beforeType == null ? classes[i] : beforeType},
                        null, classes[i - 1]);
            }
        }
        return JSON.parseObject(json, beforeType);
    }

    public static String formatJson(String jsonStr) {
        if (null != jsonStr && !"".equals(jsonStr)) {
            StringBuilder sb = new StringBuilder();
            char current = 0;
            int indent = 0;

            for (int i = 0; i < jsonStr.length(); ++i) {
                char last = current;
                current = jsonStr.charAt(i);
                switch (current) {
                    case ',':
                        sb.append(current);
                        if (last != '\\') {
                            sb.append('\n');
                            addIndentBlank(sb, indent);
                        }
                        break;
                    case '[':
                    case '{':
                        sb.append(current);
                        sb.append('\n');
                        ++indent;
                        addIndentBlank(sb, indent);
                        break;
                    case ']':
                    case '}':
                        sb.append('\n');
                        --indent;
                        addIndentBlank(sb, indent);
                        sb.append(current);
                        break;
                    default:
                        sb.append(current);
                }
            }

            return sb.toString();
        } else {
            return "";
        }
    }

    private static void addIndentBlank(StringBuilder sb, int indent) {
        for (int i = 0; i < indent; ++i) {
            sb.append('\t');
        }
    }

    public static JSONObject toJSONObject(T t){
        return JSONObject.parseObject(JSON.toJSONString(t));
    }

    public static T toClass(JSONObject jsonObject,Class<T> claz){
        return JSONObject.parseObject(jsonObject.toJSONString(),claz);
    }

}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐