You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Henri Biestro (JIRA)" <ji...@apache.org> on 2012/05/11 14:21:52 UTC

[jira] [Commented] (JEXL-132) divide zero error and others

    [ https://issues.apache.org/jira/browse/JEXL-132?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13273196#comment-13273196 ] 

Henri Biestro commented on JEXL-132:
------------------------------------

Hi;
About the "MyMath" class behavior, Jexl only looks by design at "public" classes; what you observe is thus not a bug (might be an RFE).
Division by zero will throw an exception if the JexlEngine (or at least the JexlArithmetic) is set to strict mode.

That being said, the JexlArithmetic behavior can be altered by deriving the class.
And the "preferred" way of dealing with the "Math" class - or any class only meant to expose static methods - it to use it as a namespace.
The following code might help you getting started in this direction:

{code:title=IssuesTest.java|borderStyle=solid}

    public static class Arithmetic132 extends JexlArithmetic {
        public Arithmetic132() {
            super(false);
        }

        protected double divideZero(BigDecimal x) {
            int ls = x.signum();
            if (ls < 0) {
                return Double.NEGATIVE_INFINITY;
            } else if (ls > 0) {
                return Double.POSITIVE_INFINITY;
            } else {
                return Double.NaN;
            }
        }

        protected double divideZero(BigInteger x) {
            int ls = x.signum();
            if (ls < 0) {
                return Double.NEGATIVE_INFINITY;
            } else if (ls > 0) {
                return Double.POSITIVE_INFINITY;
            } else {
                return Double.NaN;
            }
        }

        @Override
        public Object divide(Object left, Object right) {
            if (left == null && right == null) {
                return controlNullNullOperands();
            }
            // if either are bigdecimal use that type
            if (left instanceof BigDecimal || right instanceof BigDecimal) {
                BigDecimal l = toBigDecimal(left);
                BigDecimal r = toBigDecimal(right);
                if (BigDecimal.ZERO.equals(r)) {
                    return divideZero(l);
                }
                BigDecimal result = l.divide(r, getMathContext());
                return narrowBigDecimal(left, right, result);
            }
            // if either are floating point (double or float) use double
            if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
                double l = toDouble(left);
                double r = toDouble(right);
                return new Double(l / r);
            }
            // otherwise treat as integers
            BigInteger l = toBigInteger(left);
            BigInteger r = toBigInteger(right);
            if (BigInteger.ZERO.equals(r)) {
                return divideZero(l);
            }
            BigInteger result = l.divide(r);
            return narrowBigInteger(left, right, result);
        }

        @Override
        public Object mod(Object left, Object right) {
            if (left == null && right == null) {
                return controlNullNullOperands();
            }
            // if either are bigdecimal use that type
            if (left instanceof BigDecimal || right instanceof BigDecimal) {
                BigDecimal l = toBigDecimal(left);
                BigDecimal r = toBigDecimal(right);
                if (BigDecimal.ZERO.equals(r)) {
                    return divideZero(l);
                }
                BigDecimal remainder = l.remainder(r, getMathContext());
                return narrowBigDecimal(left, right, remainder);
            }
            // if either are floating point (double or float) use double
            if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
                double l = toDouble(left);
                double r = toDouble(right);
                return new Double(l % r);
            }
            // otherwise treat as integers
            BigInteger l = toBigInteger(left);
            BigInteger r = toBigInteger(right);
            BigInteger result = l.mod(r);
            if (BigInteger.ZERO.equals(r)) {
                return divideZero(l);
            }
            return narrowBigInteger(left, right, result);
        }
    }

    JexlEngine createJexl132() {
        Map<String, Object> ns = new HashMap<String, Object>();
        ns.put("math", Math.class);
        return new JexlEngine(null, new Arithmetic132(), ns, null);

    }

    public void test132a() throws Exception {
        JexlEngine jexl = createJexl132();
        String expr = "1/0";

        Object evaluate = jexl.createExpression(expr).evaluate(null);
        assertTrue(Double.isInfinite((Double) evaluate));

        expr = "-1/0";
        evaluate = jexl.createExpression(expr).evaluate(null);
        assertTrue(Double.isInfinite((Double) evaluate));
    }

    public void test132b() throws Exception {
        JexlEngine jexl = createJexl132();
        String expr = "1.0/0.0";

        Object evaluate = jexl.createExpression(expr).evaluate(null);
        assertTrue(Double.isInfinite((Double) evaluate));

        expr = "-1.0/0";
        evaluate = jexl.createExpression(expr).evaluate(null);
        assertTrue(Double.isInfinite((Double) evaluate));
    }

    public void test132c() throws Exception {
        JexlEngine jexl = createJexl132();

        String expr = "math:abs(-42)";

        Object evaluate = jexl.createExpression(expr).evaluate(null);
        assertEquals(42, evaluate);
    }
{code} 
                
> divide zero error and others
> ----------------------------
>
>                 Key: JEXL-132
>                 URL: https://issues.apache.org/jira/browse/JEXL-132
>             Project: Commons JEXL
>          Issue Type: Bug
>    Affects Versions: 2.1.1
>         Environment: JEXL2.1.1 jdk1.5.0_22
>            Reporter: freish
>              Labels: jexl
>
> code snippet:
> 		String exp;
> 		Expression expression;
> 		JexlEngine engine = new JexlEngine();
> 		
> 		exp = "1/0";
> 		expression = engine.createExpression(exp);
> 		System.out.println(expression.evaluate(null));
> this will print 0.0,shoud it indicate an error by throwing exception or return value?
> ----------------------------------------------
> code snippet:
> 		exp = "1/0.0";
> 		expression = engine.createExpression(exp);
> 		System.out.println(expression.evaluate(null));
> this will print 0.0 too,but in fact it should return Infinity.
> ----------------------------------------------
> code snippet:
> 		exp = "Math.abs(-1)";
> 		expression = engine.createExpression(exp);
> 		System.out.println(expression.evaluate(null));
> I don't know whether this is a bug.JEXL cannot invoke java static method directly,it will throw an exception
> ----------------------------------------------
> code snippet:
> 		exp = "a.abs(-1)";
> 		class MyMath {
> 			public double abs(double d) {
> 				return Math.abs(d);
> 			} 
> 		}
> 		Object obj = new MyMath();
> 		expression = engine.createExpression(exp);
> 		MapContext c = new MapContext();
> 		c.set("a", obj);
> 		System.out.println(expression.evaluate(c));
> er,this is very strange,if MyMath is not public(whether in a independent file or not),it will return null;but if MyMath is a public class,it will behave correctly

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira