结论

    名称 支持高精度 测试版本 说明
    Ognl 3.2.18 ognl <= 2.7.1 版本存在问题 注(1)
    Jexl 3.1
    MVEL 2.4.12.Final
    JEPLite 0.8.7a addVariable方法只支持double变量
    JEval 0.9.4 变量要用#{x};putVariable方法只支持string(转换为double计算)
    Janino 2.5.10 变量值是BigDecimal时报错

    注(1):ognl 版本问题
    计算 “a<=-0.1”,当 a = new BigDecimal(“-0.1”) 时,本应返回true,但是 ognl <= 2.7.1 版本返回false

    测试代码

    1. import java.io.Serializable;
    2. import java.math.BigDecimal;
    3. import java.util.ArrayList;
    4. import java.util.HashMap;
    5. import java.util.List;
    6. import java.util.Map;
    7. import java.util.Map.Entry;
    8. import org.apache.commons.jexl3.JexlContext;
    9. import org.apache.commons.jexl3.JexlEngine;
    10. import org.apache.commons.jexl3.JexlExpression;
    11. import org.apache.commons.jexl3.MapContext;
    12. import org.apache.commons.jexl3.internal.Engine;
    13. import org.cheffo.jeplite.JEP;
    14. import org.codehaus.janino.ExpressionEvaluator;
    15. import org.mvel2.MVEL;
    16. import com.gitee.qdbp.tools.utils.OgnlTools;
    17. import net.sourceforge.jeval.Evaluator;
    18. public class ExpressionTest {
    19. public static void main(String[] args) throws Exception {
    20. String content = "x-y";
    21. Map<String, BigDecimal> map = new HashMap<>();
    22. map.put("x", new BigDecimal("0.9"));
    23. map.put("y", new BigDecimal("1"));
    24. { // Java精度问题: 0.9-1=-0.09999999999999998
    25. double result = 0.9 - 1;
    26. System.out.printf("%-10s %s%n", "Java:", result);
    27. }
    28. { // Ognl支持BigDecimal: 0.9-1=-0.1
    29. Object result = OgnlTools.getValue(map, content);
    30. System.out.printf("%-10s %s%n", "Ognl:", result);
    31. }
    32. { // Jexl支持BigDecimal: 0.9-1=-0.1
    33. JexlContext context = new MapContext();
    34. for (Entry<String, BigDecimal> entry : map.entrySet()) {
    35. context.set(entry.getKey(), entry.getValue());
    36. }
    37. JexlEngine engine = new Engine();
    38. JexlExpression expression = engine.createExpression(content);
    39. Object result = expression.evaluate(context);
    40. System.out.printf("%-10s %s%n", "Jexl:", result);
    41. }
    42. { // MVEL支持BigDecimal: 0.9-1=-0.1
    43. Serializable expression = MVEL.compileExpression(content);
    44. Object result = MVEL.executeExpression(expression, map);
    45. System.out.printf("%-10s %s%n", "MVEL:", result);
    46. }
    47. { // JEPLite只支持double: 0.9-1=-0.09999999999999998
    48. JEP jep = new JEP();
    49. for (Entry<String, BigDecimal> entry : map.entrySet()) {
    50. jep.addVariable(entry.getKey(), entry.getValue().doubleValue());
    51. }
    52. jep.parseExpression(content);
    53. Object result = jep.getValue();
    54. System.out.printf("%-10s %s%n", "JEPLite:", result);
    55. }
    56. { // JEval表达式中的变量要用#{x}, 变量值只支持string, 会转换为double计算, 导致精度误差
    57. String string = "#{x}-#{y}";
    58. Evaluator evaluator = new Evaluator();
    59. for (Entry<String, BigDecimal> entry : map.entrySet()) {
    60. if (entry.getValue() != null) {
    61. evaluator.putVariable(entry.getKey(), String.valueOf(entry.getValue()));
    62. }
    63. }
    64. Object result = evaluator.evaluate(string);
    65. System.out.printf("%-10s %s%n", "JEval:", result);
    66. }
    67. { // Janino不支持BigDecimal计算: 0.9-1=-0.09999999999999998
    68. List<String> keys = new ArrayList<>();
    69. List<Object> values = new ArrayList<>();
    70. List<Class<?>> types = new ArrayList<>();
    71. for (Entry<String, BigDecimal> entry : map.entrySet()) {
    72. if (entry.getValue() != null) {
    73. keys.add(entry.getKey());
    74. values.add(entry.getValue().doubleValue());
    75. types.add(double.class);
    76. }
    77. }
    78. ExpressionEvaluator evaluator = new ExpressionEvaluator();
    79. evaluator.setParameters(keys.toArray(new String[0]), types.toArray(new Class<?>[0]));
    80. evaluator.cook(content);
    81. Object result = evaluator.evaluate(values.toArray());
    82. System.out.printf("%-10s %s%n", "Janino:", result);
    83. }
    84. }
    85. }

    涉及到的jar包

    1. <dependency>
    2. <groupId>ognl</groupId>
    3. <artifactId>ognl</artifactId>
    4. <version>3.2.18</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>net.sourceforge.jeval</groupId>
    8. <artifactId>jeval</artifactId>
    9. <version>0.9.4</version>
    10. </dependency>
    11. <dependency>
    12. <groupId>org.cheffo</groupId>
    13. <artifactId>jeplite</artifactId>
    14. <version>0.8.7a</version>
    15. </dependency>
    16. <dependency>
    17. <groupId>janino</groupId>
    18. <artifactId>janino</artifactId>
    19. <version>2.5.10</version>
    20. </dependency>
    21. <dependency>
    22. <groupId>org.mvel</groupId>
    23. <artifactId>mvel2</artifactId>
    24. <version>2.4.12.Final</version>
    25. </dependency>
    26. <dependency>
    27. <groupId>org.apache.commons</groupId>
    28. <artifactId>commons-jexl3</artifactId>
    29. <version>3.1</version>
    30. </dependency>