Jackson学习笔记(详细)
学习地址:http://tutorials.jenkov.com/java-json/index.html
github地址:https://github.com/FasterXML/jackson
fasterxml官方地址:http://fasterxml.com/
Jackson ObjectMapper
解析器和生成器
jackson有两个json解析器
- ObjectMapper将Json解析为Java对象或jackson的tree model
- JsonParser,一次解析一个token
jackson有两个json生成器
- ObjectMapper从java对象或tree model生成json
- JsonGenerator,一次生成一个token
如何映射
jackson通过映射java对象的getter和setter方法实现与json串字段的对应,去掉get set,然后将第一个字母小写,如果要实现别的对应,需要定制序列化与反序列化,或者使用一些jackson注解。
jackson可以读取的内容
jackson读取对象、对象数组可以从
- json 字符串
- Reader
- json file
- URL,包括HTTP URL
- InputStream
- ByteArray
- 需要使用new TypeReference<List<Car>>(){}的复杂对象的解析
- 通过json数组读取对象数组
- 通过json数组读取对象List
- 通过json字符串读取map
jackson的配置
// 忽略额外的json字段,默认会抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//null值赋值给java原生类型时抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
定制反序列化器
String json = "{ \"brand\" : \"Ford\", \"doors\" : 6 }";
SimpleModule module =
new SimpleModule("CarDeserializer", new Version(3, 1, 8, null, null, null));
module.addDeserializer(Car.class, new CarDeserializer(Car.class));
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
Car car = mapper.readValue(json, Car.class);
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
public class CarDeserializer extends StdDeserializer<Car> {
public CarDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Car deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException {
Car car = new Car();
while(!parser.isClosed()){
JsonToken jsonToken = parser.nextToken();
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
System.out.println(fieldName);
jsonToken = parser.nextToken();
if("brand".equals(fieldName)){
car.setBrand(parser.getValueAsString());
} else if ("doors".equals(fieldName)){
car.setDoors(parser.getValueAsInt());
}
}
}
return car;
}
}
将对象转化为json
writeValue()
writeValueAsString()
writeValueAsBytes()
定制序列化器
CarSerializer carSerializer = new CarSerializer(Car.class);
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module =
new SimpleModule("CarSerializer", new Version(2, 1, 3, null, null, null));
module.addSerializer(Car.class, carSerializer);
objectMapper.registerModule(module);
Car car = new Car();
car.setBrand("Mercedes");
car.setDoors(5);
String carJson = objectMapper.writeValueAsString(car);
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
public class CarSerializer extends StdSerializer<Car> {
protected CarSerializer(Class<Car> t) {
super(t);
}
public void serialize(Car car, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("producer", car.getBrand());
jsonGenerator.writeNumberField("doorCount", car.getDoors());
jsonGenerator.writeEndObject();
}
}
修改默认的日期序列化格式
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
objectMapper2.setDateFormat(dateFormat);
String output2 = objectMapper2.writeValueAsString(transaction);
System.out.println(output2);
json树模型 JsonNode类
String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode jsonNode = objectMapper.readTree(carJson);
} catch (IOException e) {
e.printStackTrace();
}
String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5," +
" \"owners\" : [\"John\", \"Jack\", \"Jill\"]," +
" \"nestedObject\" : { \"field\" : \"value\" } }";
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);
JsonNode brandNode = jsonNode.get("brand");
String brand = brandNode.asText();
System.out.println("brand = " + brand);
JsonNode doorsNode = jsonNode.get("doors");
int doors = doorsNode.asInt();
System.out.println("doors = " + doors);
JsonNode array = jsonNode.get("owners");
JsonNode jsonNode = array.get(0);
String john = jsonNode.asText();
System.out.println("john = " + john);
JsonNode child = jsonNode.get("nestedObject");
JsonNode childField = child.get("field");
String field = childField.asText();
System.out.println("field = " + field);
} catch (IOException e) {
e.printStackTrace();
}
java对象与JsonNode的转换
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car();
car.brand = "Cadillac";
car.doors = 4;
JsonNode carJsonNode = objectMapper.valueToTree(car);
ObjectMapper objectMapper = new ObjectMapper();
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
JsonNode carJsonNode = objectMapper.readTree(carJson);
Car car = objectMapper.treeToValue(carJsonNode);
ObjectMapper读取其他的数据格式
- CBOR
- MessagePack
- YAML
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import java.io.IOException;
public class YamlJacksonExample {
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
Employee employee = new Employee("John Doe", "john@doe.com");
String yamlString = null;
try {
yamlString = objectMapper.writeValueAsString(employee);
} catch (JsonProcessingException e) {
e.printStackTrace();
// normally, rethrow exception here - or don't catch it at all.
}
try {
Employee employee2 = objectMapper.readValue(yamlString, Employee.class);
System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Jackson JsonNode
JsonNode是不可变的,子类ObjectNode是可变的
将json读取为JsonNode,写为json
JsonNode jsonNode = objectMapper.readTree(json);
String json = objectMapper.writeValueAsString(jsonNode);
获取字段
sonNode jsonNode = ... //parse above JSON into a JsonNode
JsonNode field1 = jsonNode.get("field1");
JsonNode field2 = jsonNode.get("field2");
JsonNode nameNode = jsonNode.at("/identification/name"); //开头必须有/
转化字段的值(注意如果该字段会导致空指针异常)
String f2Str = jsonNode.get("f2").asText();
double f2Dbl = jsonNode.get("f2").asDouble();
int f2Int = jsonNode.get("f2").asInt();
long f2Lng = jsonNode.get("f2").asLong();
提供默认值
ObjectMapper objectMapper = new ObjectMapper();
String json = "{ \"f1\":\"Hello\", \"f2\":null }";
JsonNode jsonNode = objectMapper.readTree(json);
String f2Value = jsonNode.get("f2").asText("Default");
判断是否是有效的JsonNode
JsonNode fieldNode = parentNode.get("fieldName");
if(fieldNode == null || fieldNode.isNull()) {
// the field is either not present in parentNode, or explicitly set to null .
}
递归遍历整个JsonNode
public static void traverse(JsonNode root){
if(root.isObject()){
Iterator<String> fieldNames = root.fieldNames();
while(fieldNames.hasNext()) {
String fieldName = fieldNames.next();
JsonNode fieldValue = root.get(fieldName);
traverse(fieldValue);
}
} else if(root.isArray()){
ArrayNode arrayNode = (ArrayNode) root;
for(int i = 0; i < arrayNode.size(); i++) {
JsonNode arrayElement = arrayNode.get(i);
traverse(arrayElement);
}
} else {
// JsonNode root represents a single value field - do something with it.
}
}
创建ObjectNode,设置值,删除值
//创建
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode parentNode = objectMapper.createObjectNode();
JsonNode childNode = readJsonIntoJsonNode();
parentNode.set("child1", childNode);
//直接赋值原生类型
objectNode.put("field1", "value1");
objectNode.put("field2", 123);
objectNode.put("field3", 999.999);
//删除值
objectNode.remove("fieldName");
遍历JsonNode的字段
Iterator<Map.Entry<String, JsonNode>> fields = jsonNode.fields();
while(fields.hasNext()) {
Map.Entry<String, JsonNode> field = fields.next();
String fieldName = field.getKey();
JsonNode fieldValue = field.getValue();
System.out.println(fieldName + " = " + fieldValue.asText());
}
遍历字段名
Iterator<String> fieldNames = jsonNode.fieldNames();
while(fieldNames.hasNext()) {
String fieldName = fieldNames.next();
JsonNode field = jsonNode.get(fieldName);
}
Jackson JsonParser
JsonParser相对于ObjectMapper是low-level的Json解析器,因此也更快,但也更笨重。通过解析器解析就是将json分解为一个一个的token,然后迭代
创建解析器,解析(也可以直接从objectMapper创建)
String carJson =
"{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(carJson);
Car car = new Car();
while(!parser.isClosed()){
JsonToken jsonToken = parser.nextToken();
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
System.out.println(fieldName);
jsonToken = parser.nextToken();
if("brand".equals(fieldName)){
car.brand = parser.getValueAsString();
} else if ("doors".equals(fieldName)){
car.doors = parser.getValueAsInt();
}
}
}
System.out.println("car.brand = " + car.brand);
System.out.println("car.doors = " + car.doors);
token的类型有以下几种,可以通过这些常量找出当前token的类型
START_OBJECT END_OBJECT START_ARRAY END_ARRAY FIELD_NAME VALUE_EMBEDDED_OBJECT VALUE_FALSE VALUE_TRUE VALUE_NULL VALUE_STRING VALUE_NUMBER_INT VALUE_NUMBER_FLOAT
Jackson JsonGenerator
创建Json生成器、生成json
JsonFactory factory = new JsonFactory();
JsonGenerator generator = factory.createGenerator(
new File("data/output.json"), JsonEncoding.UTF8);
generator.writeStartObject(); //写入{
generator.writeStringField("brand", "Mercedes");
generator.writeNumberField("doors", 5);
generator.writeEndObject(); //写入}
generator.close();
Jackson Annotations
- Read + Write Annotations
- @JsonIgnore 忽略该属性的序列化和反序列化
- @JsonIgnoreProperties 忽略一组属性的序列化和反序列化,放在类上,@JsonIgnoreProperties({"firstName", "lastName"})
- @JsonIgnoreType 忽略该类型的属性(所有出现的地方)
- @JsonAutoDetect 包含非public的字段,放在类上,@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
- Read Annotations
- @JsonSetter 放在setter方法上,修改读取的json字段名,@JsonSetter("id")
- @JsonAnySetter 对于未识别的Json字段将调用该注解放的set方法上
- @JsonCreator @JsonAnySetter不可以用的时候用,用该注解标注的构造器创建,也需要标注哪些参数需要构造
- @JacksonInject 通过注入的方式赋值该字段的值
- @JsonDeserialize 指定定制的反序列化器
- Write Annotations
- @JsonInclude 放在类上,指定非空才序列化@JsonInclude(JsonInclude.Include.NON_EMPTY),
@JsonInclude(Include.NON_NULL)指定非null才序列化
- @JsonGetter 修改序列化的字段名
- @JsonAnyGetter 将该注解标注的方法返回的值其中的kv单独拿出来序列化
- @JsonPropertyOrder 放在类上,指定字段序列化的顺序
- @JsonRawValue 该注解标注的字段会去掉字符串的引号进行序列化
- @JsonValue 序列化时不序列化对象,而是调用该注解标注的方法
- @JsonSerialize 指定序列化器
- @JsonInclude 放在类上,指定非空才序列化@JsonInclude(JsonInclude.Include.NON_EMPTY),
总结:
- Java对象到Json字符串:objectMapper.writeValueAsString(user)
- 可以定制序列化器
- Json到Java对象
- 简单类型:objectMapper.readValue(jsonString, User.class);
- 复杂类型:objectMapper.readValue(jsonString, new TypeReference<List<User>>(){});
- 可以定制反序列化器,Custom Deserializer
-
核心模块(三个)
databind依赖于streaming和annotations,使用这一个就可以了
地址:https://github.com/FasterXML/jackson-databind,doc见wiki
-
介绍
其他格式的也支持,只要实现了解析器和生成器
mvn仓库
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>
如果使用java8的LocalDateTime需要引入jackson-datatype-jsr310(依赖于databind)的maven,且需要使用objectMapper.findAndRegisterModules()代码注册模块。
-
简单使用
//Java对象转为JSON字符串
user = new User();
objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules(); //使用java8的localDateTime时使用,但是日期还是有问题,需要在日期的属性上加@JsonFormat(paattern = "yyyy-MM-dd HH:mm:ss")
String jsonString = objectMapper.writeValueAsString(user); //返回json字符串
//JSON字符串转为Java对象
objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
objectMapper.readValue(jsonString, User.class); //简单类型, 有对应的实体类, 如果有泛型会出问题,反序列化的时候会把泛型丢掉, 使用new TypeReference<复杂类型>(){}
objectMapper.readValue(jsonString, new TypeReference<List<User>>(){}); //复杂类型
//修改属性名
@JsonProperty("changedName") //在属性上加
//忽略属性
@JsonIgnore //在属性上加
@JsonIgnoreProperties({"name1", "name2"}) //在类上加
-
复杂类型使用
/**
* 复杂类型转换1
*/
@Test
public void test() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User2 user2 = new User2();
user2.setId(1001);
user2.setName("zhangsan");
ArrayList<Account> accList = new ArrayList<>();
Account acc1 = new Account(100, "100");
Account acc2 = new Account(200, "200");
accList.add(acc1);
accList.add(acc2);
HashMap<String, Account> accMap = new HashMap<>();
accMap.put("zhang10", acc1);
accMap.put("zhang20", acc2);
user2.setAccList(accList);
user2.setAccMap(accMap);
String s = mapper.writeValueAsString(user2);
System.out.println(s);
User2 user21 = mapper.readValue(s, User2.class);
System.out.println(user21);
}
/**
* 复杂类型转换2
* List, Map转换, 简单类型可以直接使用,复杂类型使用TypeReference
*/
@Test
public void test02() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
ArrayList<User> list = new ArrayList<>();
User u1 = new User(1001, "zhang1001");
User u2 = new User(1002, "zhang1002");
list.add(u1);
list.add(u2);
String s = mapper.writeValueAsString(list);
System.out.println(s);
List list1 = mapper.readValue(s, List.class);
System.out.println(list1);
//
System.out.println("----------------------");
HashMap<String, User> map = new HashMap<>();
map.put("10", u1);
map.put("20", u2);
String s1 = mapper.writeValueAsString(map);
System.out.println(s1);
Map map1 = mapper.readValue(s1, Map.class); //返回值没有泛型信息
System.out.println(map1);
System.out.println("--------");
Object o = map1.get("10"); //强转报错
// User o = (User) map1.get("10"); //强转报错
Map<String, User> map2 = mapper.readValue(s1, new TypeReference<Map<String, User>>() {
});
System.out.println(map2);
User user = map2.get("10");
System.out.println(user);
}
-
Tree Model
将Json转化为树结构
/**
* 使用 tree 模型, 类似于JSONObject
*/
@Test
public void test03() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user = new User(1001, null);
String s = mapper.writeValueAsString(user);
JsonNode node = mapper.readTree(s);
System.out.println(node.toString());
System.out.println("------------");
JsonNode jsonNode = node.get("id");
int id = node.get("id").asInt();
String name = node.get("name").asText();
String name1 = node.get("name").asText("123");
System.out.println(name);
System.out.println(name1);
System.out.println(id);
}
-
Streaming parser, generator
流处理
/**
* Streaming parser, generator
* 将json写入流
*/
@Test
public void test04() throws IOException {
ObjectMapper mapper = new ObjectMapper();
File jsonfile = new File("test.json");
JsonGenerator g = mapper.createGenerator(jsonfile, JsonEncoding.UTF8);
g.writeStartObject();
g.writeStringField("message", "hello world");
g.writeEndObject();
g.close();
boolean newFile = jsonfile.createNewFile(); //写入文件
//从流写回
JsonParser p = mapper.createParser(jsonfile);
JsonToken t = p.nextToken();
t = p.nextToken();
if ((t != JsonToken.FIELD_NAME) || (!"message".equals(p.getCurrentName()))) {
System.out.println("handle error");
}
t = p.nextToken();
if (t != JsonToken.VALUE_STRING) {
System.out.println("handle error..");
}
String text = p.getText();
System.out.println("my message: " + text);
}
-
配置(特性、注解)
所有配置:https://github.com/FasterXML/jackson-databind/wiki/JacksonFeatures
特性配置(higher-level data-binding configuration)
//序列化
// SerializationFeature for changing how JSON is written
// to enable standard indentation ("pretty-printing"):
mapper.enable(SerializationFeature.INDENT_OUTPUT); //开启序列化标准缩进
// to allow serialization of "empty" POJOs (no properties to serialize)
// (without this setting, an exception is thrown in those cases)
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); //关闭空bean序列化异常, 允许空bean的序列化
// to write java.util.Date, Calendar as number (timestamp):
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); //关闭date序列化为时间戳
//反序列化
// DeserializationFeature for changing how JSON is read as POJOs:
// to prevent exception when encountering unknown property:
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //关闭反序列化未知属性的异常
// to allow coercion of JSON empty String ("") to null Object value:
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); //开启空字符串反序列化为null
特性配置(low-level JSON parsing, generation details)
//解析json特性
// JsonParser.Feature for configuring parsing settings:
// to allow C/C++ style comments in JSON (non-standard, disabled by default)
// (note: with Jackson 2.5, there is also `mapper.enable(feature)` / `mapper.disable(feature)`)
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); //允许注释的存在
// to allow (non-standard) unquoted field names in JSON:
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); //允许字段名未使用双引号
// to allow use of apostrophes (single quotes), non standard
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); //允许字段名使用单引号
//生成json特性
// JsonGenerator.Feature for configuring low-level JSON generation:
// to force escaping of non-ASCII characters:
mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true); //强制生成非ascii码字符
注解
public class MyBean {
private String _name;
// without annotation, we'd get "theName", but we want "name":
@JsonProperty("name")
public String getTheName() { return _name; }
// note: it is enough to add annotation on just getter OR setter;
// so we can omit it here
public void setTheName(String n) { _name = n; }
}
// means that if we see "foo" or "bar" in JSON, they will be quietly skipped
// regardless of whether POJO has such properties
@JsonIgnoreProperties({ "foo", "bar" })
public class MyBean
{
// will not be written as JSON; nor assigned from JSON:
@JsonIgnore
public String internal;
// no annotation, public field is read/written normally
public String external;
@JsonIgnore
public void setCode(int c) { _code = c; }
// note: will also be ignored because setter has annotation!
public int getCode() { return _code; }
}
public class ReadButDontWriteProps {
private String _name;
@JsonProperty public void setName(String n) { _name = n; }
@JsonIgnore public String getName() { return _name; }
}
使用定制构造器
public class CtorBean
{
public final String name;
public final int age;
@JsonCreator // constructor can be public, private, whatever
private CtorBean(@JsonProperty("name") String name,
@JsonProperty("age") int age)
{
this.name = name;
this.age = age;
}
}
public class FactoryBean
{
// fields etc omitted for brevity
@JsonCreator
public static FactoryBean create(@JsonProperty("name") String name) {
// construct and return an instance
}
}
-
POJO到POJO的转换
直接转换,只要to-JSON,from-JSON正常就可以使用
-
使用建造者模式 + Jackson
在反序列化时指定建造者进行反序列化
本文来自博客园,作者:Bingmous,转载请注明原文链接:https://www.cnblogs.com/bingmous/p/15643669.html