jaxen
  1. jaxen
  2. JAXEN-213

The function NumberFunction.evaluate() accepts only String and Double, but no Integer any more.

    Details

    • Type: Bug Bug
    • Status: Resolved Resolved
    • Priority: Major Major
    • Resolution: Not A Bug
    • Affects Version/s: 2.0
    • Fix Version/s: None
    • Component/s: core, function
    • Labels:
      None
    • Number of attachments :
      0

      Description

      In the version 1.0 of Jaxen integer worked in this function. I can't imagine that this problem is a new feature, because integer can always be converted into a double without any lose of information whereas even String is accepted.
      Since we use Jaxen in the core of our main application, we will have to change a lot of methods in order to upgrade to the new version of Jaxen. Therefore it would be great when you could fix this issue in the next version.
      An example from our code: We use XML to generate dynamic web sites. The "g:if" condition uses Jaxen:
      <g:if test="form('count')='1'">
      After an update to the new version of Jaxen this condition is always false. Though String '1' is converted to a number, it can't be compared to the function "count", because this function returns an integer value.

      To fix this issue you have to add to NumberFunction.evaluate(Object obj, Navigator nav) something like this:

      else if( obj instanceof Integer)

      { return (Double) obj; }

        Activity

        Hide
        Elliotte Rusty Harold added a comment -

        I'll look into this. However it's not immediately apparent to me that this is a bug. XPath does not have an integer data type. All numbers in XPath are floating point, not integers:

        http://www.w3.org/TR/xpath/#numbers

        Do you have a test case that demonstrates the bug by evaluation of an XPath expression? (i.e. does not directly call the Number function in code). That would be more convincing.

        In the example you cite I think you're actually comparing strings, not numbers. Try

        <g:if test="form('count')=1">

        instead and see if that works.

        Show
        Elliotte Rusty Harold added a comment - I'll look into this. However it's not immediately apparent to me that this is a bug. XPath does not have an integer data type. All numbers in XPath are floating point, not integers: http://www.w3.org/TR/xpath/#numbers Do you have a test case that demonstrates the bug by evaluation of an XPath expression? (i.e. does not directly call the Number function in code). That would be more convincing. In the example you cite I think you're actually comparing strings, not numbers. Try <g:if test="form('count')=1"> instead and see if that works.
        Hide
        Andreas Konnikov added a comment -

        Thank you for your reply. In the example I compare a Number value with a String. "1" is a String, but "form('count')" returns an integer.
        Here is the usage of Jaxen in our code.
        A sample of XML code: <g:if test="form('campaignClone.uid') and form('orderClone.state') = '1'">

        The code where XPath is called to evaluate whether the condition is true:
        if ("if".equals(localName) && optimizeIf == 0 && !suspendOptimizeIf) {
        try {
        String value = attributes.getValue("test");
        value = expandAVT(value, true, currentElement);
        JDOMXPath path = new JDOMXPath(value);
        path.setFunctionContext(xPathFunctions);
        boolean ok = path.booleanValueOf(currentElement);
        ...

        The variable "value" contains the String: "form('campaignClone.uid') and form('orderClone.state') = '1'"
        xPathFunctions is an Instance of XPathFunctions, a subclass of FunctionContext. xPathFunctions defines how the condition is interpreted. form('orderClone.state') calls getOrderClone.getState
        and form('campaignClone.uid') calls getCampaignClone.getUid of the corresponding form class.

        public int getState()

        { return state; }

        public Long getUid()

        { return uid; }

        This condition is always false with the new version of Jaxen, because getState is an Integer and getUid is a Long value

        We had to patch the NumberFunction so we could use Jaxen as usual.
        Here is the code.

        public static Double evaluate(Object obj, Navigator nav) {
        if (obj instanceof Double)

        { return (Double) obj; }

        else if (obj instanceof Number)

        { return ((Number) obj).doubleValue(); }

        else if (obj instanceof String) {
        String str = (String) obj;
        try

        { Double doubleValue = new Double(str); return doubleValue; }

        catch (NumberFormatException e)

        { return NaN; }

        } else if (obj instanceof List || obj instanceof Iterator)

        { return evaluate(StringFunction.evaluate(obj, nav), nav); } else if (nav.isElement(obj) || nav.isAttribute(obj)) { return evaluate(StringFunction.evaluate(obj, nav), nav); }

        else if (obj instanceof Boolean) {
        if (obj == Boolean.TRUE)

        { return new Double(1); }

        else

        { return new Double(0); }

        }
        return NaN;
        }

        I think that this problem is a bug, because a Not a Number Exception for an Integer value is an unexpected behavior of a class called “NumberFunction”. A number function is expected to work with all kinds of numbers, especially integer and not only double and String. Otherwise it could be called “DoubleFunction”. This class indeed worked that way in the former version. When only doubles are used internally, other kind of numbers should be accepted and casted the same way it is done with Strings

        It would be good when this issue would be solved, so we won't have to patch the class after every update of Jaxen.

        Show
        Andreas Konnikov added a comment - Thank you for your reply. In the example I compare a Number value with a String. "1" is a String, but "form('count')" returns an integer. Here is the usage of Jaxen in our code. A sample of XML code: <g:if test="form('campaignClone.uid') and form('orderClone.state') = '1'"> The code where XPath is called to evaluate whether the condition is true: if ("if".equals(localName) && optimizeIf == 0 && !suspendOptimizeIf) { try { String value = attributes.getValue("test"); value = expandAVT(value, true, currentElement); JDOMXPath path = new JDOMXPath(value); path.setFunctionContext(xPathFunctions); boolean ok = path.booleanValueOf(currentElement); ... The variable "value" contains the String: "form('campaignClone.uid') and form('orderClone.state') = '1'" xPathFunctions is an Instance of XPathFunctions, a subclass of FunctionContext. xPathFunctions defines how the condition is interpreted. form('orderClone.state') calls getOrderClone.getState and form('campaignClone.uid') calls getCampaignClone.getUid of the corresponding form class. public int getState() { return state; } public Long getUid() { return uid; } This condition is always false with the new version of Jaxen, because getState is an Integer and getUid is a Long value We had to patch the NumberFunction so we could use Jaxen as usual. Here is the code. public static Double evaluate(Object obj, Navigator nav) { if (obj instanceof Double) { return (Double) obj; } else if (obj instanceof Number) { return ((Number) obj).doubleValue(); } else if (obj instanceof String) { String str = (String) obj; try { Double doubleValue = new Double(str); return doubleValue; } catch (NumberFormatException e) { return NaN; } } else if (obj instanceof List || obj instanceof Iterator) { return evaluate(StringFunction.evaluate(obj, nav), nav); } else if (nav.isElement(obj) || nav.isAttribute(obj)) { return evaluate(StringFunction.evaluate(obj, nav), nav); } else if (obj instanceof Boolean) { if (obj == Boolean.TRUE) { return new Double(1); } else { return new Double(0); } } return NaN; } I think that this problem is a bug, because a Not a Number Exception for an Integer value is an unexpected behavior of a class called “NumberFunction”. A number function is expected to work with all kinds of numbers, especially integer and not only double and String. Otherwise it could be called “DoubleFunction”. This class indeed worked that way in the former version. When only doubles are used internally, other kind of numbers should be accepted and casted the same way it is done with Strings It would be good when this issue would be solved, so we won't have to patch the class after every update of Jaxen.
        Hide
        Elliotte Rusty Harold added a comment -

        I think the problem is how you've written your external function. Int is not an acceptable return value for call in the Function interface. Only four types are allowed here: Double, String, Boolean, and List. If this worked in previous versions, then that was incorrect. If you change your Function implementation so call() returns a Double, all should be fine. This has been true since at least 1.1.0. It looks like something we tightened up in moving from 1.0 to 1.1.

        You need to understand "Number" as a number defined in the XPath 1.0 specification, not as a number as defined in Java.

        Show
        Elliotte Rusty Harold added a comment - I think the problem is how you've written your external function. Int is not an acceptable return value for call in the Function interface. Only four types are allowed here: Double, String, Boolean, and List. If this worked in previous versions, then that was incorrect. If you change your Function implementation so call() returns a Double, all should be fine. This has been true since at least 1.1.0. It looks like something we tightened up in moving from 1.0 to 1.1. You need to understand "Number" as a number defined in the XPath 1.0 specification, not as a number as defined in Java.
        Hide
        Andreas Konnikov added a comment - - edited

        Thank you for your reply. Unfortunately it would be very difficult for us to update our code, because the library is used on our main Framework and therefore a lot of methods have to be changed.
        The changes in Jaxen would be very small as I wrote in the former message. The NumberFunction in Jaxen 1.0 accepted a Java Number value. I can imagine that a general Number can cause problems, but integer can always be converted into a double value without any loss of information or could there be any negative consequences?

        Show
        Andreas Konnikov added a comment - - edited Thank you for your reply. Unfortunately it would be very difficult for us to update our code, because the library is used on our main Framework and therefore a lot of methods have to be changed. The changes in Jaxen would be very small as I wrote in the former message. The NumberFunction in Jaxen 1.0 accepted a Java Number value. I can imagine that a general Number can cause problems, but integer can always be converted into a double value without any loss of information or could there be any negative consequences?

          People

          • Assignee:
            Elliotte Rusty Harold
            Reporter:
            Andreas Konnikov
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Time Tracking

              Estimated:
              Original Estimate - 10 minutes
              10m
              Remaining:
              Remaining Estimate - 10 minutes
              10m
              Logged:
              Time Spent - Not Specified
              Not Specified