JSON 框架系列之 Jackson 总结
https://github.com/FasterXML/jackson
https://github.com/FasterXML/jackson-docs
Core modules
Core modules are the foundation on which extensions (modules) build upon. There are 3 such modules currently (as of Jackson 2.x):
- Streaming (docs) (“jackson-core”) defines low-level streaming API, and includes JSON-specific implementations
- Annotations (docs) (“jackson-annotations”) contains standard Jackson annotations
- Databind (docs) (“jackson-databind”) implements data-binding (and object serialization) support on
streamingpackage; it depends both onstreamingandannotationspackages
Annotations
https://github.com/FasterXML/jackson-annotations
这个页面列出了所有 Jackson 2.0 通用注解,按功能分组。
常用注解如下:
@JsonProperty@JsonIgnore@JsonIgnoreProperties@JsonInclude@JsonFormat@JsonSerialize@JsonDeserialize- …
Databind
For all data-binding, we need a com.fasterxml.jackson.databind.ObjectMapper instance:
1 | ObjectMapper mapper = new ObjectMapper(); // create once, reuse |
参考:
《ObjectMapper,别再像个二货一样一直 new 了!》
Configuration
https://github.com/FasterXML/jackson-databind/wiki/#reference-manual
POJO
The most common usage is to take piece of JSON, and construct a Plain Old Java Object (“POJO”) out of it.
Serialization:
1 | MyValue value = mapper.readValue(new File("data.json"), MyValue.class); |
Deserialization:
1 | mapper.writeValue(new File("result.json"), myResultObject); |
Generic Collections
You can also handle JDK Lists, Maps.
Serialization:
1 | Map<String, Integer> scoreByName = mapper.readValue(jsonSource, Map.class); |
Deserialization:
1 | // and can obviously write out as well |
Generic Type
如果需要将 JSON 字符串反序列化为泛型,有两种方式:
方式一:TypeReference
方式一:使用 com.fasterxml.jackson.core.type.TypeReference<T>:
This generic abstract class is used for obtaining full generics type information by sub-classing; it must be converted to
ResolvedTypeimplementation (implemented byJavaTypefrom “databind” bundle) to be used. Class is based on ideas from http://gafter.blogspot.com/2006/12/super-type-tokens.html, Additional idea (from a suggestion made in comments of the article) is to require bogus implementation ofComparable(any such generic interface would do, as long as it forces a method with generic type to be implemented). to ensure that a Type argument is indeed given.Usage is by sub-classing: here is one way to instantiate reference to generic type
List<Integer>:
1 TypeReference ref = new TypeReference<List<Integer>>() { };which can be passed to methods that accept TypeReference, or resolved using
TypeFactoryto obtainResolvedType.
代码如下:
1 | TypeReference<RespDTO<XxxRespDTO>> typeRef = new TypeReference<RespDTO<XxxRespDTO>>() {}; |
方式二:JavaType
方式二:使用 com.fasterxml.jackson.databind.JavaType:
Base class for type token classes used both to contain information and as keys for deserializers.
Instances can (only) be constructed by
com.fasterxml.jackson.databind.type.TypeFactory.
JavaType 的继承结构如下图:

代码如下:
1 | JavaType valueType = mapper.getTypeFactory().constructParametricType(RespDTO.class, XxxRespDTO.class); |
JavaType 的调试结果如下图,其值为 JavaType 的子类 CollectionType:

Tree Model (JsonNode)
Tree Model can be more convenient than data-binding, especially in cases where structure is highly dynamic, or does not map nicely to Java classes.
com.fasterxml.jackson.databind.JsonNode 表示一个 JSON 树节点,可以通过 ObjectMapper#readTree 方法反序列化出来,也可以通过 JsonNode 的子类 API 自定义构建:

构建代码如下:
1 | JsonNode jsonNode = |
JsonNode 构建完成后,可以灵活的读取其值,例如:
1 | // [value0, value1] |
也可以修改其值:
1 | ((ObjectNode) jsonNode).put("key", "value"); |
使用场景
一、对接口响应的 JSON 原文进行验签:
1 | { |
1 | JsonNode jsonNode = objectMapper.readTree(responseJson); |
二、<Compare Two JSON Objects with Jackson>
using the JsonNode.equals method. The
equals()method performs a full (deep) comparison.
例子
本例中,我们需要获取以下两个方法的泛型返回值中的实际类型参数 XxxRespDTO 的 Class 类型,以用于 JSON 转换:
1 | public interface ApiService { |
定义一个方法,用于转换 JSON:
1 | private Object getObject(Method method, String json) { |
这种用法常常出现在框架之中。下面来看下调试效果:
接口一
下图展示了变量 returnType 为参数化类型 ParameterizedType,其实际类型参数 type 为 Class 类型,值为 XxxRespDTO :

接口二
下图展示了变量 returnType 的实际类型参数 type 与接口一为 Class 类型不同,接口二为 ParameterizedType 参数化类型,值为 List<XxxRespDTO>:

常见报错
Unrecognized field, not marked as ignorable
该错误的意思是说,不能够识别的字段没有标示为可忽略。出现该问题的原因就是 JSON 中包含了目标 Java 对象没有的属性。
解决方案:
保证传入的 JSON 串不包含目标对象的没有的属性。
On deserialization,
@JsonIgnoreProperties(ignoreUnknown=true)ignores properties that don’t have getter/settersDeserialization Features全局配置:1
2// 配置该 `objectMapper` 在反序列化时,忽略目标对象没有的属性。
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
缺少默认构造方法
问题:
1 | com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.***.RespBody` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) |
解决方案:
- POJO 加上
@NoArgsConstructor
Using Java inner classes for Jackson serialization
https://dev.to/pavel_polivka/using-java-inner-classes-for-jackson-serialization-4ef8
Google Gson
https://github.com/google/gson
1 | JsonObject jsonObject = new JsonObject(); |
Deserialization to Generic Type: com.google.gson.reflect.TypeToken
1 | RespDTO<XxxRespDTO> data = new Gson().fromJson(json, new TypeToken<RespDTO<XxxRespDTO>>() {}.getType()); |
参考
https://www.baeldung.com/category/json/jackson/
https://github.com/qidawu/java-api-test/tree/master/src/main/java/json