LitePal
LitePal copied to clipboard
有参构造器存在风险
当生成对象时,利用
org.litepal.crud.DataHandler#findBestSuitConstructor 找到了一个最合适的构造器,
如果这个构造器是一个有参构造器,且有空指针风险时,例如:
public class Bar extends LitePalSupport {
public int i;
public String s;
public Bar(BarArg arg) {
i = arg.i;
s = arg.s;
}
public Bar(@NonNull BarArg2 arg) {
i = arg.i;
s = arg.bean.s;
}
@Override
public String toString() {
return "Bar{" +
"i=" + i +
", s='" + s + '\'' +
'}';
}
}
public class BarArg2 {
public static class Bean {
public String s;
}
public int i;
public Bean bean;
}
会出现空指针,实际使用的构造函数为: Bar(BarArg2 arg), arg.bean.s;出现空指针。
虽然这是业务方的疏漏,但是有点不太友好,这要求业务方对类似BarArg2的类均需要提供合适的构造器,例如:
public class BarArg2 {
public static class Bean {
@NonNull
public String s;
public Bean(@NonNull String s) {
this.s = s;
}
}
public int i;
@NonNull
public Bean bean;
public BarArg2(int i, @NonNull Bean bean) {
this.i = i;
this.bean = bean;
}
}
或者
public class BarArg2 {
public static class Bean {
@NonNull
public String s;
public Bean(@NonNull String s) {
this.s = s;
}
}
public int i;
@NonNull
public Bean bean;
public BarArg2(@NonNull Bean bean) {
this.bean = bean;
}
}
这两种情况下均不会出现空指针
或者要求Bar提供无参构造(这会被认为是最合适的构造器选择出来
建议直接使用Unsafe类生成实例
public class UnsafeHelper {
private UnsafeHelper() {
}
private static final Object unsafe;
private static final Method allocateInstance;
static {
final Class<?> unsafeClass;
final Field theUnsafeField;
try {
unsafeClass = Class.forName("sun.misc.Unsafe");
} catch (ClassNotFoundException e) {
throw new UnsupportedOperationException("can't find sun.misc.Unsafe. " + e.getMessage(), e);
}
try {
theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");
} catch (NoSuchFieldException e) {
throw new UnsupportedOperationException("can't find the field theUnsafe in sun.misc.Unsafe." + e.getMessage(), e);
}
theUnsafeField.setAccessible(true);
try {
unsafe = theUnsafeField.get(null);
} catch (IllegalAccessException e) {
throw new UnsupportedOperationException("get Unsafe instance failed: " + e.getMessage(), e);
}
try {
allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
} catch (NoSuchMethodException e) {
throw new UnsupportedOperationException("can't find the method allocateInstance in sun.misc.Unsafe : " + e.getMessage(),
e);
}
}
public static <T> T newInstance(Class<?> clazz) {
try {
return (T) allocateInstance.invoke(unsafe, clazz);
} catch (Exception e) {
throw new UnsupportedOperationException("create instance for " + clazz + " failed. " + e.getMessage(), e);
}
}
}
这样可以避免稀奇古怪的业务问题。就不提Pr了
你的提议是有道理的,我也确实有计划在下个版本中使用Unsafe API来构建对象的实例,谢谢建议。
刚才又反思了一下,上文体积的UnSafe助手类,还不适合直接放入litepal中使用,还不够全面完善,对于plain object类而言没多大问题,对于ArrayList等jdk中的类而言反而会出现问题。
感谢采纳。
过段时间不太忙的时候准备把项目里的litepal升级一波了。