起因
自己在写接口文档或者进行postman测试时,需要一些json字符串来作为接口入参或者返回值,以前都是要手动地创建一个对象,并对属性赋值后再通过阿里的fastjson输出的,挺麻烦的,后面想了想能不能只需要Class类就能够产生json字符串,之前也在swagger2的一个ui中看到了类似的效果。但我现在是想自动地生成postman的导入需要的json文件,所以需要自定义注解后,再获取注解标注的参数或方法的返回值的Class类对象,这时候就是搞这个的动机——要将Class类对象转为json字符串
过程
其实关键是为类反射创建的对象的属性赋初始值。
只不过这里属性的类分情况:
- 基本数据类型:例如int初值是0,boolean初值是false,赋初值jvm都帮我们搞定了,就不用我们处理了。
- 包装类以及系统的一些常用类型:如Integer,String,Date,这些就需要我们手动进行赋初值了。
- 自定义的类型:这个在我的应用中,一般是vo层的实体类,我们处理时就需要递归到第1种和第2种为止,然后它们的定义我是判断该类的package是否是以项目的package开始的,即利用String的startsWith方法
- 集合类型:我这里只考虑了List(因为其他的用得少,大家可以自行加上),这里关键是获得List的泛型从而对其进行分情况,所以也要求类中的List属性要加上泛型。
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
public class ClassInitUtils {
private static final String PROJECT_BASE_PACKAGE = "自己项目的包名";
public static <T> T getObjDefault(Class<T> clazz) throws IllegalAccessException, InstantiationException {
T instance = clazz.newInstance();
Field[] fs = clazz.getDeclaredFields();
for (int i = 0; i < fs.length; i++) {
Field f = fs[i];
// 设置些属性是可以访问的
boolean isStatic = Modifier.isStatic(f.getModifiers());
if (isStatic) {
continue;
}
// 设置些属性是可以访问的
f.setAccessible(true);
try {
Class<?> type = f.getType();
//是基本数据类型
if (type.isPrimitive())
continue;
// 得到此属性的值
Object val = f.get(instance);
// 得到此属性的类型
String typeStr = type.toString();
if (typeStr.endsWith("String") && val == null) {
f.set(instance, "");
} else if ((typeStr.endsWith("Integer") || typeStr.endsWith("Double")) && val == null) {
f.set(instance, 0);
} else if ( typeStr.endsWith("Long") && val == null) {
f.set(instance, 0L);
} else if (typeStr.endsWith("Date") && val == null) {
f.set(instance, Date.valueOf("1970-01-01"));
} else if (typeStr.endsWith("Timestamp") && val == null) {
f.set(instance, Timestamp.valueOf("1970-01-01 00:00:00"));
} else if (typeStr.endsWith("BigDecimal") && val == null) {
f.set(instance, new BigDecimal(0));
} else if (type.getPackage().toString().startsWith(PROJECT_BASE_PACKAGE)) {
f.set(instance, getObjDefault(type));
} else if (type.isAssignableFrom(List.class)) {
f.set(instance,getObjDefaultList(f));
}
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
}
public static List<Object>getObjDefaultList(Field field) throws IllegalAccessException, InstantiationException {
//获取List的泛型
Type genericType = field.getGenericType();
List<Object>list=new ArrayList();
//无泛型
if (null == genericType) {
return list;
}
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
// 得到泛型里的class类型对象
Class<?> actualTypeArgument = (Class<?>) pt.getActualTypeArguments()[0];
Object obj = getObjDefault(actualTypeArgument);
//List属性默认只填入一个
list.add(obj);
}
return list;
}
}
我上方的代码逻辑也挺明了的,目前在我的项目中挺适用的,能够应对常用的属性。我也看到了上面代码的getObjDefault和getObjDefaultList存在着相互递归调用的情况,可能会导致栈溢出,大家可以结合自身的情况进行改进。
剩下步骤的就简单了,直接利用阿里的fastjson将对象转为json串即可
(不过fastjson会将类中的属性按字典序排序,json串里的属性就不是原来的顺序了,有些别扭)
Object obj = ClassInitUtils.getObjDefault(type);
String raw = JSONObject.toJSONString(obj);