1. wiki
用于 Json 和 XML(基于jackson-dataformat-xml) 与 JavaBean 之间的序列化和反序列化
2. 模块
jackson-core
:核心包,定义了低级流(Streaming) API,提供基于“流模式”解析。Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json;
jackson-annotations
:注解包,提供标准的 Jackson 注解功能;
jackson-databind
:数据绑定包,实现了数据绑定(和对象序列化)支持,它依赖于 Streaming 和 Annotations 包。提供基于“对象绑定”解析的 API(ObjectMapper) 和“树模型”解析的 API(JsonNode),两者则依赖基于“流模式”解析的API。
一般必须引入以下3个依赖
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
| <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency>
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.9.8</version> </dependency>
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.9.8</version> </dependency>
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-yaml</artifactId> <version>2.9.8</version> </dependency>
|
3. 核心类
3.1. ObjectMapper
常用功能:
- 从字符串、流或文件中解析 JSON,并创建表示已解析的 JSON 的 Java 对象(反序列化)。
- 将 Java 对象构建成 JSON 字符串(序列化)。
- 将 JSON 解析为自定义类的对象,也可以解析 JSON 树模型的对象。
一般遵循已下规则的属性都可以被序列化和反序列化:
- public 修饰的属性可序列化和反序列化。
- 属性提供 public 的 getter/setter 方法,该属性可序列化和反序列化。
- 属性只有 public 的 setter 方法,而无 public 的 getter 方法,该属性只能用于反序列化。
3.1.1. JavaBean 与 json
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
| private static ObjectMapper mapper = new ObjectMapper();
WeChat weChat = new WeChat(); weChat.setId("hello"); weChat.setName("world"); weChat.setInterest(new String[]{"Java", "Python", "C"}); String result = mapper.writeValueAsString(weChat); System.out.println(result);
String json = "{\"id\":\"hello\",\"name\":\"world\",\"interest\":[\"Java\",\"Python\",\"C\"]}"; WeChat weChat = mapper.readValue(json, WeChat.class); System.out.println(weChat);
String json = ...; Map<String, Object> map1 = mapper.readValue(json, new TypeReference<Map<String, Object>>() {}); List<WeChat> list1 = mapper.readValue(jsonStr, new TypeReference<List<WeChat>>() {}); Map<String, Object> map2 = mapper.readValue(json, Map.class); List<WeChat> list2 = mapper.readValue(jsonStr, List.class);
WeChat weChat = ...; mapper.writeValue(new File("/json.txt"), weChat); WeChat weChat1 = mapper.readValue(new File("/json.txt"), WeChat.class);
WeChat weChat = ...; byte[] bytes = mapper.writeValueAsBytes(weChat); WeChat weChat1 = mapper.readValue(bytes, WeChat.class);
|
3.1.2. JSON 树模型
JSON树模型,用于字符串比较大但不是所有字段都需要时,灵活的获取所需的字段内容。其中 get 方法和 path 功能相似,区别在于:
- 如果要读取的 key 在Json串中不存在时,get 方法会 null,
- 而 path 会返回 MissingNode 实例对象,在链路方法情况下保证不会抛出异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
ObjectNode root = mapper.createObjectNode(); root.put("id", "hello"); root.put("name", "world"); ArrayNode interest = root.putArray("interest"); interest.add("Java"); interest.add("Python"); interest.add("C");
String json = mapper.writeValueAsString(root);
String json = ...; JsonNode jsonNode = mapper.readTree(json); String name = jsonNode.path("name").asText(); JsonNode interestNode = jsonNode.get("interest"); if (interestNode.isArray()){ for (JsonNode node : interestNode){ System.out.println(node.asText()); } }
|
3.1.3. 格式化统一配置
可以统一配置一些需要的参数。在2.2版本中新增了一个 ObjectMapper 的实现类 JsonMapper,功能与 ObjectMapper 一致,但是可以使用链式配置
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
| static{ mapper.enable(SerializationFeature.INDENT_OUTPUT); mapper.setSerializationInclusion(Include.ALWAYS); mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true); mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); mapper.registerModule(new JavaTimeModule()); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); }
|
3.2. 常用注解
@JsonProperty
:作用JavaBean字段上,指定一个字段用于JSON映射,默认情况下映射的JSON字段与注解的字段名称相同。可通过value属性指定映射的JSON的字段名称
@JsonIgnore
:可用于字段、getter/setter、构造函数参数上,指定字段不参与序列化和反序列化
@JsonValue
:反序列化时,指定将枚举字段反序列化为什么值
@JsonIgnoreProperties
:作用于类上,序列化时@JsonIgnoreProperties({"prop1", "prop2"})
会忽略 pro1 和 pro2 两个属性。反序列化时@JsonIgnoreProperties(ignoreUnknown=true)
会忽略类中不存在的字段。
@JsonFormat
:作用于字段上,通常用来进行格式化操作。@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
3.3. 自定义解析器
可自定义解析器
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class MyFastjsonDeserialize extends JsonDeserializer<Point> {
@Override public Point deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { JsonNode node = jsonParser.getCodec().readTree(jsonParser); Iterator<JsonNode> iterator = node.get("coordinates").elements(); List<Double> list = new ArrayList<>(); while (iterator.hasNext()) { list.add(iterator.next().asDouble()); } return new Point(list.get(0), list.get(1)); } }
|
定义完成之后,注册到Mapper中:
1 2 3 4
| ObjectMapper objectMapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addDeserializer(Point.class, new MyFastjsonDeserialize()); objectMapper.registerModule(module);
|
3.4. 解析 XML
1 2 3 4 5
| WeChat weChat = ...; XmlMapper xmlMapper = new XmlMapper(); String xml = xmlMapper.writeValueAsString(weChat); System.out.println(xml);
|
结果
1 2 3 4 5 6 7 8 9
| <WeChat> <id>hello</id> <name>world</name> <interest> <interest>Java</interest> <interest>Python</interest> <interest>C</interest> </interest> </WeChat>
|
3.5 @JsonTypeInfo
及相关注解
1. @JsonTypeInfo
作用在接口或类上,被用来开启多态类型的处理,对基类、接口、子类、实现类都有效,语法为 @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = “name”)
。
use
:定义使用哪一种类型识别码,可选值:
JsonTypeInfo.Id.CLASS
:使用完全限定类名做识别
JsonTypeInfo.Id.MINIMAL_CLASS
:若基类和子类在同一包类,使用忽略包名的类名作为识别码
JsonTypeInfo.Id.NAME
:一个合乎逻辑的指定名称
JsonTypeInfo.Id.CUSTOM
:自定义识别码,由 @JsonTypeIdResolver
对应,稍后解释
JsonTypeInfo.Id.NONE
:不使用识别码
include
:可选,指定识别码是如何被包含进去的,可选值:
JsonTypeInfo.As.PROPERTY
:作为数据的兄弟属性
JsonTypeInfo.As.EXISTING_PROPERTY
:作为 POJO 中已经存在的属性,需要手动 set
JsonTypeInfo.As.EXTERNAL_PROPERTY
:作为扩展属性
JsonTypeInfo.As.WRAPPER_OBJECT
:作为一个包装的对象
JsonTypeInfo.As.WRAPPER_ARRAY
:作为一个包装的数组
property
:可选,制定识别码的属性名称,此属性只有如下情况时才有效:
use
为 JsonTypeInfo.Id.CLASS
(默认为 @class)、JsonTypeInfo.Id.MINIMAL_CLASS
(默认为@c)、JsonTypeInfo.Id.NAME
(默认为 @type)
include
为 JsonTypeInfo.As.PROPERTY、JsonTypeInfo.As.EXISTING_PROPERTY、JsonTypeInfo.As.EXTERNAL_PROPERTY
defaultImpl
:可选,如果类型识别码不存在或者无效,可以使用该属性来制定反序列化时使用的默认类型
visible
:可选,定义了类型标识符的值是否会通过 JSON 流成为反序列化器的一部分,默认为 fale,也就是说,jackson 会从 JSON 内容中处理和删除类型标识符再传递给 JsonDeserializer
2. @JsonSubTypes
作用于类或接口,用来列出给定类的子类,只有当子类类型无法被检测到时才会使用它,一般是配合 @JsonTypeInfo
在基类上使用。
1 2 3 4
| @JsonSubTypes({ @JsonSubTypes.Type(name="Dog", value=Dog.class) @JsonSubTypes.Type(name="Cat", value=Cat.class) })
|
- 它值是一个
@JsonSubTypes.Type[]
数组,里面枚举了多态类型
value
为相应子类
name
为类型的标识符,对应 @JsonTypeInfo
中的 property 标识名称的值,此为可选值,若不指定需由 @JsonTypeName
在子类上指定)
3. @JsonTypeName
作用于子类,用来为多态子类指定类型标识符的值。
1 2 3 4 5 6 7 8 9 10 11 12
| @JsonTypeInfo( use = Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "animalType", visible = true) @JsonSubTypes({ @JsonSubTypes.Type(name="Dog", value=Dog.class), @JsonSubTypes.Type(name="Cat", value=Cat.class), }) public class Animal{ private String animalType; }
|
等效于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @JsonTypeInfo( use = Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "animalType", visible = true) @JsonSubTypes({ @JsonSubTypes.Type(value=Dog.class), @JsonSubTypes.Type(value=Cat.class), }) public class Animal{ private String animalType; }
@JsonTypeName("Dog") public class Dog extends Animal {}
|
4. @JsonTypeIdResolver
通过 @JsonSubtypes
来实现多态序列化,在有些情况下会比较麻烦,如新增子类的时候,需要添加一下 @JsonSubTypes
。此时,可以使用 JsonTypeInfo.Id.CUSTOM
策略,然后实现自定义实现 TypeIdResolve
。
1 2 3 4 5 6
| @JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, property = "type") @JsonTypeIdResolver(AnimalTypeIdResolver.class)
public class AnimalTypeIdResolver extends TypeIdResolverBase {}
|
其中有主要的 2 个重要方法:
idFromValueAndType
:序列化的时,如何生成标识符
typeFromId
:是反序列化的时,如何根据标识符来识别到具体类型
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
| public class AnimalTypeIdResolver extends TypeIdResolverBase { @Override public String idFromValue(Object value) { return idFromValueAndType(value, value.getClass()); }
@Override public String idFromValueAndType(Object value, Class<?> suggestedType) { if (suggestedType.isAssignableFrom(Cat.class)) { return "cat"; } else if (suggestedType.isAssignableFrom(Dog.class)) { return "dog"; } else if (suggestedType.isAssignableFrom(Wolf.class)) { return "wolf"; } return null; }
@Override public JavaType typeFromId(DatabindContext context, String id) { if ("cat".equals(id)) { return context.constructType(Cat.class); } else if ("dog".equals(id)) { return context.constructType(Dog.class); } return null; }
@Override public JsonTypeInfo.Id getMechanism() { return JsonTypeInfo.Id.NAME; } }
|