- Data Binding
- 序列化
- 数据绑定
- 泛型绑定
- 数组绑定
- 线程安全
- Tree Model
- Streaming API
- SerializationFeature
- WRAP_ROOT_VALUE
- INDENT_OUTPUT
- WRITE_DATES_AS_TIMESTAMPS
- WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS
- ORDER_MAP_ENTRIES_BY_KEYS
- DeserializationFeature
- FAIL_ON_UNKNOWN_PROPERTIES
- MapperFeature
- ACCEPT_CASE_INSENSITIVE_PROPERTIES
- 注解
- JsonProperty
- JsonInclude
- JsonSerialize
- module
Jackson 提供了三种对JSON处理的方式
- Data Binding
- Tree Model
- Streaming API
Data Binding
这种方式提供了JSON数据和Java对象之间的无缝转换,而且这种方式是相当便利的. 它内部基于 Streaming API 的JSON 读写系统, 尽管Data Binding 是非常高效地,但是相比纯 streaming/incremental 方式,仍然有一些额外的性能消耗.
序列化
1 2 3 4 5 6 7 8 9 10 11
| @Test public void test_Serialization() throws IOException { Obj obj = new Obj(); obj.platform = "qq"; StringWriter stringWriter = new StringWriter();
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.writeValue(stringWriter, obj);
System.out.println(stringWriter); }
|
输出为{"platform":"qq"}
数据绑定
1 2 3 4 5 6 7
| @Test public void test_ObjectMapperRead () throws IOException { String jsonStr = "{\"platform\":\"1\"}"; ObjectMapper objectMapper = new ObjectMapper(); Obj obj = objectMapper.readValue(jsonStr, Obj.class); System.out.println(obj.platform); }
|
输出为1
泛型绑定
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void test_Serialization() throws IOException { Map<Integer, String> map = new HashMap<>(); map.put(2016, "10/11"); StringWriter stringWriter = new StringWriter();
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.writeValue(stringWriter, map);
Map<Integer, String> newMap = objectMapper.readValue(stringWriter.toString(), new TypeReference<Map<Integer, String>>() {}); System.out.println(newMap.get(2016)); }
|
输出为10/11
数组绑定
1 2 3 4 5 6 7 8 9 10 11
| @Test public void test_Binding() throws IOException { String[] array = {"2016"}; StringWriter stringWriter = new StringWriter();
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.writeValue(stringWriter, array);
String[] arr = objectMapper.readValue(stringWriter.toString(), String[].class); System.out.println(arr[0]); }
|
线程安全
ObjectMapper被共享出来之后, 只要重新配置共享实例, 那么它就是线程安全的. 也就是不要调用下列方法
enable()
disable()
configure()
参考
Tree Model
Tree Model 和XML 处理方式 非常类似.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Test;
public class TestTreeModel {
@Test public void test_() throws Exception { Obj1 obj1 = new Obj1(); Obj2 obj2 = new Obj2(); Obj3 obj3 = new Obj3(); obj1.obj2 = obj2; obj2.obj3 = obj3; obj3.string = "hello";
ObjectMapper objectMapper = new ObjectMapper(); String str = objectMapper.writeValueAsString(obj1); JsonNode objtree = objectMapper.readTree(str); System.out.println("get obj2 : " + objtree.get("obj2")); System.out.println("get obj3 : " + objtree.get("obj3")); System.out.println("get string : " + objtree.get("string"));
System.out.println("path obj2 : " + objtree.path("obj2")); System.out.println("path obj3 : " + objtree.path("obj3")); System.out.println("path string : " + objtree.path("string"));
System.out.println("path string obj2 -> obj3 -> string : " + objtree.path("obj2").path("obj3").path("string")); }
private static class Obj1 { public Obj2 obj2; }
private static class Obj2 { public Obj3 obj3; }
private static class Obj3 { public String string; } }
|
输出结果为
1 2 3 4 5 6 7
| get obj2 : {"obj3":{"string":"hello"}} get obj3 : null get string : null path obj2 : {"obj3":{"string":"hello"}} path obj3 : path string : path string obj2 -> obj3 -> string : "hello"
|
当调用get()方法时, 如果找不到的话, 会返回null, 而path()找不到的话则会返回MissingNode
还有一个方法with(int index)我们没有演示, 这个方法是如果找不到就添加.
get()方法还有一个特别有用的地方就是用来处理数组.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Test;
public class TestTreeModel {
@Test public void test_() throws Exception { Obj1 obj1 = new Obj1();
ObjectMapper objectMapper = new ObjectMapper(); String str = objectMapper.writeValueAsString(obj1); System.out.println(str);
JsonNode tree = objectMapper.readTree(str); System.out.println(tree.get("strings").get(1)); }
private static class Obj1 { public String[] strings = {"123", "456"}; } }
|
结果为
1 2
| {"strings":["123","456"]} "456"
|
Streaming API
Streaming API 是 Jackson处理 JSON最高效地方式. 但是它的易用性却大大地降低了, 我们不能像Data Binding 或者 Tree Model 那样随机访问元素.
SerializationFeature
WRAP_ROOT_VALUE
是否环绕根元素,默认false,如果为true,则默认以类名作为根元素,也可以通过@JsonRootName来自定义根元素名称
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import org.junit.Test;
import java.io.IOException;
public class TestDataBinding {
@Test public void test_SerializationFeature () throws IOException { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE); System.out.println( objectMapper.writeValueAsString(new Obj())); }
public static class Obj { public String platform = "example"; } }
|
结果为{"Obj":{"platform":"example"}} 如果不开启WRAP_ROOT_VALUE的话, 结果为{"platform":"example"}
INDENT_OUTPUT
是否缩放排列输出
1
| objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
结果为
1 2 3
| { "platform" : "example" }
|
WRITE_DATES_AS_TIMESTAMPS
序列化日期时以timestamps输出
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class TestDataBinding {
@Test public void test_SerializationFeature () throws IOException { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); System.out.println( objectMapper.writeValueAsString(new Obj())); }
public static class Obj { public Date now = new Date(); } }
|
结果为
WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS
序列化char[]时以json数组输出
ORDER_MAP_ENTRIES_BY_KEYS
序列化Map时对key进行排序操作
DeserializationFeature
FAIL_ON_UNKNOWN_PROPERTIES
在反序列化时, 如果Java对象中不包含json串的某个数据 属性, 则会报错.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class TestDataBinding {
@Test public void test_SerializationFeature () throws IOException { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
String str = "{\"strings1\":[\"123\"],\"strings2\":[\"456\"]}"; objectMapper.readValue(str, Obj.class); }
public static class Obj { public String[] strings1 = {"123"}; } }
|
MapperFeature
ACCEPT_CASE_INSENSITIVE_PROPERTIES
在反序列化时是否忽略大小写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Test;
import java.io.IOException;
public class TestDataBinding {
@Test public void test_SerializationFeature () throws IOException { ObjectMapper objectMapper = new ObjectMapper(); Upper upper = new Upper(); upper.setFirstName("John"); System.out.println(objectMapper.writeValueAsString(upper));
Lower lower = new Lower(); lower.setLastName("li"); System.out.println(objectMapper.writeValueAsString(lower));
}
@Test public void test_DeserializationFeature () throws IOException { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
Upper obj1 = objectMapper.readValue("{\"firstName\":\"John\"}", Upper.class); System.out.println(obj1.getFirstName());
Upper obj2 = objectMapper.readValue("{\"FirstName\":\"John\"}", Upper.class); System.out.println(obj2.getFirstName()); } }
class Upper { private String FirstName; public String getFirstName() {return FirstName;} public void setFirstName(String firstName) {FirstName = firstName;} }
class Lower { private String lastName; public String getLastName() {return lastName;} public void setLastName(String lastName) {this.lastName = lastName;} }
|
在test_SerializationFeature()这个测试中, 我们可以通过结果看到, Upper的FirstName在JSON串 中成了firstName. 当反序列化得时候, 如果不指定ACCEPT_CASE_INSENSITIVE_PROPERTIES, 那么当JSON串中的FirstName为大写的时候, 是没办法序列化出来的.
注解
JsonProperty
jackson 默认是根据Getter来进行注值反序列化的, 但是有时候为了节省存储空间, 字段名远小于Getter名称, 这样就造成了字段名和方法名不一致, 此时就可以利用JsonProperty注解重命名来解决这个问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Test;
import java.io.IOException;
public class TestDataBinding {
@Test public void test_Deferent () throws IOException { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
Different different = new Different(); different.setMiddle("Nice"); System.out.println(objectMapper.writeValueAsString(different));
Different obj2 = objectMapper.readValue("{\"middle\":\"Nice\"}", Different.class); System.out.println(obj2.getMiddle());
Different obj3 = objectMapper.readValue("{\"Mid\":\"Nice\"}", Different.class); System.out.println(obj3.getMiddle());
Different obj4 = objectMapper.readValue("{\"mid\":\"Nice\"}", Different.class); System.out.println(obj4.getMiddle()); } }
class Different { @JsonProperty("mid") private String Mid; public String getMiddle() {return Mid;} public void setMiddle(String middle) {this.Mid = middle;} }
|
说到这里就需要点出一个坑了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import com.alibaba.fastjson.JSON; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson;
import java.io.IOException;
public class TestPrivate {
public static void main(String[] args) throws IOException { ObjectMapper objectMapper = new ObjectMapper();
SimpleId simpleId = new SimpleId(); simpleId.setString("simple Id"); String json = objectMapper.writeValueAsString(simpleId); System.out.println("Jsckson ---> " + json);
Gson gson = new Gson(); json = gson.toJson(simpleId); System.out.println("Gson ---> " + json);
json = JSON.toJSONString(simpleId); System.out.println("FastJson ---> " + json); }
public static class SimpleId { private String stringId; private String stringName = "empty name";
public String getString() { return stringId; }
public void setString(String string) { this.stringId = string; }
public String getString1() { return "123456"; } } }
|
结果为
1 2 3
| Jsckson ---> {"string":"simple Id","string1":"123456"} Gson ---> {"stringId":"simple Id","stringName":"empty name"} FastJson ---> {"string":"simple Id","string1":"123456"}
|
有时候我们需要Gson这种输出结果, 即不使用Getter, 而是使用filed进行序列化, 怎么办呢?我们可以使用 @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE), 但是对于有时候我们并不想在每个类上面都加一个这样的注解, 配置一些ObjectMapper就可以了
1 2 3 4 5 6
| ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker() .withFieldVisibility(JsonAutoDetect.Visibility.ANY) .withGetterVisibility(JsonAutoDetect.Visibility.NONE) .withSetterVisibility(JsonAutoDetect.Visibility.NONE) .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
|
这样结果为
1 2 3
| Jsckson ---> {"stringId":"simple Id","stringName":"empty name"} Gson ---> {"stringId":"simple Id","stringName":"empty name"} FastJson ---> {"string":"simple Id","string1":"123456"}
|
JsonInclude
指定在序列化时, 可以输出哪些值. 例如只输出非默认值(包含类型默认值和初始化默认值)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Test;
public class TestDefault { @Test public void test_() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); Foo foo = new Foo(); foo.string1 = "123"; System.out.println(objectMapper.writeValueAsString(foo)); } }
@JsonInclude(JsonInclude.Include.NON_DEFAULT) class Foo { public String string1; public String string2 = "xxx"; public String string3; }
|
JsonSerialize
实现浮点数只保留俩位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.junit.Test;
import java.io.IOException; import java.text.DecimalFormat;
public class TestDouble {
@Test public void test_() throws JsonProcessingException { DoubleObject doubleObject = new DoubleObject(); doubleObject.aDouble = 1.101010101010101; doubleObject.aFloat = 1.101010101010101f;
ObjectMapper objectMapper = new ObjectMapper(); String string = objectMapper.writeValueAsString(doubleObject); System.out.println(string); }
public static class CustomDoubleSerializer extends JsonSerializer<Number> { @Override public void serialize(Number value, JsonGenerator jgen, SerializerProvider provider) throws IOException { if (null == value) { jgen.writeNull(); } else if (value instanceof Double || value instanceof Float){ final String pattern = ".##"; final DecimalFormat myFormatter = new DecimalFormat(pattern); final String output = myFormatter.format(value); jgen.writeNumber(output); } } }
public static class DoubleObject { @JsonSerialize(using = CustomDoubleSerializer.class) private double aDouble; @JsonSerialize(using = CustomDoubleSerializer.class) private float aFloat; public double getaDouble() {return aDouble;} public void setaDouble(double aDouble) {this.aDouble = aDouble;} public float getaFloat() {return aFloat;} public void setaFloat(float aFloat) {this.aFloat = aFloat;} } }
|
module
可以通过module来自定义实现 序列化和反序列机制. 下面的例子中就是演示对Double类型的序列化时保留浮点数位数的实现
注意 如果注解和自定义序列化重复时, 那么注解的设置会覆盖自定义序列化机制. 而且对于原生类型来说, 是区分原生类型和包装类型的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException; import java.text.DecimalFormat;
public class TestModule {
private static final ObjectMapper objectMapper;
static { objectMapper = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); simpleModule.addSerializer(Double.class, new CustomFiveDoubleSerializer()); simpleModule.addSerializer(double.class, new CustomFiveDoubleSerializer()); objectMapper.registerModule(simpleModule); }
public static class CustomFiveDoubleSerializer extends JsonSerializer<Number> { @Override public void serialize(Number value, JsonGenerator jgen, SerializerProvider provider) throws IOException { if (null == value) { jgen.writeNull(); } else if (value instanceof Double || value instanceof Float){ final String pattern = ".#####"; final DecimalFormat myFormatter = new DecimalFormat(pattern); final String output = myFormatter.format(value); jgen.writeNumber(output); } } }
public static class CustomOneDoubleSerializer extends JsonSerializer<Number> { @Override public void serialize(Number value, JsonGenerator jgen, SerializerProvider provider) throws IOException { if (null == value) { jgen.writeNull(); } else if (value instanceof Double || value instanceof Float){ final String pattern = ".#"; final DecimalFormat myFormatter = new DecimalFormat(pattern); final String output = myFormatter.format(value); jgen.writeNumber(output); } } }
public static void main(String[] args) throws JsonProcessingException { Obj obj = new Obj(); obj.aDouble1 = 1.111111111111; obj.aDouble2 = 1.111111111111;
System.out.println(objectMapper.writeValueAsString(obj)); }
public static class Obj { public Double aDouble1; @JsonSerialize(using = CustomOneDoubleSerializer.class) public Double aDouble2; }
}
|