Skip to content

Commit

Permalink
Improve getBestCandidate() for BigDecimal args
Browse files Browse the repository at this point in the history
- [DROOLS-5284] MVELTest.testTypeCoercionLongDivByInt fails with IBM JDK 8
  • Loading branch information
tkobayas committed May 1, 2020
1 parent 71d422a commit d9d0a93
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 2 deletions.
35 changes: 34 additions & 1 deletion src/main/java/org/mvel2/util/ParseTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ public static Method getBestCandidate(Class[] arguments, String method, Class de
bestScore = score;
}
else if (score == bestScore) {
if (isMoreSpecialized(meth, bestCandidate) && !isVarArgs) {
if ((isMoreSpecialized(meth, bestCandidate) || isMorePreciseForBigDecimal(meth, bestCandidate, arguments))&& !isVarArgs) {
bestCandidate = meth;
}
}
Expand Down Expand Up @@ -309,6 +309,39 @@ private static boolean isMoreSpecialized( Method newCandidate, Method oldCandida
oldCandidate.getDeclaringClass().isAssignableFrom( newCandidate.getDeclaringClass());
}

private static boolean isMorePreciseForBigDecimal(Method newCandidate, Method oldCandidate, Class[] arguments) {
Class<?>[] newParmTypes = newCandidate.getParameterTypes();
Class<?>[] oldParmTypes = oldCandidate.getParameterTypes();
int score = 0;
for (int i = 0; i != arguments.length; i++) {
Class<?> newParmType = newParmTypes[i];
Class<?> oldParmType = oldParmTypes[i];
if (arguments[i] != BigDecimal.class || !isNumeric(oldParmType) || !isNumeric(newParmType)) {
continue;
}
score += comparePrecision(unboxPrimitive(newParmType), unboxPrimitive(oldParmType));
}
return (score > 0);
}

private static int comparePrecision(Class<?> numeric1, Class<?> numeric2) {
if (numeric1 == numeric2) {
return 0;
}
if ((numeric1 == double.class) && (numeric2 == float.class || numeric2 == long.class || numeric2 == int.class || numeric2 == short.class)) {
return 1;
} else if ((numeric1 == float.class) && (numeric2 == long.class || numeric2 == int.class || numeric2 == short.class)) {
// float is preferred over long assuming users don't want to lose decimal part
return 1;
} else if ((numeric1 == long.class) && (numeric2 == int.class || numeric2 == short.class)) {
return 1;
} else if ((numeric1 == int.class) && numeric2 == short.class) {
return 1;
} else {
return -1;
}
}

private static int getMethodScore(Class[] arguments, boolean requireExact, Class<?>[] parmTypes, boolean varArgs) {
int score = 0;
for (int i = 0; i != arguments.length; i++) {
Expand Down
19 changes: 18 additions & 1 deletion src/test/java/org/mvel2/tests/core/CoreConfidenceTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import java.util.concurrent.atomic.AtomicInteger;

import junit.framework.TestCase;

import org.junit.Assert;
import org.mvel2.CompileException;
import org.mvel2.DataConversion;
import org.mvel2.MVEL;
Expand Down Expand Up @@ -4882,4 +4882,21 @@ public void testLiteralToStringWithSpace() throws Throwable {
Serializable s = MVEL.compileExpression(expr);
assertEquals(Integer.valueOf(hashCode), MVEL.executeExpression(s));
}

public void testGetBestCandidateForBigDecimalArg() {
Class<?>[] arguments = new Class<?>[] {BigDecimal.class};
Method method = ParseTools.getBestCandidate(arguments, "round", Math.class, Math.class.getMethods(), true);
assertEquals(long.class, method.getReturnType());
Assert.assertArrayEquals(new Class<?>[] {double.class}, method.getParameterTypes());

arguments = new Class<?>[] {BigDecimal.class, BigDecimal.class};
method = ParseTools.getBestCandidate(arguments, "max", Math.class, Math.class.getMethods(), true);
assertEquals(double.class, method.getReturnType());
Assert.assertArrayEquals(new Class<?>[] {double.class, double.class}, method.getParameterTypes());

arguments = new Class<?>[] {BigDecimal.class, BigDecimal.class};
method = ParseTools.getBestCandidate(arguments, "scalb", Math.class, Math.class.getMethods(), true);
assertEquals(double.class, method.getReturnType());
Assert.assertArrayEquals(new Class<?>[] {double.class, int.class}, method.getParameterTypes());
}
}

0 comments on commit d9d0a93

Please sign in to comment.