首页 > 技术文章 > Jackson的基本用法

whuxz 2018-08-26 19:31 原文

一、依赖

    jackson依赖3个包,由于jackson-databind依赖于jackson-annotations,jackson-core,所以实际引用jackson-databind即可以。

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.8.1</version>
</dependency>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.8.1</version>
</dependency>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.8.1</version>
</dependency>

 

二、常用注解

1、@JsonAnyGetter, @JsonAnySetter:用于将字符串中未映射到属性的值放在一个map;

@Data
public class DatasetDynamic {
    private String album_id;
    private String album_title;
@J private Map<String , Object> otherProperties = new HashMap<String , Object>(); @JsonCreator public DatasetDynamic(@JsonProperty("album_id") String album_id, @JsonProperty("album_title") String album_title) { this.album_id = album_id; this.album_title = album_title; } public Object get(String name) { return otherProperties.get(name); }
@JsonAnyGetter public Map<String , Object> any() { return otherProperties; }
@JsonAnySetter public void set(String name, Object value) { otherProperties.put(name, value); } }
      {
      "album_id":"123",
      "album_title":"haha",
      "test1":"heihei",
      "test2":222
      }

  输出:DatasetDynamic(album_id=123, album_title=haha, otherProperties={test2=222, test1=heihei}) 

 

2、@JsonIgnoreProperties和@JsonIgnore: 

用于标记属性,在json与java之间相互转化时,将忽略被此注解标记的属性。@JsonIgnoreProperties是类级别注解,可以忽略多个属性,@JsonIgnore用来标注单个属性。

@JsonIgnoreProperties({ "album_title" })
public class DatasetFilter {
    @JsonIgnore
    private String album_id;
    private String album_title;
    private Map<String , Object> otherProperties = new HashMap<String , Object>();
    private String album_comments;
}

  

3、@JsonRawValue: 直接显示属性值,对字符串,即是去掉双引号。

public class PersonRawValue {
    public long   personId = 0;
    //@JsonRawValue
    public String address  = "$#";
}
不加注解显示:{"personId":0,"address":"$#"}
加注解显示:{"personId":0,"address":$#}

4、@JsonPropertyOrder:指对象属性序列化的顺序,指定顺序的先显示,没有指定的按照默认顺序在后面,@JsonFormat:时间格式化

@JsonPropertyOrder({"id","time","name"})
public class User {
   private Long id;
   private String name;
   private BigDecimal age;
   @JsonFormat(pattern = "yyyy-MM-dd")
   private Date date;
   @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
   private Timestamp time;
   public User(Long id, String name, Date date) {
      this.id = id;
      this.name = name;
      this.date = date;
   }
}

输出结果:

{
  "id" : 2,
  "time" : null,
  "name" : "theUser",
  "age" : null,
  "date" : "2018-07-23"
}

 

5、@JsonInclude:控制序列化时的显示,将该标记放在属性上,如果该属性为NULL则不参与序列化 。如果放在类上边,那对这个类的全部属性起作用 

Include.Include.ALWAYS 默认 
Include.NON_DEFAULT
属性为默认值不序列化 
Include.NON_EMPTY
属性为空(“”或者为 NULL 都不序列化 
Include.NON_NULL
属性为NULL 不序列化 

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class User {
   private Long id;
}

 

6、@JsonSerialize@JsonDeserialize: 自定义序列化

// 自定义反序列化
public class ItemDeserializer extends JsonDeserializer<Item> {
    @Override
    public Item deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
            throws IOException, JsonProcessingException {
        JsonNode jsonNode = jsonParser.readValueAsTree();
        int id = jsonNode.path("id").intValue();
        String itemName = jsonNode.get("itemName").asText();
        Long userId = jsonNode.get("owner").asLong();
        return new Item(id, itemName, new User(userId, ""));
    }
}
// 自定义序列化
public class ItemSerializer extends JsonSerializer<Item> {
    @Override public void serialize(Item item, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeStartObject();
        jsonGenerator.writeNumberField("id", item.id);
        jsonGenerator.writeStringField("itemName", item.itemName);
        jsonGenerator.writeNumberField("owner", item.getOwner().getId());
        //jsonGenerator.writeObjectField("owner", item.owner);
        jsonGenerator.writeEndObject();
    }
}

 应用方法有2种:

(1)注解方式:

@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonSerialize(using = ItemSerializer.class)
@JsonDeserialize(using = ItemDeserializer.class)
public class Item {
    public int id;
    public String itemName;
    public User owner;
}

(2)代码方式:

SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Item.class, new ItemSerializer());
simpleModule.addDeserializer(Item.class, new ItemDeserializer());
ObjectMapper mapper = JacksonUtil.getNewDefaultMapper();
mapper.registerModule(simpleModule);
//...

 

7、@JsonCreator :解决多态性问题,通过注解,可以在序列化时,保存具体的类型信息到json中,当json反序列到java对象时,就可以根据具体类型信息创建正确的java对象。

当str -> bean时会调用@JsonCreator注解的构造函数,如果没有此注解,则默认调用无参构造函数

@Data
public class Lion extends Animal {
    private String name;
    @JsonCreator
    public Lion(@JsonProperty("name") String name) {
        this.name = name;
    }
}
public static void main(String[] args) throws IOException {
    Lion lion = new Lion("jack");
    log.info(JacksonUtil.toJson(lion));
    log.info(JacksonUtil.jsonToBean(JacksonUtil.toJson(lion), Lion.class));
}

 输出:

  "@class" : "vo.Lion",
  "name" : "jack",
  "sound" : null,
  "type" : null,
  "endangered" : null
} 
 [2018-08-26 21:03:47] main  INFO test.annotation.Test1.main(Test1.java:26) Lion(name=jack) 

 修改类:

@Data
@NoArgsConstructor
public class Lion extends Animal {
    private String name;
    public Lion(String name) {
        this.name = name;
    }
}
// 输出结果:
  "@class" : "vo.Lion",
  "name" : "jack",
  "sound" : null,
  "type" : null,
  "endangered" : null
} 
 [2018-08-26 21:08:46] main  INFO test.annotation.Test1.main(Test1.java:26) Lion(name=jack) 

 

8、@JsonTypeInfo、@JsonSubTypes:解决多态性问题,通过注解,可以在序列化时,保存具体的类型信息到json中,当json反序列到java对象时,就可以根据具体类型信息创建正确的java对象

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
@JsonSubTypes({ @Type(value = Lion.class, name = "lion"), @Type(value = Elephant.class, name = "elephant") })
@Data
public abstract class Animal {
    @JsonProperty("name")
    String name;
    @JsonProperty("sound")
    String sound;
    @JsonProperty("type")
    String type;
    @JsonProperty("endangered")
    Boolean endangered;
}

@Data
public class Zoo {
    public String name;
    public String city;
    public List<Animal> animals = new ArrayList<Animal>();

    @JsonCreator
    public Zoo(@JsonProperty("name") String name,@JsonProperty("city") String city) {
        this.name = name;
        this.city = city;
    }
    public List<Animal> addAnimal(Animal animal) {
        animals.add(animal);
        return animals;
    }
}

@Data
@NoArgsConstructor
public class Lion extends Animal {
    private String name;
    @JsonCreator
    public Lion(@JsonProperty("name") String name) {
        this.name = name;
    }
}

@Data
@NoArgsConstructor
public class Elephant extends Animal {
    @JsonProperty
    private String name;
    @JsonCreator
    public Elephant(@JsonProperty("name") String name) {
        this.name = name;
    }
}

    public static void main(String[] args) throws IOException {
        Zoo zoo = new Zoo("London zoo", "London");
        Lion lion = new Lion("Simba");
        Elephant elephant = new Elephant("Manny");
        zoo.addAnimal(lion).add(elephant);
        String jsonStr = JacksonUtil.toJson(zoo);
        log.info(jsonStr);
        log.info(JacksonUtil.jsonToBean(jsonStr, Zoo.class));
    }

 输出:

[2018-08-26 21:18:24] main  INFO test.annotation.Test1.main(Test1.java:26) {
  "name" : "London zoo",
  "city" : "London",
  "animals" : [ {
    "@class" : "vo.Lion",
    "name" : "Simba",
    "sound" : null,
    "type" : null,
    "endangered" : null
  }, {
    "@class" : "vo.Elephant",
    "name" : "Manny",
    "sound" : null,
    "type" : null,
    "endangered" : null
  } ]
} 
 [2018-08-26 21:18:24] main  INFO test.annotation.Test1.main(Test1.java:27) Zoo(name=London zoo, city=London, animals=[Lion(name=Simba), Elephant(name=Manny)]) 

 这里面有个问题,Jackson是如何识别具体的实现类?有2个问题解答:(1)区分实现类的标识?(2)标识如何写入?

注解:@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")  //使用类限定名区分,标识作为数据的史弟属性定入

具体参数:

use:定义使用哪一种类型识别码,它有下面几个可选值:
1、JsonTypeInfo.Id.CLASS:使用完全限定类名做识别
2、JsonTypeInfo.Id.MINIMAL_CLASS:若基类和子类在同一包类,使用类名(忽略包名)作为识别码
3、JsonTypeInfo.Id.NAME:一个合乎逻辑的指定名称
4、JsonTypeInfo.Id.CUSTOM:自定义识别码,
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:作为一个包装的数组

 

三、ObjectMapper常用配置:

    private static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.enable(SerializationFeature.INDENT_OUTPUT); //化化输出
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); //序列化空的POPJ
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); //不将date转化成timestamp
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //忽略未知属性
        mapper.disable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); //不将空转化为null
        mapper.disable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); //允许没有引号的字段名(非标准)
        mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }

 

四、Jackson模型:【待补充】

 

附1:封装类

/**
 * 例1:String str = JacksonUtil.toJson(userList);
 * 例2:User u = JacksonUtil.jsonToBean(str, User.class);
 * 例3:List<User> userList = JacksonUtil.jsonTo(str, new TypeReference<List<User>>(){});
 * 例4:Map<String, User> map = JacksonUtil.jsonTo(str, new TypeReference<Map<String, User>(){});
 */

@Log4j2
public class JacksonUtil {
    private static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.enable(SerializationFeature.INDENT_OUTPUT); //化化输出
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); //序列化空的POPJ
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); //不将date转化成timestamp
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //忽略未知属性
        mapper.disable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); //不将空转化为null
        mapper.disable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); //允许没有引号的字段名(非标准)
        mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }

    public JacksonUtil() {
    }

    public static ObjectMapper getNewMapper() {
        return new ObjectMapper();
    }

    public static ObjectMapper getNewDefaultMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); //序列化空的POPJ
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); //不将date转化成timestamp
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //忽略未知属性
        mapper.disable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); //不将空转化为null
        mapper.disable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); //允许没有引号的字段名(非标准)
        mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        return mapper;
    }

    public static <T> String toJson(T t) {
        return toJson(t, null);
    }

    public static <T> T jsonTo(String json, TypeReference<T> typeReference) {
        return jsonTo(json, typeReference, null);
    }

    public static <T> T jsonToBean(String json, Class<T> clazz) {
        return jsonToBean(json, clazz, null);
    }

    public static <T> T fileToBean(File file, Class<T> clazz) {
        return fileToBean(file, clazz, null);
    }

    public static <T> String toJson(T t, ObjectMapper objectMapper) {
        if (Objects.isNull(t))
            return null;
        try {
            return objectMapper == null ? mapper.writeValueAsString(t) : objectMapper.writeValueAsString(t);
        } catch (JsonProcessingException e) {
            log.error("to json error:" + t, e);
            return null;
        }
    }

    public static <T> T jsonToBean(String json, Class<T> clazz, ObjectMapper objectMapper) {
        if (StringUtils.isBlank(json))
            return null;
        try {
            return objectMapper == null ? mapper.readValue(json, clazz) : objectMapper.readValue(json, clazz);
        } catch (IOException e) {
            log.error("json to bean error:" + json, e);
            return null;
        }
    }

    public static <T> T fileToBean(File file, Class<T> clazz, ObjectMapper objectMapper) {
        if (!file.exists())
            return null;
        try {
            return objectMapper == null ? mapper.readValue(file, clazz) : objectMapper.readValue(file, clazz);
        } catch (IOException e) {
            log.error("file to bean error:" + file.getName(), e);
            return null;
        }
    }

    public static <T> T jsonTo(String json, TypeReference<T> typeReference, ObjectMapper objectMapper) {
        if (StringUtils.isBlank(json))
            return null;
        try {
            return objectMapper == null ? mapper.readValue(json, typeReference) : objectMapper.readValue(json, typeReference);
        } catch (Exception e) {
            log.error("json to map error:" + json, e);
            return null;
        }
    }

    public static <T> T jsonTo(String json, Class<T> clazz, ObjectMapper objectMapper) {
        if (StringUtils.isBlank(json))
            return null;
        try {
            return mapper.readValue(json, new TypeReference<T>(){});
        } catch (Exception e) {
            log.error("json to map error:" + json, e);
            return null;
        }
    }
}

  

 

 

 









 

推荐阅读