精彩文章免费看

jackson使用入门

jackson是java中最常用的json处理工具包之一,其他类似功能的包括gson和fastjson等。本文将简单介绍jackson的基础知识,以作为各位读者未来使用的参考。

三种使用方式

jackson有三种处理json的方式,分别为

  • data binding
  • tree model
  • streaming api
  • data binding

    这种方式可以在json字符串和pojo对象之间直接进行转换。比如说我们有一个json字符串

    {"firstName":"dizzy","lastName":"dwarf"}
    

    通过这种方式我们可以直接将其转换成一个Person类的实例,其中firstName和lastName是Person类定义的两个成员变量。

    ObjectMapper objectMapper = new ObjectMapper();
    Person person = objectMapper.readValue(jsonStr, Person.class);
    

    tree model

    这种方式类似于xml的DOM解析,在json字符串和DOM树之间进行转换,DOM树的节点是JsonNode类型。其优点在于以统一的方式看待json字符串中的各个部分,使用起来更灵活。

    ObjectMapper objectMapper = new ObjectMapper();
    JsonNode root = objectMapper.readTree(jsonStr);
    JsonNode firstName = root.path("firstName");
    

    构建DOM树

    如何构建JsonNode的DOM树呢?JsonNode是抽象类,需要使用ObjectNodeArrayNode等子类。

    ObjectNode objectNode = objectMapper.createObjectNode();
    ArrayNode arrayNode = objectMapper.createArrayNode();
    

    streaming api

    这种方式类似于xml的SAX解析,每次处理一个事件,或者这里叫token更合适。

    streaming api反序列化

    反序列化用的是JsonParser,它的使用方式和迭代器非常相似。你每次处理的都是一个token,比如说在上面这个json字符串中,包括{、firstName、dizzy、lastName、dwarf、}等6个token,通过调用nextToken方法可以获得下一个token。

    streaming api序列化

    序列化用的JsonGenerator,它的方法都非常直观,比如说writeStartObjectwriteStringFieldwriteEndObject等,这里就不具体介绍了。

    通过注解可以定制jackson的各种特性,这里只介绍最常用的几个。

    序列化注解

    @JsonGetter
    注解在方法上,将方法返回的值作为字段序列化的值
    public class Person {
        private String firstName;
        @JsonGetter("firstName")
        public String getFirstName() {
            return firstName + "_modified";
        // 省略了setter方法
    

    这样一个firstName为"dizzy"的Person序列化后就变成了

    {"firstName":"dizzy_modified"}
    @JsonSerialize
    注解在成员变量上,使用指定的JsonSerializer实现类来序列化这个字段,这个实现类最关键的是serialize方法,这个方法会为你提供JsonGenerator对象作为参数,让你可以通过它来构建序列化后的值。 @JsonValue
    注解在方法上,将方法返回的值作为整个对象序列化的结果。

    反序列化注解

    @JsonSetter
    @JsonGetter的逆过程 @JsonDeserialize
    @JsonSerialize的逆过程 @JsonAlias
    默认情况下java对象中的成员变量名和json字符串的字段名是一对一关系的,但是可能存在这样一种情况。比如firstName这个成员变量,可能json字符串有不同的来源,有的地方这个字段叫firstName,另外一些地方传的字段名称是fName。这个时候就可以用@JsonAlias使这个成员变量接受更多的名称。 @JsonProperty
    指定该成员变量对应的json字符串的字段名,默认情况下如果两者相同的话不需要使用该注解。 @JsonIgnore
    指定该成员变量不参与序列化和反序列化

    具体问题解决

    下划线和驼峰转换

    一般情况下java变量命名采用驼峰方式,而json字符串可能采用下划线方式。解决方式为在类或者成员变量上增加以下注解

    @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
    

    需要注意的是虽然反序列化的时候first_name会对应到firstName变量,但是序列化的时候也会输出为first_name

    有时候我们希望根据json字符串中某个字段的取值反序列化成不同的子类,比如说type为1是Student,type为2是Teacher,注意Student和Teacher必须继承同一个父类Person。

    @JsonTypeInfo(use = JsonTypeInfo.ID.NAME, property = "type", defaultImpl = Person.class)
    @JsonSubTypes({
        @JsonSubTypes.Type(value = Student.class, name = "1"),
        @JsonSubTypes.Type(value = Teacher.class, name = "2")
    public class Person {}
    
  • property是决定子类型的字段名称
  • defaultImpl是默认情况下反序列化的类型,这里指的是当type不为1和2时
  • name是子类型对应的字段取值
  • 带泛型参数的List和Map的反序列化

    如果我们希望ObjectMapper.readValue返回List<Person>或者Map<String, Person>,由于List<Person>.class和Map<String, Person>.class在java中是不合法的,需要借助于TypeReference

    TypeReference<List<Person>> typeReference = new TypeReference<List<Person>>(){};
    List<Person> list = objectMapper.readValue(jsonStr, typeReference);
    

    jackson如何集成Spring

    Spring提供的MappingJackson2MessageConverter类封装了ObjectMapper,如果希望对ObjectMapper进行定制,可以自己生成一个MappingJackson2MessageConverter对象并注册为bean

    只对部分成员变量序列化同时不影响反序列化

    有时候我们希望只对部分成员变量进行序列化,如果用@JsonIgnore,会同时影响反序列化。这个时候我们可以用@JsonView注解指定某个视图类的序列化结果包含该成员变量。

  • baeldung jackson教程
  • jackson github
  •