欢迎你来读这篇博客,这篇博客主要是关于SpringBoot-JackSon 使用指南
。
其中包括了关于我的见解和收集的知识分享。
序言
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
| <mvn> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.10</version> <relativePath/> </parent> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2023.0.0</version> <type>pom</type> <scope>import</scope> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>lasted-version</version> </dependency> </mvn>
|
正文
Jackson 是一个广泛使用的开源类库,用于处理 JSON 和 XML 数据的格式化。它在日常开发中非常流行,尤其是在 Spring MVC 框架中,默认的
JSON 解析器就是 Jackson。
除了 Jackson,还有一些常见的 JSON 解析器,比如 Jsonlib、Gson 和 fastjson 等。然而,Jackson 在处理大型 JSON
文件时,凭借其较快的处理速度、较低的内存占用以及出色的性能,显现出了明显的优势。它还提供了灵活的 API,便于扩展和定制。
总之,Jackson 是一款非常强大的处理 JSON 和 XML 格式的开源类库,非常适合开发中使用。它在 Spring Boot 项目中也是默认的 JSON
处理库,主要用于对象与 JSON 之间的序列化和反序列化。接下来,将详细介绍在 Spring Boot 中如何使用
Jackson,包括基本配置、注解使用、自定义序列化器与反序列化器以及如何处理复杂数据类型等内容。
Jackson 核心模块
jackson-core:核心包,它提供基于”流模式”解析的相关 API,它包括JsonPaser和JsonGenerator。Jackson 内部实现正是通过高性能的流模式
API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
jackson-annotations:注解包,提供标准注解功能。
jackson-databind:数据绑定包, 提供基于”对象绑定” 解析的相关 API ( ObjectMapper ) 和”树模型” 解析的相关 API
(JsonNode);基于”对象绑定” 解析的 API 和”树模型”解析的 API 依赖基于”流模式”解析的 API
性能分析
Jackson、Gson、Fastjson 是三个最常用的 JSON 库。它们各有优缺点,性能和使用场景也有所不同。下面我们从性能、功能、易用性和安全性等方面进行详细对比。
库名称 |
序列化性能 |
反序列化性能 |
内存占用 |
描述 |
Jackson |
高 |
高 |
低 |
性能最优,适合高并发场景。支持流式 API(JsonParser 和 JsonGenerator),适合处理大文件。多格式支持如 JSON/XML/YAML/CSV。 学习曲线陡峭(配置复杂)。 |
Fastjson |
极高 |
高 |
极低 |
性能较好,但存在安全隐患,新版本可用。但 历史上多次曝出反序列化漏洞。 Fastjson 1.x:已停止维护,存在反序列化RCE等严重漏洞。Fastjson2:重构版本,修复安全问题并提升性能(性能较1.x提升20%+) |
Gson |
中 |
中 |
高 |
性能中等,适合简单场景,适合新手,学习难度平缓,API简洁。 |
- Jackson的流式API 在处理GB级JSON时内存占用仅为Gson的1/3;
- Gson的宽松映射 允许字段名不匹配、无参构造器缺失,容错性最佳。
- Fastjson2的Path查询 支持类XPath语法,可直接提取嵌套字段(如JSONPath.eval(json, “$.user.address”));
- 序列化场景:Fastjson2 > Jackson > Gson
- 反序列化场景:Fastjson2 ≈ Jackson > Gson
配置
通过yaml配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai default-property-inclusion: non_null serialization: indent-output: true deserialization: fail-on-unknown-properties: false parser: allow-unquoted-control-chars: true allow-single-quotes: true
|
自定义配置
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
| import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.text.SimpleDateFormat; import java.util.TimeZone;
@Configuration public class JacksonConfig {
@Bean @Primary public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.build();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
objectMapper.registerModule(new JavaTimeModule());
return objectMapper; } }
|
注解
- @JsonIgnore:忽略字段的序列化和反序列化。
- @JsonProperty:指定字段的JSON键名。
- @JsonCreator:此注解用于构造方法,和 @JsonProperty 配合使用,适用有参数的构造方法。
- @JsonFormat:指定日期格式。
- @JsonInclude:控制字段的序列化条件。
- @JsonView:控制视图。
- @JsonAlias:为反序列化期间要接受的属性定义一个或多个替代名称。
- @JsonPropertyOrder:指定字段的序列化顺序。
- @JsonRawValue:将字段值作为原始JSON字符串处理。
- @JsonAnyGetter和@JsonAnySetter:处理动态属性。
- @JsonValue 自动适配枚举
- @JsonIdentityInfo注解来避免无限递归
- @JsonTypeInfo和@JsonSubTypes注解来处理多态类型
示例
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
| @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({"name", "age", "email"}) public class User {
@JsonProperty("user_name") private String name;
private int age;
@JsonIgnore private String password;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") private Date createdDate;
@JsonProperty("user_email") private String email;
@JsonInclude(JsonInclude.Include.NON_NULL) private String email; @JsonRawValue private String rawJson; private CategoryEnum category; private Map<String, Object> additionalProperties; @JsonAnyGetter public Map<String, Object> any() { return additionalProperties; } @JsonAnySetter public void set(String name, Object value) { if (additionalProperties == null) { additionalProperties = new HashMap<>(); } additionalProperties.put(name, value); }
}
public enum CategoryEnum {
WEB("Web", 1), APP("App", 2), EMAIL("Email", 3);
private final String category; @JsonValue private final Integer value;
CategoryEnum(String category, Integer value) { this.category = category; this.value = value; } }
|
序列化与反序列化
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 67 68 69 70
|
@Autowired private ObjectMapper objectMapper;
String jsonString = objectMapper.writeValueAsString(user);
User user = objectMapper.readValue(jsonString, User.class);
String jsonString = objectMapper.writeValueAsString(users);
List<User> users = objectMapper.readValue(jsonString, objectMapper.getTypeFactory().constructCollectionType(List.class, User.class));
String jsonString = objectMapper.writeValueAsString(map);
Map<String, Object> resultMap = objectMapper.readValue(jsonString, Map.class);
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") public class User { private Long id; private String name; private User friend; }
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = Dog.class, name = "dog"), @JsonSubTypes.Type(value = Cat.class, name = "cat") }) interface Animal {}
@Data class Dog implements Animal { private String breed; }
@Data class Cat implements Animal { private String color; }
public class Main { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); Animal dog = new Dog("German Shepherd"); Animal cat = new Cat("Black"); String jsonStringDog = mapper.writeValueAsString(dog); String jsonStringCat = mapper.writeValueAsString(cat); System.out.println("序列化后的JSON字符串 (Dog): " + jsonStringDog); System.out.println("序列化后的JSON字符串 (Cat): " + jsonStringCat); Animal deserializedDog = mapper.readValue(jsonStringDog, Animal.class); Animal deserializedCat = mapper.readValue(jsonStringCat, Animal.class); System.out.println("反序列化后的多态对象 (Dog): " + deserializedDog); System.out.println("反序列化后的多态对象 (Cat): " + deserializedCat); } }
|
自定义序列化器
1 2 3 4 5 6 7 8 9
| public class CustomDateSerializer extends JsonSerializer<Date> { private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override public void serialize(Date date, JsonGenerator gen, SerializerProvider provider) throws IOException { String formattedDate = dateFormat.format(date); gen.writeString(formattedDate); } }
|
自定义反序列化器
1 2 3 4 5 6 7 8 9 10 11 12
| public class CustomDateDeserializer extends JsonDeserializer<Date> { private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { try { return dateFormat.parse(p.getValueAsString()); } catch (ParseException e) { throw new RuntimeException(e); } } }
|
使用自定义序列化和反序列化器
1 2 3 4 5 6 7
| public class User { private String name; @JsonSerialize(using = CustomDateSerializer.class) @JsonDeserialize(using = CustomDateDeserializer.class) private Date registerDate; }
|
参考资料
启示录
富贵岂由人,时会高志须酬。
能成功于千载者,必以近察远。