如何在Java中校验一个对象是否为空
编辑原因
在 SpringBoot
项目中,我们通过对应的 JavaBean
来接收前端传来的 Json
数据,然后执行我们自己的业务逻辑,特殊一点的比如更新接口,我们一般是判断 JavaBean
对象的属性来决定对应的更新SQL,得益于各种框架,我们不用再手动做这种麻烦的事情。
我司项目在下一版本中提出了一个要求:当用户只修改了某一个字段,那么执行不同的逻辑,否则执行更新逻辑。看到这里,我想各位都想的是反射,毕竟一个个的判断属性太low了。 在这里先不论如何实现这个,我突然发现一个问题,如果前端调用更新接口,传过来一个空的json对象,那么会怎么样?
复现
我司使用的 MyBatis(Plus)
来处理数据库相关的操作,因为是更新接口,为了以后方便记录用户的更新日志,所以前端都是用户修改了什么就只传什么过来,自然没办法在参数上添加校验器,由此引申出问题:如果用户传的是 null
或者 {}
,那么会发生什么。
整个service中都没有处理这种情况,最后进入到了 MyBatis
部分,然后执行失败,生成的SQL语句变为了:
update xxx where id = ?
思考
原因很简单,更新的 Entity
中,因为之后 id
不为空(更新接口id是放在url中的),其他的都为 null
,所以生成了这样子的SQL,这自然是不对的,所以我们需要在 Service
或者 Controller
中进行处理。
So. How to detect this situation?
思路1
反射应该是我们第一个想到的,毕竟一个个的 if 判断太low了。 于是,有了如下代码:
/**
* 检测对象的属性是否全部为空
*
* @param object 对象
* @return true: 属性全部为空 false: 属性有的不为空
*/
private <T> boolean isAllFieldsNull(@Nullable T object) throws IllegalAccessException {
if (object == null) {
return true;
}
for (Field declaredField : object.getClass().getDeclaredFields()) {
declaredField.setAccessible(true);
if (declaredField.get(object) != null) {
return false;
}
}
return true;
}
简单,明了。 但是,是存在问题的!!!
如果 object
中存在默认值呢?那么就校验通过了(当然,某些情况下这个也不属于错误,具体看各位的需求)。
还有就是 serialVersionUID
或者说只考虑了引用类型,基本类型没考虑。
思路2
既然想到了上面的问题,所以就自然有对应的解决方法。
得益于 LarryZeal
的文章,我完美的跳过了这个步骤,所以在这里,我就只贴上 LarryZeal
的代码。
/**
* 目的,判断是否有赋值。
* 不能传入null对象!!!
*
* @param obj
* @return
* @throws Exception
*/
public <T> boolean isAllFieldStill(T obj) throws Exception {
Class cls = obj.getClass();
T t2 = (T) cls.getConstructor().newInstance();// 创建一个新的对象,用于对比数据
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true); // 访问所有字段
// if (field.getName().equals("serialVersionUID")) {// 无视掉序列化ID
// continue;
// }
if (field.get(obj) != null) { // 卧槽,基本类型做不到啊
if (field.getType().getName().equals("byte") || field.getType().getName().equals("short")
|| field.getType().getName().equals("int") || field.getType().getName().equals("long")) {
// 判断
if ((int) field.get(obj) != (int) field.get(t2)) {
return false;
}
} else if (field.getType().getName().equals("boolean")) {
// 判断
if ((boolean) field.get(obj) != (boolean) field.get(t2)) {
return false;
}
} else if (field.getType().getName().equals("float")) {
// 判断
if ((float) field.get(obj) != (float) field.get(t2)) {
return false;
}
} else if (field.getType().getName().equals("double")) {
// 判断
if ((double) field.get(obj) != (double) field.get(t2)) {
return false;
}
} else {
// 都是引用类型了(引用类型需要有equals方法)
// 判断....
if (!field.get(obj).equals(field.get(t2))) {
return false;
}
}
return false;
}
}
return true;
}
思路3
直接使用新的对象然后使用 equals
判断不就行了?
按理说应该是行的,但是我试了……不行
换一种思路
既然前端提交的是 json
串,那么我们能不能从 json
角度去判断呢?
于是有了以下代码:
/**
* 判断对象的所有属性是否为空
*
* @param value 对象
* @param <T> 范型
* @return true: 全部属性为空 false: 全部属性不为空
*/
public static <T> boolean isAllFieldNull(@Nullable T value) {
if (value == null) {
return true;
}
try {
String origin = JSON.toJSONString(value);
String empty = JSON.toJSONString(value.getClass().newInstance());
return origin.equals(empty);
} catch (Exception e) {
log.warn("verify object failed", e);
return true;
}
}
但是 这种方法是有一定条件的,我们都知道不同的 json
处理器对空数据的判定不一样,没有这个属性算不算null?字符串值是 ""
算不算 null
?有这个属性但是值是null算不算null?
我们只需要定义好自己的 json
处理逻辑,然后将需要判断的对象以及使用反射创建的一个空对象转换成 json
数据,只要 json
处理逻辑没问题,判断两个字符串是否相等就行了。
延伸
判断List中所有的数据是否为空
/**
* 判断集合的所有成员是否为空
*
* @param collection 集合
* @param <T> 范型
* @return true: 全部成员为空 false: 全部成员中有的不为空
*/
public static <T> boolean isAllElementNull(@Nullable Collection<T> collection) {
if (collection == null) {
return true;
}
if (CollectionUtils.isEmpty(collection)) {
return true;
}
for (T t : collection) {
boolean result = isAllFieldNull(t);
if (result) {
return false;
}
}
return true;
}
感谢列表
- 0
- 0
-
分享