Jackson是Java生态系统中最受欢迎的JSON处理库之一,由FasterXML维护。它提供了一套全面的工具来处理JSON数据,支持Java对象与JSON数据之间的转换,同时也提供了处理其他数据格式的能力。Jackson具有以下特点:
Jackson库被分为多个模块,其核心组件包括:
Spring Boot已经包含了Jackson依赖,当您添加spring-boot-starter-web
时,Jackson会被自动引入。如果需要单独引入或指定版本,可以在pom.xml
中添加:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.14.0version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformatgroupId>
<artifactId>jackson-dataformat-xmlartifactId>
<version>2.14.0version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatypegroupId>
<artifactId>jackson-datatype-jsr310artifactId>
<version>2.14.0version>
dependency>
如果您使用Gradle,可以在build.gradle
文件中添加:
// Spring Boot Web依赖,已含Jackson
implementation 'org.springframework.boot:spring-boot-starter-web'
// 或者单独引入Jackson
implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0'
// 引入Jackson XML支持(可选)
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.0'
// 日期时间模块
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.0'
Spring Boot自动配置了Jackson,不需要额外的配置。但如果您想自定义Jackson行为,可以通过以下方式:
# 配置日期格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
# 配置时区
spring.jackson.time-zone=Asia/Shanghai
# 在序列化时忽略null值
spring.jackson.default-property-inclusion=non_null
# 允许未知属性
spring.jackson.deserialization.fail-on-unknown-properties=false
# 允许空对象
spring.jackson.serialization.fail-on-empty-beans=false
或者使用YAML格式:
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
default-property-inclusion: non_null
deserialization:
fail-on-unknown-properties: false
serialization:
fail-on-empty-beans: false
package com.example.config;
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.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.text.SimpleDateFormat;
@Configuration
public class JacksonConfig {
@Bean
@Primary
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 设置日期格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 设置Java 8日期时间模块
objectMapper.registerModule(new JavaTimeModule());
// 禁用将日期作为时间戳输出
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// 禁用在空对象上失败
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// 美化输出
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
return objectMapper;
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
// 创建一个简单的用户类
public class User {
private Long id;
private String name;
private int age;
// 构造函数、getter和setter方法
public User() {}
public User(Long id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
// getter和setter方法...
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
// 使用Jackson将对象转换为JSON字符串
ObjectMapper mapper = new ObjectMapper();
User user = new User(1L, "张三", 25);
String jsonString = mapper.writeValueAsString(user);
System.out.println(jsonString);
// 输出: {"id":1,"name":"张三","age":25}
// 美化输出
String prettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user);
System.out.println(prettyJson);
/*
输出:
{
"id" : 1,
"name" : "张三",
"age" : 25
}
*/
// 定义JSON字符串
String jsonString = "{\"id\":2,\"name\":\"李四\",\"age\":30}";
// 使用Jackson将JSON字符串转换为Java对象
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(jsonString, User.class);
System.out.println(user.getId() + ", " + user.getName() + ", " + user.getAge());
// 输出: 2, 李四, 30
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
// 创建用户列表
List<User> userList = new ArrayList<>();
userList.add(new User(1L, "张三", 25));
userList.add(new User(2L, "李四", 30));
userList.add(new User(3L, "王五", 35));
// 序列化列表
ObjectMapper mapper = new ObjectMapper();
String jsonArrayString = mapper.writeValueAsString(userList);
System.out.println(jsonArrayString);
// 输出: [{"id":1,"name":"张三","age":25},{"id":2,"name":"李四","age":30},{"id":3,"name":"王五","age":35}]
// 定义JSON数组字符串
String jsonArrayString = "[{\"id\":1,\"name\":\"张三\",\"age\":25},{\"id\":2,\"name\":\"李四\",\"age\":30}]";
// 反序列化为用户列表
ObjectMapper mapper = new ObjectMapper();
// 方法1:使用TypeReference
import com.fasterxml.jackson.core.type.TypeReference;
List<User> userList1 = mapper.readValue(jsonArrayString, new TypeReference<List<User>>() {});
// 方法2:使用CollectionType
import com.fasterxml.jackson.databind.type.CollectionType;
CollectionType listType =
mapper.getTypeFactory().constructCollectionType(List.class, User.class);
List<User> userList2 = mapper.readValue(jsonArrayString, listType);
// 遍历用户列表
for (User user : userList1) {
System.out.println(user.getId() + ", " + user.getName() + ", " + user.getAge());
}
import java.util.HashMap;
import java.util.Map;
// Map转JSON
Map<String, Object> map = new HashMap<>();
map.put("id", 1);
map.put("name", "张三");
map.put("active", true);
map.put("scores", new int[] {90, 85, 78});
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(map);
System.out.println(jsonString);
// 输出: {"name":"张三","id":1,"active":true,"scores":[90,85,78]}
// JSON转Map
String jsonMapString = "{\"name\":\"李四\",\"id\":2,\"active\":false,\"address\":{\"city\":\"北京\",\"street\":\"朝阳路\"}}";
Map<String, Object> resultMap = mapper.readValue(jsonMapString, new TypeReference<Map<String, Object>>() {});
System.out.println("name: " + resultMap.get("name"));
System.out.println("id: " + resultMap.get("id"));
System.out.println("active: " + resultMap.get("active"));
// 处理嵌套对象
@SuppressWarnings("unchecked")
Map<String, String> address = (Map<String, String>) resultMap.get("address");
System.out.println("city: " + address.get("city"));
System.out.println("street: " + address.get("street"));
// 定义部门类
public class Department {
private Long id;
private String name;
private List<User> users;
// 构造函数、getter和setter方法
public Department() {}
public Department(Long id, String name, List<User> users) {
this.id = id;
this.name = name;
this.users = users;
}
// getter和setter方法...
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public List<User> getUsers() { return users; }
public void setUsers(List<User> users) { this.users = users; }
}
// 创建复杂对象
List<User> users = new ArrayList<>();
users.add(new User(1L, "张三", 25));
users.add(new User(2L, "李四", 30));
Department department = new Department(1L, "技术部", users);
// 序列化复杂对象
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(department);
System.out.println(jsonString);
// 输出: {"id":1,"name":"技术部","users":[{"id":1,"name":"张三","age":25},{"id":2,"name":"李四","age":30}]}
// 反序列化复杂对象
Department parsedDepartment = mapper.readValue(jsonString, Department.class);
System.out.println("部门名称: " + parsedDepartment.getName());
System.out.println("用户数量: " + parsedDepartment.getUsers().size());
import java.util.Date;
import java.text.SimpleDateFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Event {
private Long id;
private String name;
private Date eventDate;
// 构造函数、getter和setter方法
// ...
}
// 创建带日期的对象
Event event = new Event();
event.setId(1L);
event.setName("年会");
event.setEventDate(new Date());
// 配置日期格式
ObjectMapper mapper = new ObjectMapper();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mapper.setDateFormat(dateFormat);
// 序列化
String jsonString = mapper.writeValueAsString(event);
System.out.println(jsonString);
// 输出: {"id":1,"name":"年会","eventDate":"2023-06-15 14:30:45"}
// 反序列化
Event parsedEvent = mapper.readValue(jsonString, Event.class);
System.out.println("事件名称: " + parsedEvent.getName());
System.out.println("事件日期: " + dateFormat.format(parsedEvent.getEventDate()));
import java.time.LocalDate;
import java.time.LocalDateTime;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.databind.SerializationFeature;
public class ModernEvent {
private Long id;
private String name;
private LocalDate eventDate;
private LocalDateTime eventDateTime;
// 构造函数、getter和setter方法
// ...
}
// 创建带Java 8日期时间的对象
ModernEvent event = new ModernEvent();
event.setId(1L);
event.setName("产品发布会");
event.setEventDate(LocalDate.of(2023, 6, 15));
event.setEventDateTime(LocalDateTime.of(2023, 6, 15, 14, 30, 0));
// 配置ObjectMapper支持Java 8日期时间
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// 序列化
String jsonString = mapper.writeValueAsString(event);
System.out.println(jsonString);
// 输出: {"id":1,"name":"产品发布会","eventDate":"2023-06-15","eventDateTime":"2023-06-15T14:30:00"}
// 反序列化
ModernEvent parsedEvent = mapper.readValue(jsonString, ModernEvent.class);
System.out.println("事件名称: " + parsedEvent.getName());
System.out.println("事件日期: " + parsedEvent.getEventDate());
System.out.println("事件时间: " + parsedEvent.getEventDateTime());
Jackson提供了丰富的注解系统,可以精确控制序列化和反序列化的行为。以下是常用的注解:
用于指定JSON属性名称,可以与Java字段名不同:
public class User {
@JsonProperty("user_id")
private Long id;
@JsonProperty("user_name")
private String name;
// 其他字段和方法...
}
// 序列化结果: {"user_id":1,"user_name":"张三","age":25}
用于排除不需要序列化/反序列化的字段:
public class User {
private Long id;
private String name;
@JsonIgnore
private String password; // 不会被序列化/反序列化
private int age;
// 其他字段和方法...
}
类级别注解,可以一次性指定多个要忽略的属性:
@JsonIgnoreProperties({"password", "salary", "emailAddress"})
public class User {
private Long id;
private String name;
private String password; // 将被忽略
private double salary; // 将被忽略
private String emailAddress; // 将被忽略
private int age;
// 其他字段和方法...
}
控制在何种条件下包含属性:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
// 类级别设置
@JsonInclude(Include.NON_NULL)
public class User {
private Long id;
private String name;
private Integer age; // 如果为null,将不会被序列化
// 属性级别设置,覆盖类级别
@JsonInclude(Include.NON_EMPTY)
private List<String> roles; // 如果为空列表,将不会被序列化
// 其他字段和方法...
}
常用的Include选项有:
Include.ALWAYS
:始终包含属性,不管值是什么(默认行为)Include.NON_NULL
:只包含非null值Include.NON_EMPTY
:排除null或空集合/数组/字符串Include.NON_DEFAULT
:排除默认值(如数字0,布尔值false)Include.NON_ABSENT
:排除null和缺失值(Optional.empty())用于指定日期/时间格式:
public class Event {
private Long id;
private String name;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date eventDate;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate eventDay;
// 其他字段和方法...
}
使用自定义的序列化器:
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
public class Product {
@JsonSerialize(using = ToStringSerializer.class)
private BigDecimal price; // 将使用toString()方法进行序列化
// 其他字段和方法...
}
使用自定义的反序列化器:
import com.fasterxml.jackson.databind.deser.std.DateDeserializers.DateDeserializer;
public class Event {
private Long id;
private String name;
@JsonDeserialize(using = DateDeserializer.class)
private Date eventDate;
// 其他字段和方法...
}
当JSON不能直接匹配构造函数或工厂方法的参数时,可以使用这种组合:
public class User {
private final Long id;
private final String name;
private final int age;
// 使用@JsonCreator指定用于反序列化的构造函数
@JsonCreator
public User(
@JsonProperty("user_id") Long id,
@JsonProperty("user_name") String name,
@JsonProperty("user_age") int age) {
this.id = id;
this.name = name;
this.age = age;
}
// 只有getter方法,没有setter方法
public Long getId() { return id; }
public String getName() { return name; }
public int getAge() { return age; }
}
// 使用这种方式可以反序列化以下JSON
// {"user_id":1,"user_name":"张三","user_age":25}
用于指定序列化时的根元素名称,需要启用SerializationFeature.WRAP_ROOT_VALUE
:
@JsonRootName("user")
public class User {
private Long id;
private String name;
private int age;
// 其他字段和方法...
}
// 配置启用根包装
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
String json = mapper.writeValueAsString(new User(1L, "张三", 25));
// 输出: {"user":{"id":1,"name":"张三","age":25}}
用于在序列化/反序列化时展开嵌套对象:
public class Address {
private String city;
private String street;
// getter和setter方法...
}
public class User {
private Long id;
private String name;
@JsonUnwrapped
private Address address;
// 其他字段和方法...
}
// 创建对象
User user = new User();
user.setId(1L);
user.setName("张三");
Address address = new Address();
address.setCity("北京");
address.setStreet("朝阳路");
user.setAddress(address);
// 序列化
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);
// 输出: {"id":1,"name":"张三","city":"北京","street":"朝阳路"}
// 注意address的属性被展开到顶层
用于控制对象的部分视图,实现同一个对象的不同JSON表示:
// 定义视图
public class Views {
public static class Public { }
public static class Internal extends Public { }
public static class Admin extends Internal { }
}
public class User {
@JsonView(Views.Public.class)
private Long id;
@JsonView(Views.Public.class)
private String name;
@JsonView(Views.Internal.class)
private String email;
@JsonView(Views.Admin.class)
private String password;
// 其他字段和方法...
}
// 使用视图进行序列化
ObjectMapper mapper = new ObjectMapper();
User user = new User(1L, "张三", "[email protected]", "password123");
// 公开视图
String publicJson = mapper.writerWithView(Views.Public.class)
.writeValueAsString(user);
// 输出: {"id":1,"name":"张三"}
// 内部视图
String internalJson = mapper.writerWithView(Views.Internal.class)
.writeValueAsString(user);
// 输出: {"id":1,"name":"张三","email":"[email protected]"}
// 管理员视图
String adminJson = mapper.writerWithView(Views.Admin.class)
.writeValueAsString(user);
// 输出: {"id":1,"name":"张三","email":"[email protected]","password":"password123"}
当需要定制序列化逻辑时,可以编写自定义序列化器:
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
// 自定义序列化器
public class MoneySerializer extends JsonSerializer<BigDecimal> {
private final DecimalFormat formatter = new DecimalFormat("¥#,##0.00");
@Override
public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeString(formatter.format(value));
}
}
// 在类中使用自定义序列化器
public class Product {
private Long id;
private String name;
@JsonSerialize(using = MoneySerializer.class)
private BigDecimal price;
// 其他字段和方法...
}
// 序列化示例
Product product = new Product();
product.setId(1L);
product.setName("笔记本电脑");
product.setPrice(new BigDecimal("6999.99"));
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(product);
// 输出: {"id":1,"name":"笔记本电脑","price":"¥6,999.99"}
同样,可以编写自定义反序列化器:
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
// 自定义反序列化器
public class MoneyDeserializer extends JsonDeserializer<BigDecimal> {
private final DecimalFormat formatter = new DecimalFormat("¥#,##0.00");
@Override
public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
String valueAsString = p.getValueAsString();
try {
// 移除货币符号和逗号
String normalized = valueAsString.replace("¥", "").replace(",", "");
return new BigDecimal(normalized);
} catch (NumberFormatException e) {
throw new IOException("无法解析金额: " + valueAsString, e);
}
}
}
// 在类中使用自定义反序列化器
public class Product {
private Long id;
private String name;
@JsonDeserialize(using = MoneyDeserializer.class)
private BigDecimal price;
// 其他字段和方法...
}
当您无法修改要序列化/反序列化的类时,可以使用混合注解:
// 无法修改的第三方类
public class ThirdPartyUser {
private Long id;
private String name;
private String email;
private String internalData; // 不希望序列化此字段
// getter和setter方法...
}
// 创建混合注解接口
@JsonIgnoreProperties({"internalData"})
abstract class UserMixIn {
@JsonProperty("user_id")
abstract Long getId();
@JsonProperty("user_name")
abstract String getName();
}
// 将混合注解应用到ObjectMapper
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(ThirdPartyUser.class, UserMixIn.class);
// 序列化
ThirdPartyUser user = new ThirdPartyUser();
user.setId(1L);
user.setName("张三");
user.setEmail("[email protected]");
user.setInternalData("私有数据");
String json = mapper.writeValueAsString(user);
// 输出: {"user_id":1,"user_name":"张三","email":"[email protected]"}
// 注意:internalData被忽略,id和name属性名被改变
用于处理多态情况,如继承关系:
// 基类
@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")
})
public abstract class Animal {
private String name;
// getter和setter方法...
}
// 子类
@JsonTypeName("dog")
public class Dog extends Animal {
private String barkSound;
// getter和setter方法...
}
@JsonTypeName("cat")
public class Cat extends Animal {
private int livesLeft;
// getter和setter方法...
}
// 使用示例
ObjectMapper mapper = new ObjectMapper();
// 创建动物列表
List<Animal> animals = new ArrayList<>();
Dog dog = new Dog();
dog.setName("旺财");
dog.setBarkSound("汪汪");
animals.add(dog);
Cat cat = new Cat();
cat.setName("咪咪");
cat.setLivesLeft(9);
animals.add(cat);
// 序列化
String json = mapper.writeValueAsString(animals);
/*
输出:
[
{"type":"dog","name":"旺财","barkSound":"汪汪"},
{"type":"cat","name":"咪咪","livesLeft":9}
]
*/
// 反序列化
List<Animal> deserializedAnimals = mapper.readValue(json,
new TypeReference<List<Animal>>() {});
// 验证对象类型
System.out.println(deserializedAnimals.get(0).getClass()); // class Dog
System.out.println(deserializedAnimals.get(1).getClass()); // class Cat
除了对象绑定API外,Jackson还提供了树模型API,适用于动态操作JSON:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
// 读取JSON到树模型
String jsonString = "{\"name\":\"张三\",\"age\":25,\"address\":{\"city\":\"北京\",\"street\":\"朝阳路\"},\"hobbies\":[\"阅读\",\"游泳\"]}";
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(jsonString);
// 访问属性
String name = rootNode.get("name").asText();
int age = rootNode.get("age").asInt();
String city = rootNode.get("address").get("city").asText();
// 遍历数组
ArrayNode hobbies = (ArrayNode) rootNode.get("hobbies");
for (JsonNode hobby : hobbies) {
System.out.println("爱好: " + hobby.asText());
}
// 创建新的树模型
ObjectNode userNode = mapper.createObjectNode();
userNode.put("name", "李四");
userNode.put("age", 30);
ObjectNode addressNode = mapper.createObjectNode();
addressNode.put("city", "上海");
addressNode.put("street", "南京路");
userNode.set("address", addressNode);
ArrayNode newHobbies = mapper.createArrayNode();
newHobbies.add("篮球");
newHobbies.add("编程");
userNode.set("hobbies", newHobbies);
// 转换为JSON字符串
String newJsonString = mapper.writeValueAsString(userNode);
System.out.println(newJsonString);
在Spring Boot中,当您返回一个对象或接收一个@RequestBody参数时,Jackson会自动处理序列化和反序列化:
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// 返回对象自动序列化为JSON
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.findById(id);
}
// 返回集合自动序列化为JSON数组
@GetMapping
public List<User> getAllUsers() {
return userService.findAll();
}
// 接收JSON请求体并自动反序列化为User对象
@PostMapping
public User createUser(@RequestBody User user) {
return userService.save(user);
}
// 返回ResponseEntity
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
User updatedUser = userService.update(user);
return ResponseEntity.ok(updatedUser);
}
}
可以创建不同的ObjectMapper实例,用于特定的序列化需求:
@RestController
@RequestMapping("/api/products")
public class ProductController {
private final ProductService productService;
private final ObjectMapper defaultMapper;
private final ObjectMapper customMapper;
@Autowired
public ProductController(ProductService productService, ObjectMapper defaultMapper) {
this.productService = productService;
this.defaultMapper = defaultMapper;
// 创建自定义的ObjectMapper
this.customMapper = new ObjectMapper();
customMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
customMapper.registerModule(new JavaTimeModule());
customMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
customMapper.setDateFormat(new SimpleDateFormat("yyyy年MM月dd日"));
}
// 使用默认的ObjectMapper(自动配置)
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return productService.findById(id);
}
// 手动使用自定义ObjectMapper
@GetMapping("/{id}/custom")
public String getProductByIdCustomFormat(@PathVariable Long id) throws JsonProcessingException {
Product product = productService.findById(id);
return customMapper.writeValueAsString(product);
}
}
使用Jackson序列化错误响应:
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理资源未找到异常
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Map<String, Object> handleResourceNotFoundException(ResourceNotFoundException ex) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("timestamp", new Date());
errorResponse.put("status", HttpStatus.NOT_FOUND.value());
errorResponse.put("error", "Not Found");
errorResponse.put("message", ex.getMessage());
errorResponse.put("path", getCurrentRequestPath());
return errorResponse;
}
// 处理验证异常
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, Object> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("timestamp", new Date());
errorResponse.put("status", HttpStatus.BAD_REQUEST.value());
errorResponse.put("error", "Validation Failed");
// 收集所有验证错误
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage()));
errorResponse.put("errors", errors);
errorResponse.put("path", getCurrentRequestPath());
return errorResponse;
}
private String getCurrentRequestPath() {
try {
return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest().getRequestURI();
} catch (Exception e) {
return "unknown";
}
}
}
ObjectMapper的创建成本较高,应该重用实例:
// 在Spring Boot应用中定义ObjectMapper Bean
@Configuration
public class JacksonConfig {
@Bean
@Primary
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
// 配置mapper...
return mapper;
}
}
// 在服务类中注入和重用
@Service
public class JsonService {
private final ObjectMapper mapper;
@Autowired
public JsonService(ObjectMapper mapper) {
this.mapper = mapper;
}
public String toJson(Object object) throws JsonProcessingException {
return mapper.writeValueAsString(object);
}
public <T> T fromJson(String json, Class<T> clazz) throws JsonProcessingException {
return mapper.readValue(json, clazz);
}
}
ObjectMapper mapper = new ObjectMapper();
// 禁用不需要的特性可以提高性能
mapper.disable(MapperFeature.USE_ANNOTATIONS);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 对于特定应用,可以进一步优化
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
mapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
对于非常大的JSON文件,使用流式API可以减少内存使用:
// 流式读取大型JSON数组
public void processLargeJsonArray(InputStream jsonStream) throws IOException {
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(jsonStream);
// 确保开始于数组
if (parser.nextToken() != JsonToken.START_ARRAY) {
throw new IllegalStateException("预期JSON数组");
}
// 逐个处理数组元素
while (parser.nextToken() != JsonToken.END_ARRAY) {
// 当前元素是一个对象
if (parser.currentToken() == JsonToken.START_OBJECT) {
// 处理单个用户对象
processUserObject(parser);
}
}
parser.close();
}
private void processUserObject(JsonParser parser) throws IOException {
String fieldName;
Long id = null;
String name = null;
// 解析对象字段
while (parser.nextToken() != JsonToken.END_OBJECT) {
fieldName = parser.getCurrentName();
parser.nextToken(); // 移动到字段值
if ("id".equals(fieldName)) {
id = parser.getLongValue();
} else if ("name".equals(fieldName)) {
name = parser.getText();
} else {
// 忽略其他字段,跳过其值
parser.skipChildren();
}
}
// 处理提取的数据
if (id != null && name != null) {
System.out.println("处理用户: " + id + ", " + name);
}
}
Jackson的多态类型绑定可能导致安全漏洞,建议禁用默认类型处理:
ObjectMapper mapper = new ObjectMapper();
mapper.activateDefaultTyping(
mapper.getPolymorphicTypeValidator(),
ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT
);
或者指定可信任的类:
mapper.activateDefaultTyping(
BasicPolymorphicTypeValidator.builder()
.allowIfSubType("com.example.model.")
.build(),
ObjectMapper.DefaultTyping.NON_FINAL
);
当处理不受信任的输入时,使用安全的配置:
ObjectMapper mapper = new ObjectMapper();
// 禁用自动类型检测
mapper.disable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
// 禁用POJO转换为树模型
mapper.disable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
// 在未知属性上失败
mapper.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 在数字类型溢出时失败
mapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);
Jackson可以与Bean Validation一起使用,确保数据符合要求:
import javax.validation.constraints.*;
public class User {
@NotNull
private Long id;
@NotBlank
@Size(min = 2, max = 50)
private String name;
@Min(0)
@Max(150)
private int age;
@Email
private String email;
// getter和setter方法...
}
// 在Controller中进行验证
@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
// 由于@Valid注解,如果验证失败会抛出MethodArgumentNotValidException
return ResponseEntity.ok(userService.save(user));
}
// 全局配置
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
// 注册模块以支持Java 8日期时间类型
mapper.registerModule(new JavaTimeModule());
// 配置日期时间格式
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mapper.setDateFormat(dateFormat);
// 以ISO-8601输出日期时间
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// 设置时区
mapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
return mapper;
}
}
// 方法1:通过配置
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 方法2:通过注解
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
// ...
}
// 方法1:配置不要在空对象上失败
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// 方法2:全局配置输出null值
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
// 方法3:全局配置不输出null值
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 方法1:使用@JsonManagedReference和@JsonBackReference
public class Department {
@JsonManagedReference
private List<Employee> employees;
// ...
}
public class Employee {
@JsonBackReference
private Department department;
// ...
}
// 方法2:直接禁用循环引用检测
mapper.disable(SerializationFeature.FAIL_ON_SELF_REFERENCES);
Jackson通常具有更高的性能,特别是在处理大型对象时,但Gson配置更简单:
// Jackson示例
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(jsonString, User.class);
String newJsonString = mapper.writeValueAsString(user);
// Gson示例
Gson gson = new Gson();
User user = gson.fromJson(jsonString, User.class);
String newJsonString = gson.toJson(user);
Fastjson性能更好,但Jackson在功能和生态系统上更完善:
// Jackson示例
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(jsonString, User.class);
String newJsonString = mapper.writeValueAsString(user);
// Fastjson示例
User user = JSON.parseObject(jsonString, User.class);
String newJsonString = JSON.toJSONString(user);
## 10. 与其他JSON库的比较
### 10.1 Jackson vs Gson
Jackson通常具有更高的性能,特别是在处理大型对象时,但Gson配置更简单:
```java
// Jackson示例
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(jsonString, User.class);
String newJsonString = mapper.writeValueAsString(user);
// Gson示例
Gson gson = new Gson();
User user = gson.fromJson(jsonString, User.class);
String newJsonString = gson.toJson(user);
Fastjson性能更好,但Jackson在功能和生态系统上更完善:
// Jackson示例
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(jsonString, User.class);
String newJsonString = mapper.writeValueAsString(user);
// Fastjson示例
User user = JSON.parseObject(jsonString, User.class);
String newJsonString = JSON.toJSONString(user);