最近在编写程序在使用mybatis(3.4.6版本) Mapper进行SQL语句映射查询时发现在的test中使用判断语句时,当判断条件为flag!="" 且flag为数字等于0时返回的结果为false
跟踪mybatis的的执行源码时发现。
```java
class ASTNotEq extends ComparisonExpression {
public ASTNotEq(int id) {
super(id);
}
public ASTNotEq(OgnlParser p, int id) {
super(p, id);
}
protected Object getValueBody(OgnlContext context, Object source) throws OgnlException {
//获取到用户输入的数据
Object v1 = this._children[0].getValue(context, source);
//获取到 flag != "" 中的 "" 也就是写定的后置条件
Object v2 = this._children[1].getValue(context, source);
return OgnlOps.equal(v1, v2) ? Boolean.FALSE : Boolean.TRUE;
}
public String getExpressionOperator(int index) {
return "!=";
}
public String getComparisonFunction() {
return "!ognl.OgnlOps.equal";
}
}
```
跟踪equal得到
```java
public static boolean equal(Object v1, Object v2) {
if (v1 == null) {
return v2 == null;
} else if (v1 != v2 && !isEqual(v1, v2)) {
if (v1 instanceof Number && v2 instanceof Number) {
return ((Number)v1).doubleValue() == ((Number)v2).doubleValue();
} else {
return false;
}
} else {
return true;
}
}
```
可以看到在v1不等于null时,进行isEqual的判断,查看isEqul的代码
```
public static boolean isEqual(Object object1, Object object2) {
boolean result = false;
if (object1 == object2) {
result = true;
} else if (object1 != null && object1.getClass().isArray()) {
if (object2 != null && object2.getClass().isArray() && object2.getClass() == object1.getClass()) {
result = Array.getLength(object1) == Array.getLength(object2);
if (result) {
int i = 0;
for(int icount = Array.getLength(object1); result && i < icount; ++i) {
result = isEqual(Array.get(object1, i), Array.get(object2, i));
}
}
}
} else {
result = object1 != null && object2 != null && (object1.equals(object2) || compareWithConversion(object1, object2) == 0);
}
return result;
}
```
在上述条件中,v1=0且v2=""的情况下,会进行compareWithConversion的判断
```
public static int compareWithConversion(Object v1, Object v2) {
int result;
if (v1 == v2) {
result = 0;
} else {
int t1 = getNumericType(v1);
int t2 = getNumericType(v2);
int type = getNumericType(t1, t2, true);
switch(type) {
case 6:
result = bigIntValue(v1).compareTo(bigIntValue(v2));
break;
case 9:
result = bigDecValue(v1).compareTo(bigDecValue(v2));
break;
case 10:
if (t1 == 10 && t2 == 10) {
if (v1 instanceof Comparable && v1.getClass().isAssignableFrom(v2.getClass())) {
result = ((Comparable)v1).compareTo(v2);
break;
}
throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and " + v2.getClass().getName());
}
case 7:
case 8:
double dv1 = doubleValue(v1);
double dv2 = doubleValue(v2);
return dv1 == dv2 ? 0 : (dv1 < dv2 ? -1 : 1);
default:
long lv1 = longValue(v1);
long lv2 = longValue(v2);
return lv1 == lv2 ? 0 : (lv1 < lv2 ? -1 : 1);
}
}
return result;
}
```
继续查看getNumericType方法
```
public static int getNumericType(Object value) {
if (value != null) {
Class c = value.getClass();
if (c == Integer.class) {
return 4;
}
if (c == Double.class) {
return 8;
}
if (c == Boolean.class) {
return 0;
}
if (c == Byte.class) {
return 1;
}
if (c == Character.class) {
return 2;
}
if (c == Short.class) {
return 3;
}
if (c == Long.class) {
return 5;
}
if (c == Float.class) {
return 7;
}
if (c == BigInteger.class) {
return 6;
}
if (c == BigDecimal.class) {
return 9;
}
}
return 10;
}
```
可以了解到getNumericType是通过对象的类型,返回其类的指定代码的函数
可以得到 v1为integer类型 返回的结果为4,v2为String类型,返回结果为10
之后进入case判断,通过第二个getNumericType的代码
```
public static int getNumericType(int t1, int t2, boolean canBeNonNumeric) {
if (t1 == t2) {
return t1;
} else if (canBeNonNumeric && (t1 == 10 || t2 == 10 || t1 == 2 || t2 == 2)) {
return 10;
} else {
if (t1 == 10) {
t1 = 8;
}
if (t2 == 10) {
t2 = 8;
}
if (t1 >= 7) {
if (t2 >= 7) {
return Math.max(t1, t2);
} else if (t2 < 4) {
return t1;
} else {
return t2 == 6 ? 9 : Math.max(8, t1);
}
} else if (t2 >= 7) {
if (t1 < 4) {
return t2;
} else {
return t1 == 6 ? 9 : Math.max(8, t2);
}
} else {
return Math.max(t1, t2);
}
}
```
最终返回的数值为10,
```java
case 10:
if (t1 == 10 && t2 == 10) {
if (v1 instanceof Comparable && v1.getClass().isAssignableFrom(v2.getClass())) {
result = ((Comparable)v1).compareTo(v2);
break;
}
throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and " + v2.getClass().getName());
}
case 7:
case 8:
double dv1 = doubleValue(v1);
double dv2 = doubleValue(v2);
return dv1 == dv2 ? 0 : (dv1 < dv2 ? -1 : 1);
```
查看case 10:的代码可以得知,只有当两者皆为String类型时,才会进入case 10的条件中进行判断,否则,跳过10 ,进入case 8的语句中 ,也就是默认两者皆为double类型。
查看doubleValue方法
```
public static double doubleValue(Object value) throws NumberFormatException {
if (value == null) {
return 0.0D;
} else {
Class c = value.getClass();
if (c.getSuperclass() == Number.class) {
return ((Number)value).doubleValue();
} else if (c == Boolean.class) {
return (Boolean)value ? 1.0D : 0.0D;
} else if (c == Character.class) {
return (double)(Character)value;
} else {
String s = stringValue(value, true);
return s.length() == 0 ? 0.0D : Double.parseDouble(s);
}
}
}
```
v1为用户输入值,在此前的场景中为Integer类型的0,可以看到最终结果为
double dv1=0.0
v2为写定的结果,为String类型的"",在判断中通过对String的长度判断进行赋值,而""在判断逻辑中等同于0.0D,结果为double dv2=0.0
最终得出 0==""的结果。