您的位置:首页 > 其它

Jackson基础教程

2016-06-05 23:55 369 查看

相关地址

Jackson Home Page:https://github.com/FasterXML/jackson

Jackson Wiki:http://wiki.fasterxml.com/JacksonHome

Jackson doc: https://github.com/FasterXML/jackson-docs

Jackson Download Page:http://wiki.fasterxml.com/JacksonDownload

简介

    Jackson是一套Java平台的数据处理工具集,具体可以参考官网的说法:
including the flagship streaming JSON parser / generator library, matching data-binding library (POJOs to and from JSON) and additional data format modules to process data encoded in
Avro, BSON, CBOR, CSV, Smile, Protobuf, XML or YAML; and even the large set of data format modules to support data types of widely used data types such as Joda, Guava and many, many more.

    Jackson有两个主要分支,1.x处于维护状态,只会发布bug修复版本。2.x还在积极地开发当中。这两个版本的Java包名和Maven artifact不一样,所以它们不互相兼容,但是可以和平共存,也就是项目可以同时依赖1.x和2.x而不会发生冲突,本文只会简单介绍2.x版本的用法。

Jackson主要模块

核心模块

    核心模块是扩展模块构建的基础,到2.7版本为止,共有3个核心模块:
Streaming : jackson-core jar,定义了底层的streaming API和实现了Json特性。
Annotations: jackson-annotations jar,包含了标准的Jackson注解。本文暂不介绍。
Databind : jackson-databind jar,实现了数据绑定和对象序列化,它依赖于streaming和annotations的包。

第三方数据类型模块

    这些扩展是插件式的Jackson模块,用ObjectMapper.registerModule()注册,并且通过添加serializers和deserializers以便Databind包(ObjectMapper / ObjectReader / ObjectWriter)可以读写这些类型,来增加对各种常用的Java库的数据类型的支持。参考https://github.com/FasterXML/jacksonThird-party
datatype modules。

数据格式模块

    Jackson也有处理程序对JAX-RS标准实现者例如Jersey, RESTeasy, CXF等提供了数据格式支持。处理程序实现了MessageBodyReader和MessageBodyWriter,目前支持的数据格式包括JSON, Smile, XML, YAML和CBOR。
    数据格式提供了除了Json之外的数据格式支持,它们绝大部分仅仅实现了streaming API abstractions,以便数据绑定组件可以按照原来的方式使用。另一些(几乎不需要)提供了databind标准功能来处理例如schemas。参考https://github.com/FasterXML/jacksonData
format modules


准备工作

    Jackson包含了一个核心的jar包和其他两个依赖于核心jar包的jar包,三者的依赖关系是从上到下的,如下:
Jackson Core

Jackson Annotations

Jackson Databind


       可以从https://github.com/FasterXML下载Jackson的jar包,或者采用maven来管理。如果是maven的方式,需要加入如下的依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.4</version>
</dependency>

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

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


处理Json

    本文用JDK7.0的版本。Jackson提供了三种可选的Json处理方法:数据绑定(Data Binding),流式API(Streaming API) 、树模型(Tree Model)。

Data Binding

    我们主要使用ObjectMapper来操作Json,默认情况下会使用BeanSerializer来序列化POJO。如果是解析,那么如下的例子里的TestJson必须要有setters,且setters必须是public修饰的,否则属性的值将会为null。如果是生成,那么必须有getters,且getters必须是public修饰的。如果属性不是private修饰,那么可以不用有getters和setters。这参考访问修饰符。

Json解析    
public class Demo {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();

//        当反序列化json时,未知属性会引起的反序列化被打断,这里我们禁用未知属性打断反序列化功能,
//        因为,例如json里有10个属性,而我们的bean中只定义了2个属性,其它8个属性将被忽略
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

//从json映射到java对象,得到country对象后就可以遍历查找,下面遍历部分内容,能说明问题就可以了
TestJson testJson = mapper.readValue("{\"a\":\"1\",\"b\":\"2\",\"c\":\"test\",\"d\":\"true\",\"e\":\"e\"}", TestJson.class);
System.out.println("a:" + testJson.getA());
System.out.println("b:" + testJson.getB());
System.out.println("c:" + testJson.getC());
System.out.println("d:" + testJson.getD());
}
}

class TestJson {
private Integer a;
private Integer b;
private String c;
private Boolean d;

public Integer getA() {
return a;
}

public void setA(Integer a) {
this.a = a;
}

public Integer getB() {
return b;
}

public void setB(Integer b) {
this.b = b;
}

public String getC() {
return c;
}

public void setC(String c) {
this.c = c;
}

public Boolean getD() {
return d;
}

public void setD(Boolean d) {
this.d = d;
}
}
输出:
a:1
b:2
c:test
d:true


解析的时候如果碰到集合类,那么可以使用TypeReference<T>类。
public static <T> T json2Obj(String jsonStr, TypeReference<T> typeReference, String dateFormat)
throws Exception {
ObjectMapper objectMapper = getObjectMapper();
if (dateFormat != null && !dateFormat.trim().equals("")) {
objectMapper.setDateFormat(new SimpleDateFormat(dateFormat));
}

return objectMapper.readValue(jsonStr, typeReference);
}


Json生成
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class SerializationExample {
    public static void main(String[] args) throws IOException, ParseException {
        ObjectMapper mapper = new ObjectMapper();
        Album album = new Album("Kind Of Blue");
        album.setLinks(new String[]{"link1", "link2"});
        List<String> songs = new ArrayList<String>();
        songs.add("So What");
        songs.add("Flamenco Sketches");
        songs.add("Freddie Freeloader");
        album.setSongs(songs);
        Artist artist = new Artist();
        artist.name = "Miles Davis";
        SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
        artist.birthDate = format.parse("26-05-1926");
        album.setArtist(artist);
        album.addMusician("Miles Davis", "Trumpet, Band leader");
        album.addMusician("Julian Adderley", "Alto Saxophone");
        album.addMusician("Paul Chambers", "double bass");

        //让Json可以缩进,可读性更好,一般用在测试和开发阶段。
        mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        //让map的key按自然顺序排列
        mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
        //日期输出格式
        SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd");
        mapper.setDateFormat(outputFormat);
        //默认情况下java类属性名就是输出的json字段名,但是可以采用注解的方式修改。如果你不想让java类和json绑定
        // 或者无法修改java类,这里采用如下另外一种方式。你需要重写如下两个方法,这个取决属性是public或者getter是public
        mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
            /**
             * @param config  Configuration in used: either SerializationConfig or DeserializationConfig, depending on whether method is called during serialization or deserialization
             * @param field Field used to access property
             * @param defaultName Default name that would be used for property in absence of custom strategy
             * @return
             */
            @Override
            public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
                if (field.getFullName().equals("Artist#name"))
                    return "Artist-Name";
                return super.nameForField(config, field, defaultName);
            }

            /**
             * @param config  Configuration in used: either SerializationConfig or DeserializationConfig, depending on whether method is called during serialization or deserialization
             * @param method  Method used to access property.
             * @param defaultName Default name that would be used for property in absence of custom strategy
             * @return
             */
            @Override
            public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
                if (method.getAnnotated().getDeclaringClass().equals(Album.class) && defaultName.equals("title"))
                    return "Album-Title";
                return super.nameForGetterMethod(config, method, defaultName);
            }
        });
        //如果属性没有值,那么Json是会处理的,int类型为0,String类型为null,数组为[],设置这个特性可以忽略空值属性
        mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        mapper.writeValue(System.out, album);
    }
}

class Album {
    private String title;
    private String[] links;
    private List<String> songs = new ArrayList<String>();
    private Artist artist;
    private Map<String, String> musicians = new HashMap<String, String>();

    public Album(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setLinks(String[] links) {
        this.links = links;
    }

    public String[] getLinks() {
        return links;
    }

    public void setSongs(List<String> songs) {
        this.songs = songs;
    }

    public List<String> getSongs() {
        return songs;
    }

    public void setArtist(Artist artist) {
        this.artist = artist;
    }

    public Artist getArtist() {
        return artist;
    }

    public Map<String, String>

    getMusicians() {
        return Collections.unmodifiableMap(musicians);
    }

    public void addMusician(String key, String value) {
        musicians.put(key, value);
    }
}

class Artist {
    public String name;
    public Date birthDate;
    public int age;
    public String homeTown;
    public List<String> awardsWon = new ArrayList<String>();
}
输出:
{
  "Album-Title" : "Kind Of Blue",
  "links" : [ "link1", "link2" ],
  "songs" : [ "So What", "Flamenco Sketches", "Freddie Freeloader" ],
  "artist" : {
    "Artist-Name" : "Miles Davis",
    "birthDate" : "1926-05-26",
    "age" : 0
  },
  "musicians" : {
    "Julian Adderley" : "Alto Saxophone",
    "Miles Davis" : "Trumpet, Band leader",
    "Paul Chambers" : "double bass"
  }
}


Streaming API

    Jackson提供了一套底层API来解析Json字符串,这个API为每个Json对象提供了符号。例如, '{' 是解析器提供的第一个对象(writeStartObject()),键值对是解析器提供的另一个单独对象(writeString(key,value))。这些API很强大,但是需要大量的代码。大多数情况下,Tree Model和Data Binding可以代替Streaming
API。

Json解析

public static void main(String[] args) throws IOException {
// 从JsonFactory获得一个JsonParser实例
JsonFactory factory = new JsonFactory();
//createParser有很多种重载,具体可以看API
JsonParser parser = factory.createParser("{\"title\":\"Free Music Archive - Albums\",\"message\":\"test\",\"errors\":[\"invalid or disabled api_key\"],\"dataset\":[{\"id\":\"1\"},{\"id\":\"2\"}]}");

// 解析符号直到字符串结尾
while (!parser.isClosed()) {
// 如果有必要的话,这个方法会沿着流前进直到足以确下一个JsonToken的类型
JsonToken token = parser.nextToken();
// 如果是最后一个JsonToken,那么就结束了
if (token == null)
break;
//如果JsonToken是JsonToken.FIELD_NAME类型并且当前的name是dataset
if (JsonToken.FIELD_NAME.equals(token) && "dataset".equals(parser.getCurrentName())) {
// 开始解析dateset,第一个JsonToken必须是JsonToken.START_ARRAY"["
token = parser.nextToken();
if (!JsonToken.START_ARRAY.equals(token)) {
break;
}
// 数组的每个元素都是对象,因此下一个JsonToken是JsonToken.START_OBJECT"{"
token = parser.nextToken();
if (!JsonToken.START_OBJECT.equals(token)) {
break;
}
// 输出id字段的值
while (true) {
token = parser.nextToken();
if (token == null)
break;
if (JsonToken.FIELD_NAME.equals(token) && "id".equals(parser.getCurrentName())) {
token = parser.nextToken();
System.out.println(parser.getText());
}
}
}
}
}


Json生成

public static void main(String[] args) throws IOException {
JsonFactory factory = new JsonFactory();
JsonGenerator generator = factory.createGenerator(new BufferedOutputStream(System.out));

generator.writeStartObject();//{
generator.writeFieldName("title");
generator.writeString("Free Music Archive - Albums");
generator.writeFieldName("dataset");
generator.writeStartArray();//[
generator.writeStartObject();//{
generator.writeStringField("album_title", "A.B.A.Y.A.M");
generator.writeEndObject();//}
generator.writeEndArray();//]
generator.writeEndObject();//}
//输出{"title":"Free Music Archive - Albums","dataset":[{"album_title":"A.B.A.Y.A.M"}]}

generator.close();
}


Tree Mode

    如果你不想为你的Json结构写一个class的话,Tree Mode是一个很好的选择。

JSON生成
public static void main(String[] args) throws IOException {
//创建一个提供所有节点的JsonNodeFactory,false表示不创建DecimalNode
JsonNodeFactory factory = new JsonNodeFactory(false);

// 创建JsonFactory,使用Streaming API的方式输出到控制台
JsonFactory jsonFactory = new JsonFactory();
JsonGenerator generator = jsonFactory.createGenerator(System.out);
ObjectMapper mapper = new ObjectMapper();

//创建节点和数据,一个ObjectNode代表一个节点对象
ObjectNode node1 = factory.objectNode();
ObjectNode node2 = factory.objectNode();
node1.put("A", "a");
node1.put("B", "b");
node2.set("C", node1);

// 根节点
ObjectNode root = factory.objectNode();
root.put("root", "root");
root.set("children", node2);
mapper.writeTree(generator, root);
//输出{"root":"root","children":{"C":{"A":"a","B":"b"}}}
}


Json解析
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
// 读取json,将整个json作为根节点
JsonNode node = mapper.readTree("{\"root\":\"root\",\"children\":{\"C\":{\"A\":\"a\",\"B\":\"b\"}}}");
// 看看根节点的类型
System.out.println("node JsonNodeType:" + node.getNodeType());//OBJECT
// 是不是一个ContainerNode(array and object nodes)
System.out.println("node is containerNode ? " + node.isContainerNode());//true
// 得到所有node节点的直接子节点名称
Iterator<String> fieldNames = node.fieldNames();
while (fieldNames.hasNext()) {
String fieldName = fieldNames.next();
System.out.println(fieldName + " ");//root children
}
System.out.println(node.get("root").isContainerNode());//false
}


总结

    这只是基本的用法,其他的如果有用到,再继续添加进来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: