昨天发现一个鬼畜问题,测试环境和生产的配置互换后,测试后把环境切换回测试就一直报错,原因是用户表中生的一个用户生成了两个openId,getOne后报错,于是做出了一些改变:
QueryWrapper<MiniproUser> wrapper = new QueryWrapper<MiniproUser>().eq("openid",
loginResult.getOpenid());
MiniproUser user = this.list(wrapper) == null?null:this.list(wrapper).get(0);
把原来的getOne()改为了list,有数据取第一条,结果偏偏集合判空这里出了,如果用户不存在,走到这行代码直接抛异常。这里对OpenId重新设置下,模拟新用户注册的情况:
结果发现成勋直接跳到了catch代码块并抛出:java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
有说法是:
实体类使用了@Builder注解,则无法使用无参构造函数,最终导致mybatis在创建实体时报错
在实体类加上@NoArgsConstructor和@AllArgsConstructor即可使用无参构造函数(来源:Mybatis查询报IndexOutOfBoundsException - 博客 - 编程圈)
但是我确实使用了@Builder,但是也已经添加了@NoArgsConstructor和@AllArgsConstructor:
微微一笑发现问题并没有那么简单,既然直接判空集合不行,用工具类试试,然后调试进入看一下:
于是进行改造如下:
MiniproUser user = ObjectUtils.isEmpty(this.list(wrapper))?null:this.list(wrapper).get(0);
进入isEmpty()调试发现:
/**
* Determine whether the given object is empty.
* <p>This method supports the following object types.
* <ul>
* <li>{@code Optional}: considered empty if {@link Optional#empty()}</li>
* <li>{@code Array}: considered empty if its length is zero</li>
* <li>{@link CharSequence}: considered empty if its length is zero</li>
* <li>{@link Collection}: delegates to {@link Collection#isEmpty()}</li>
* <li>{@link Map}: delegates to {@link Map#isEmpty()}</li>
* </ul>
* <p>If the given object is non-null and not one of the aforementioned
* supported types, this method returns {@code false}.
* @param obj the object to check
* @return {@code true} if the object is {@code null} or <em>empty</em>
* @since 4.2
* @see Optional#isPresent()
* @see ObjectUtils#isEmpty(Object[])
* @see StringUtils#hasLength(CharSequence)
* @see StringUtils#isEmpty(Object)
* @see CollectionUtils#isEmpty(java.util.Collection)
* @see CollectionUtils#isEmpty(java.util.Map)
*/
@SuppressWarnings("rawtypes")
public static boolean isEmpty(@Nullable Object obj) {
if (obj == null) {
return true;
}
if (obj instanceof Optional) {
return !((Optional) obj).isPresent();
}
if (obj instanceof CharSequence) {
return ((CharSequence) obj).length() == 0;
}
if (obj.getClass().isArray()) {
return Array.getLength(obj) == 0;
}
if (obj instanceof Collection) {
return ((Collection) obj).isEmpty();
}
if (obj instanceof Map) {
return ((Map) obj).isEmpty();
}
// else
return false;
}
第一个if判断obj竟然不是null,查看堆栈信息,发现里边是一个LinkedList,而且内部还有Map,存放有框架和mybatis的一些东西,猜想是一个返回数据集的附加信息,但是没有真正需要的数据在里边,因此,为了保险起见,改成
ObjectUtils.isEmpty(this.list(wrapper))
或者
this.list(wrapper).size == 0
经过测试两者都可以。
总结:在使用框架或者封装第三方的工具时,对于一些常见的集合操作或者判断操作,还是谨慎选择,因为经过层层封装后的对象,你不知道里边带了究竟有多少其他的东西,很可能会给出错误的结果。