1.說明
在開發中,經常需要測試Restful接口,
需要生成POJO簡單對象的JSON字符串,
如果對象類的字段比較多,
手工生成的時候會很麻煩,
下面提供一個基於Jackson的工具類,
能夠根據POJO簡單對象類,
初始化對象類中字段的默認值,
然後生成JSON字符串。
2.POJO簡單對象
簡單對象類UserEntity.java如下,
省略了get/set/toString等方法:
package com.yuwen.spring.demo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 用戶實體類
*/
public class UserEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 用戶ID
*/
private Long id;
/**
* 姓名
*/
private String name;
/**
* 郵箱
*/
private String email;
/**
* 生日
*/
private LocalDate birthday;
/**
* 創建時間
*/
private LocalDateTime createTime;
/**
* 修改時間
*/
private LocalDateTime updateTime;
}
3.Jackson工具類
工具類JacksonJsonGenerator.java如下,
每次使用的時候只需要修改targetClass:
package com.yuwen.spring.jackson.generator;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.yuwen.spring.demo.entity.UserEntity;
/**
* 使用Jackson,指定Java的POJO簡單對象類,生成對應的JSON字符串
*/
public class JacksonJsonGenerator {
// 指定需要生成JSON的Java類
public static Class<?> targetClass = UserEntity.class;
public static void main(String[] args) throws Exception {
Object object = initObjectDefaultValue(targetClass);
genetateJson(object);
}
/**
* 初始化對象字段的默認值
*/
private static Object initObjectDefaultValue(Class<?> targetClass)
throws InstantiationException, IllegalAccessException {
Object object = targetClass.newInstance();
// 根據屬性類型給屬性設默認值
FieldCallback fc = new FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
Class<?> fieldType = field.getType();
// final修飾的字段無法設置新的值
if (Modifier.isFinal(field.getModifiers())) {
return;
}
String type = fieldType.getSimpleName();
Object fieldValue = StringUtils.EMPTY;
switch (type) {
case "String":
fieldValue = StringUtils.EMPTY;
break;
case "int":
case "Integer":
fieldValue = 0;
break;
case "long":
case "Long":
fieldValue = 0L;
break;
case "LocalDate":
fieldValue = LocalDate.now();
break;
case "LocalDateTime":
fieldValue = LocalDateTime.now();
break;
default:
fieldValue = StringUtils.EMPTY;
break;
}
try {
field.setAccessible(true);
field.set(object, fieldValue);
} catch (Exception e) {
e.printStackTrace();
}
}
};
ReflectionUtils.doWithFields(targetClass, fc);
return object;
}
/**
* 生成對象的JSON字符串
*/
private static void genetateJson(Object object) throws JsonProcessingException {
System.out.println("POJO對象:");
System.out.println(object);
ObjectMapper mapper = new ObjectMapper();
// 用於序列化Java8新的時間類型
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
mapper.registerModule(javaTimeModule);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
System.out.println("JSON字符串:");
System.out.println(json);
}
}
4.生成JSON字符串
運行main方法輸出結果:
POJO對象:
UserEntity{id=0, name=, email=, birthday=2021-11-19,
createTime=2021-11-19T15:10:32.874, updateTime=2021-11-19T15:10:32.874}
JSON字符串:
{
"id" : 0,
"name" : "",
"email" : "",
"birthday" : "2021-11-19",
"createTime" : "2021-11-19T15:10:32.874",
"updateTime" : "2021-11-19T15:10:32.874"
}
5.更多的數據類型
在initObjectDefaultValue方法中,
修改swith-case增加更多的case,
可以支持更多的數據類型,
也可以修改類型對應的默認值。
6.問題解決
Jackson無法序列化Java8新的時間類型,
異常如下:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Java 8 date/time type `java.time.LocalDate` not supported by default:
add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling
(through reference chain: com.yuwen.spring.demo.entity.UserEntity["birthday"])
因爲birthday字段爲LocalDate類型,
按照提示在pom.xml新增
如下依賴:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.12.5</version>
</dependency>
然後在ObjectMapper註冊JavaTimeModule即可:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
7.其他方案
使用Jsr310NullKeySerializer,
也可以設置字段值爲NULL時的序列化動作,
但是隻能設置爲""空字符串,
同時由於無法獲取值爲NULL的字段的類型,
無法爲數據類型設置對應的默認值。
Jsr310NullKeySerializer.java代碼如下:
package com.fasterxml.jackson.datatype.jsr310.ser.key;
import java.io.IOException;
import java.util.Map;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
/**
* This class is to be used in case {@code null} keys are needed to be serialized in a {@link Map} with Java 8 temporal keys. By default the
* {@code null} key is not supported by jackson, the serializer needs to be registered manually.
*
* @author Zoltan Kiss
* @since 2.6
*/
@Deprecated // since 2.10 -- not sure why module should provide general purpose null serializer
// (maybe add in databind)
public class Jsr310NullKeySerializer extends JsonSerializer<Object> {
public static final String NULL_KEY = "";
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException
{
if (value != null) {
throw JsonMappingException.from(gen,
"Jsr310NullKeySerializer is only for serializing null values.");
}
gen.writeFieldName(NULL_KEY);
}
}