综述:任意对象及其属性(实例变量)转换为非null对象
关键点:
我们在实现之前,先准备一个测试用的复杂类,包含我们上述的所有需求。为了清楚描述,我们给出具体代码和类图,如下(省略所有get、set方法):
/**
*
* 测试类,包含3个内部类
*
* @author sunjie at 2016年8月3日
*
*/
public class TestNull {
private String string1;
private Long long1;
private int int1;
private Float float1;
private Boolean boolean1;
private Character character1;
private TestNullEnum testNullEnum1;
private TestNullChlidA testNullChlidA1;
private List testNullChlid1;
private Map testNullChlid2;
private TestNullChlidB[] testNullChlid3;
@Override
public String toString() {
return "TestNull [string1=" + string1 + ", long1=" + long1 + ", int1=" + int1 + ", float1=" + float1
+ ", boolean1=" + boolean1 + ", character1=" + character1 + ", testNullEnum1=" + testNullEnum1
+ ", testNullChlidA1=" + testNullChlidA1 + ", testNullChlid1=" + testNullChlid1 + ", testNullChlid2="
+ testNullChlid2 + ", testNullChlid3=" + Arrays.toString(testNullChlid3) + "]";
}
public class TestNullChlidBaseA {
private String childBaseAString1;
private int childBaseALong1;
private Boolean childABoolean2;
@Override
public String toString() {
return "TestNullChlidBaseA [childBaseAString1=" + childBaseAString1 + ", childBaseALong1="
+ childBaseALong1 + ", childABoolean2=" + childABoolean2 + "]";
}
}
public class TestNullChlidA extends TestNullChlidBaseA {
private String childAString1;
private Long childALong1;
private long childALong2;
private boolean childABoolean1;
private Boolean childABoolean2;
@Override
public String toString() {
return "TestNullChlidA [childAString1=" + childAString1 + ", childALong1=" + childALong1 + ", childALong2="
+ childALong2 + ", childABoolean1=" + childABoolean1 + ", childABoolean2=" + childABoolean2
+ ", superClass=" + super.toString() + "]";
}
}
public class TestNullChlidB {
private String childBString1;
private Float childBFloat1;
private TestNullEnum testNullEnum1;
@Override
public String toString() {
return "TestNullChlidB [childBString1=" + childBString1 + ", childBFloat1=" + childBFloat1
+ ", testNullEnum1=" + testNullEnum1 + "]";
}
}
}
/**
*
* 枚举类
*
* @author sunjie at 2016年8月3日
*
*/
public enum TestNullEnum implements Serializable {
ENUM_VALUE0("0", "零"),
ENUM_VALUE1("1", "一"),
ENUM_VALUE2("2", "二"),
;
private String code;
private String name;
public String getCode() {
return code;
}
public String getName() {
return name;
}
private TestNullEnum(String code, String name) {
this.code = code;
this.name = name;
}
public static TestNullEnum getEnum(String code) {
for (TestNullEnum e : TestNullEnum.values()) {
if (e.getCode().equals(code)) {
return e;
}
}
return null;
}
}
根据以上测试类,我们可以梳理出几种场景,以及想要达到的效果,如下:
01、testNull对象为null:
====源对象:null
====处理后:TestNull [string1=, long1=0, int1=0, float1=0.0, boolean1=false, character1=0, testNullEnum1=ENUM_VALUE0, testNullChlidA1=TestNullChlidA [childAString1=, childALong1=0, childALong2=0, childABoolean1=false, childABoolean2=false, superClass=TestNullChlidBaseA [childBaseAString1=, childBaseALong1=0, childABoolean2=false]], testNullChlid1=[], testNullChlid2={}, testNullChlid3=[]]
02、testNull对象内所有属性为null:
====源对象:TestNull [string1=null, long1=null, int1=0, float1=null, boolean1=null, character1=null, testNullEnum1=null, testNullChlidA1=null, testNullChlid1=null, testNullChlid2=null, testNullChlid3=null]
====处理后:TestNull [string1=, long1=0, int1=0, float1=0.0, boolean1=false, character1=0, testNullEnum1=ENUM_VALUE0, testNullChlidA1=TestNullChlidA [childAString1=, childALong1=0, childALong2=0, childABoolean1=false, childABoolean2=false, superClass=TestNullChlidBaseA [childBaseAString1=, childBaseALong1=0, childABoolean2=false]], testNullChlid1=[], testNullChlid2={}, testNullChlid3=[]]
03、testNull对象内List、Map中元素为null:
====源对象:TestNull [string1=null, long1=null, int1=0, float1=null, boolean1=null, character1=null, testNullEnum1=null, testNullChlidA1=null, testNullChlid1=[null], testNullChlid2={key1=null}, testNullChlid3=null]
====处理后:TestNull [string1=, long1=0, int1=0, float1=0.0, boolean1=false, character1=0, testNullEnum1=ENUM_VALUE0, testNullChlidA1=TestNullChlidA [childAString1=, childALong1=0, childALong2=0, childABoolean1=false, childABoolean2=false, superClass=TestNullChlidBaseA [childBaseAString1=, childBaseALong1=0, childABoolean2=false]], testNullChlid1=[TestNullChlidB [childBString1=, childBFloat1=0.0, testNullEnum1=ENUM_VALUE0]], testNullChlid2={key1=TestNullChlidB [childBString1=, childBFloat1=0.0, testNullEnum1=ENUM_VALUE0]}, testNullChlid3=[]]
04、testNull对象内Array中元素为null:
====源对象:TestNull [string1=null, long1=null, int1=0, float1=null, boolean1=null, character1=null, testNullEnum1=null, testNullChlidA1=null, testNullChlid1=null, testNullChlid2=null, testNullChlid3=[null]]
====处理后:TestNull [string1=, long1=0, int1=0, float1=0.0, boolean1=false, character1=0, testNullEnum1=ENUM_VALUE0, testNullChlidA1=TestNullChlidA [childAString1=, childALong1=0, childALong2=0, childABoolean1=false, childABoolean2=false, superClass=TestNullChlidBaseA [childBaseAString1=, childBaseALong1=0, childABoolean2=false]], testNullChlid1=[], testNullChlid2={}, testNullChlid3=[TestNullChlidB [childBString1=, childBFloat1=0.0, testNullEnum1=ENUM_VALUE0]]]
要实现非null,核心就是将值为null的属性赋默认值,其中有两个关键点:
对于第一点,通过递归遍历对应类的字段来实现判断,其中需要考虑内部类、数组、集合容器。
对于第二点,首先要知道属性的类型:
完整代码链接:https://github.com/popkidorc/JavaUtils/tree/master/JavaUtil
下面直接放出完整代码,这里依赖了commons-lang.jar包的ArrayUtils类:
package com.liepin.leiting.proxy.common.util;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
import org.springframework.util.CollectionUtils;
/**
*
* 对象处理工具类 TODO 该类可以改为工厂,对于各种特殊类型可以方便扩展
*
* @author sunjie at 2016年11月29日
*
*/
public class ObjectUtil {
private static final Logger catalinaLog = Logger.getLogger(ObjectUtil.class);
/**
*
* 将任意对象及对象内属性转为非null对象。深度转换,自动创建对象(对于多个构造方法的类,使用第一个能够成功的构造方法进行实例化)。
*
* @author sunjie at 2016年7月28日
*
* @param object
* @param clazz
* 对象的类,无范型
* @return
* @throws Exception
*/
@SuppressWarnings("rawtypes")
public static T getNotNullObject(T object, Class clazz) {
return getNotNullObject(object, clazz, new ArrayList());
}
/**
*
* 将任意对象及对象内属性转为非null对象。深度转换,自动创建对象(对于多个构造方法的类,使用第一个能够成功的构造方法进行实例化)。
*
* @author sunjie at 2016年7月28日
*
* @param object
* @param clazz
* 对象的类
* @param _actualTypeClazz
* 泛型类,单范型,例如List
* @return
* @throws Exception
*/
@SuppressWarnings("rawtypes")
public static T getNotNullObject(T object, Class clazz, Class _actualTypeClazz) {
List _actualTypeClazzes = new ArrayList();
if (null != _actualTypeClazz) {
_actualTypeClazzes.add(_actualTypeClazz);
}
return getNotNullObject(object, clazz, _actualTypeClazzes);
}
/**
*
* 将任意对象及对象内属性转为非null对象。深度转换,自动创建对象(对于多个构造方法的类,使用第一个能够成功的构造方法进行实例化)。
*
* @author sunjie at 2016年7月28日
*
* @param object
* @param clazz
* 对象的类
* @param _actualTypeClazz
* 泛型类,多范型,例如Map
* @return
* @throws Exception
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static T getNotNullObject(T object, Class clazz, List _actualTypeClazzes) {
try {
if (null == clazz) {
throw new Exception("clazz is NULL");
}
if (null == object) {
return ObjectUtil.getNotNullObject((T) ObjectUtil.getNewInstance(clazz, _actualTypeClazzes), clazz,
_actualTypeClazzes);
}
if (clazz.isPrimitive()) {
return object;
}
if (clazz.isEnum()) {
return object;
}
if (clazz.isInterface()) {
return ObjectUtil.getInterfaceNotNullObject(object, clazz, _actualTypeClazzes);
}
if (clazz.isArray()) {
return ObjectUtil.getArrayNotNullObject(object, clazz, _actualTypeClazzes);
}
if (!clazz.isAnnotation() && !clazz.isInterface() && !clazz.isArray() && !clazz.equals(object.getClass())) {
throw new Exception("object.getClass() and clazz is NOT EQUAL, clazz:" + clazz + ", obejctClass:"
+ object.getClass());
}
// 获取父类字段
Field[] declaredFields = getSuperFields(clazz);
Field.setAccessible(declaredFields, true);
for (Field field : declaredFields) {
// final放过
if (Modifier.isFinal(field.getModifiers())) {
continue;
}
Object fieldObject = field.get(object);
Class fieldClass = field.getType();
List fieldActualTypeClazzes = null;
// 判断泛型
if (field.getGenericType() instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
fieldActualTypeClazzes = new ArrayList();
for (Type type : parameterizedType.getActualTypeArguments()) {
fieldActualTypeClazzes.add((Class) type);
}
}
if (null == fieldObject) {
fieldObject = ObjectUtil.getNewInstance(fieldClass, fieldActualTypeClazzes);
}
field.set(object, ObjectUtil.getNotNullObject(fieldObject, fieldClass, fieldActualTypeClazzes));
}
} catch (Exception e) {
catalinaLog.error("NotNullObject is ERROR , object:" + object + ", class:" + clazz
+ ", _actualTypeClazzes:" + _actualTypeClazzes, e);
}
return object;
}
@SuppressWarnings("rawtypes")
private static Field[] getSuperFields(Class clazz) {
if (null == clazz) {
return new Field[] {};
}
Field[] declaredFields = clazz.getDeclaredFields();
if (null == clazz.getSuperclass()) {
return new Field[] {};
}
Field[] superFields = getSuperFields(clazz.getSuperclass());
return (Field[]) ArrayUtils.addAll(declaredFields, superFields);
}
/**
*
* 获取interface类型的非空对象,TODO 需要自行扩展
*
* @author sunjie at 2016年7月28日
*
* @param clazz
* @param _actualType
* 泛型类型
* @return
* @throws Exception
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static T getInterfaceNotNullObject(T object, Class clazz, List _actualTypeClazzes)
throws Exception {
if (List.class.equals(clazz)) {
List list = (List) object;
Class actualTypeClazz = Object.class;
for (int i = 0; i < list.size(); i++) {
Object entry = list.get(i);
if (!CollectionUtils.isEmpty(_actualTypeClazzes)) {
actualTypeClazz = _actualTypeClazzes.get(0);
}
if (null == entry) {
entry = ObjectUtil.getNewInstance(actualTypeClazz, null);
}
entry = ObjectUtil.getNotNullObject(entry, actualTypeClazz, new ArrayList());
list.remove(i);
list.add(i, entry);
}
return object;
}
if (Map.class.equals(clazz)) {
Map map = (Map) object;
Class actualTypeClazz = Object.class;
for (Object key : map.keySet()) {
if (!CollectionUtils.isEmpty(_actualTypeClazzes) && _actualTypeClazzes.size() > 1) {
actualTypeClazz = _actualTypeClazzes.get(1);// 取value的class
}
Object entry = map.get(key);
if (null == entry) {
entry = ObjectUtil.getNewInstance(actualTypeClazz, null);
}
entry = ObjectUtil.getNotNullObject(entry, actualTypeClazz, new ArrayList());
map.put(key, entry);
}
return object;
}
throw new Exception("not support this interface, clazz:" + clazz);
}
/**
*
* 获取数组的非空对象,TODO 待实现
*
* @author sunjie at 2016年7月28日
*
* @param arrayObject
* @param clazz
* @param _actualTypeClazz
* @return
* @throws Exception
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static T getArrayNotNullObject(T arrayObject, Class clazz, List _actualTypeClazzes)
throws Exception {
Object[] objectArray = (Object[]) arrayObject;
Class arrayClass = clazz.getComponentType();
if (objectArray.length <= 0) {
return (T) Array.newInstance(arrayClass, objectArray.length);
}
for (int i = 0; i < objectArray.length; i++) {
objectArray[i] = ObjectUtil.getNotNullObject(arrayClass.cast(objectArray[i]), arrayClass);
}
return (T) objectArray;
}
/**
*
* 获取基本类型的默认值
*
* @author sunjie at 2016年7月28日
*
* @param clazz
* @return
*/
@SuppressWarnings("rawtypes")
private static Object getPrimitiveDefault(Class clazz) {
if (Boolean.TYPE.equals(clazz)) {
return false;
} else if (Character.TYPE.equals(clazz)) {
return '0';
}
return 0;
}
/**
*
* 获取interface类型的默认值,TODO 需要自行扩展
*
* @author sunjie at 2016年7月28日
*
* @param clazz
* @param _actualType
* 泛型类型
* @return
* @throws Exception
*/
@SuppressWarnings("rawtypes")
private static Object getInterfaceDefault(Class clazz, List _actualTypeClazzes) throws Exception {
if (List.class.equals(clazz)) {
return new ArrayList();
}
if (Map.class.equals(clazz)) {
return new HashMap();
}
throw new Exception("not support this interface, clazz:" + clazz);
}
/**
*
* 获取数组的默认值,TODO 待实现
*
* @author sunjie at 2016年7月28日
*
* @param clazz
* @param _actualType
* 泛型类型
* @return
* @throws Exception
*/
@SuppressWarnings("rawtypes")
private static Object getArrayDefault(Class clazz, List _actualTypeClazzes) throws Exception {
return new ArrayList().toArray();
}
/**
*
* 获取interface类型的默认值,需要自行扩展
*
* @author sunjie at 2016年7月28日
*
* @param clazz
* @param _actualType
* 泛型类型
* @return
* @throws Exception
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static Object getEnumDefault(Class clazz) throws Exception {
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
if (clazz.equals(field.getType())) {
return Enum.valueOf(clazz, field.getName());
}
}
throw new Exception("the enum is NOT VALUE, enum:" + clazz);
}
/**
*
* 构造任意对象的空对象,深层构造
*
* @author sunjie at 2016年7月28日
*
* @param clazz
* @param _actualTypeClazz
* @return
* @throws Exception
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static Object getNewInstance(Class clazz, List _actualTypeClazzes) throws Exception {
// 基本类型
if (clazz.isPrimitive()) {
return ObjectUtil.getPrimitiveDefault(clazz);
}
// enum
if (clazz.isEnum()) {
return ObjectUtil.getEnumDefault(clazz);
}
// interface
if (clazz.isInterface()) {
return ObjectUtil.getInterfaceDefault(clazz, _actualTypeClazzes);
}
// 数组
if (clazz.isArray()) {
return ObjectUtil.getArrayDefault(clazz, _actualTypeClazzes);
}
Object object = new Object();
// 首先获取无参构造器
try {
Constructor constructor = clazz.getDeclaredConstructor();
if (null != constructor) {
object = constructor.newInstance();
}
} catch (NoSuchMethodException e1) {
// 获取InnerClass构造器
try {
Constructor constructor = clazz.getDeclaredConstructor(clazz);
if (null != constructor) {
object = constructor.newInstance(object);
}
} catch (NoSuchMethodException e2) {
// 获取其他类型,取第一个
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
try {
List
测试类:
public static void main(String[] args) throws Exception {
System.out.println("01、testNull对象为null:");
TestNull testNull = null;
System.out.println("====源对象:" + testNull);
TestNull notNullObject = ObjectUtils.getNotNullObject(testNull, TestNull.class, null);
System.out.println("====处理后:" + notNullObject);
System.out.println("");
System.out.println("02、testNull对象内所有属性为null:");
testNull = new TestNull();
System.out.println("====源对象:" + testNull);
notNullObject = ObjectUtils.getNotNullObject(testNull, TestNull.class, null);
System.out.println("====处理后:" + notNullObject);
System.out.println("");
System.out.println("03、testNull对象内List、Map中元素为null:");
testNull = new TestNull();
List testNullChlid1 = new ArrayList.TestNullChlidB>();
testNullChlid1.add(null);
testNull.setTestNullChlid1(testNullChlid1);
Map testNullChlid2 = new HashMap.TestNullChlidB>();
testNullChlid2.put("key1", null);
testNull.setTestNullChlid2(testNullChlid2);
System.out.println("====源对象:" + testNull);
notNullObject = ObjectUtils.getNotNullObject(testNull, TestNull.class, null);
System.out.println("====处理后:" + notNullObject);
System.out.println("");
System.out.println("04、testNull对象内Array中元素为null:");
testNull = new TestNull();
TestNullChlidB[] testNullChlidB3 = new TestNullChlidB[1];
testNullChlidB3[0] = null;
testNull.setTestNullChlid3(testNullChlidB3);
System.out.println("====源对象:" + testNull);
notNullObject = ObjectUtils.getNotNullObject(testNull, TestNull.class, null);
System.out.println("====处理后:" + notNullObject);
}
运行结果如下,满足我们的预期:
01、testNull对象为null:
====源对象:null
====处理后:TestNull [string1=, long1=0, int1=0, float1=0.0, boolean1=false, character1=0, testNullEnum1=ENUM_VALUE0, testNullChlidA1=TestNullChlidA [childAString1=, childALong1=0, childALong2=0, childABoolean1=false, childABoolean2=false, superClass=TestNullChlidBaseA [childBaseAString1=, childBaseALong1=0, childABoolean2=false]], testNullChlid1=[], testNullChlid2={}, testNullChlid3=[]]
02、testNull对象内所有属性为null:
====源对象:TestNull [string1=null, long1=null, int1=0, float1=null, boolean1=null, character1=null, testNullEnum1=null, testNullChlidA1=null, testNullChlid1=null, testNullChlid2=null, testNullChlid3=null]
====处理后:TestNull [string1=, long1=0, int1=0, float1=0.0, boolean1=false, character1=0, testNullEnum1=ENUM_VALUE0, testNullChlidA1=TestNullChlidA [childAString1=, childALong1=0, childALong2=0, childABoolean1=false, childABoolean2=false, superClass=TestNullChlidBaseA [childBaseAString1=, childBaseALong1=0, childABoolean2=false]], testNullChlid1=[], testNullChlid2={}, testNullChlid3=[]]
03、testNull对象内List、Map中元素为null:
====源对象:TestNull [string1=null, long1=null, int1=0, float1=null, boolean1=null, character1=null, testNullEnum1=null, testNullChlidA1=null, testNullChlid1=[null], testNullChlid2={key1=null}, testNullChlid3=null]
====处理后:TestNull [string1=, long1=0, int1=0, float1=0.0, boolean1=false, character1=0, testNullEnum1=ENUM_VALUE0, testNullChlidA1=TestNullChlidA [childAString1=, childALong1=0, childALong2=0, childABoolean1=false, childABoolean2=false, superClass=TestNullChlidBaseA [childBaseAString1=, childBaseALong1=0, childABoolean2=false]], testNullChlid1=[TestNullChlidB [childBString1=, childBFloat1=0.0, testNullEnum1=ENUM_VALUE0]], testNullChlid2={key1=TestNullChlidB [childBString1=, childBFloat1=0.0, testNullEnum1=ENUM_VALUE0]}, testNullChlid3=[]]
04、testNull对象内Array中元素为null:
====源对象:TestNull [string1=null, long1=null, int1=0, float1=null, boolean1=null, character1=null, testNullEnum1=null, testNullChlidA1=null, testNullChlid1=null, testNullChlid2=null, testNullChlid3=[null]]
====处理后:TestNull [string1=, long1=0, int1=0, float1=0.0, boolean1=false, character1=0, testNullEnum1=ENUM_VALUE0, testNullChlidA1=TestNullChlidA [childAString1=, childALong1=0, childALong2=0, childABoolean1=false, childABoolean2=false, superClass=TestNullChlidBaseA [childBaseAString1=, childBaseALong1=0, childABoolean2=false]], testNullChlid1=[], testNullChlid2={}, testNullChlid3=[TestNullChlidB [childBString1=, childBFloat1=0.0, testNullEnum1=ENUM_VALUE0]]]