Struts 2
  1. Struts 2
  2. WW-2971

type conversion cannot convert negative numbers to Double

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.1.6
    • Fix Version/s: 2.1.8
    • Component/s: Expression Language
    • Labels:
      None
    • Environment:

      Struts 2.1.6, 2.1.6 Conventions plugin

      Description

      Replicate via the following:

      1. create an action with a Double property
      2. post to the action with a negative number for that property
      3. exception stack trace similar to the following will appear, where LongitudeLatitudeBox has a Double maximumLongitude property :

      expr: longitudeLatitudeBox.maximumLongitude val: [Ljava.lang.String;@bf2f7c context: ognl.OgnlContext@39042078 root:[org.tdar.struts.action.DatasetController@13072d, com.opensymphony.xwork2.DefaultTextProvider@17fd168] value: [Ljava.lang.String;@bf2f7c
      ognl.MethodFailedException: Method "setMinimumLongitude" failed for object org.tdar.core.bean.coverage.LongitudeLatitudeBox@299813 [java.lang.NoSuchMethodException: setMinimumLongitude([Ljava.lang.String;)]
      at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:823)
      at ognl.OgnlRuntime.setMethodValue(OgnlRuntime.java:964)
      at ognl.ObjectPropertyAccessor.setPossibleProperty(ObjectPropertyAccessor.java:75)
      at ognl.ObjectPropertyAccessor.setProperty(ObjectPropertyAccessor.java:131)
      at com.opensymphony.xwork2.ognl.accessor.ObjectAccessor.setProperty(ObjectAccessor.java:28)
      at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:1656)
      at ognl.ASTProperty.setValueBody(ASTProperty.java:101)
      at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:177)
      at ognl.SimpleNode.setValue(SimpleNode.java:246)
      at ognl.ASTChain.setValueBody(ASTChain.java:172)
      at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:177)
      at ognl.SimpleNode.setValue(SimpleNode.java:246)
      at ognl.Ognl.setValue(Ognl.java:476)
      at com.opensymphony.xwork2.ognl.OgnlUtil.setValue(OgnlUtil.java:192)
      at com.opensymphony.xwork2.ognl.OgnlValueStack.setValue(OgnlValueStack.java:155)
      at com.opensymphony.xwork2.ognl.OgnlValueStack.setValue(OgnlValueStack.java:143)
      at com.opensymphony.xwork2.interceptor.ParametersInterceptor.setParameters(ParametersInterceptor.java:276)
      at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:187)
      at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:195)
      at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:148)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:93)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:235)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:89)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:128)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at org.apache.struts2.interceptor.ProfilingActivationInterceptor.intercept(ProfilingActivationInterceptor.java:104)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:267)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:126)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:138)
      at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:148)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:128)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
      at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:176)

        Activity

        Hide
        Allen Lee added a comment -

        Sample Struts 2 project, post negative double to IndexAction to generate OGNL type conversion failure.

        Show
        Allen Lee added a comment - Sample Struts 2 project, post negative double to IndexAction to generate OGNL type conversion failure.
        Hide
        Travis Newby added a comment - - edited

        The issue is caused by the isInRange method of the XWorkBasicConverter using (Double | Float).MIN_VALUE. These constants normally return the smallest POSITIVE value, rather than the most negative value as seems to be the intent.

        Show
        Travis Newby added a comment - - edited The issue is caused by the isInRange method of the XWorkBasicConverter using (Double | Float).MIN_VALUE. These constants normally return the smallest POSITIVE value, rather than the most negative value as seems to be the intent.
        Hide
        Philip Luppens added a comment -

        Wow - I never noticed that .. talk about poor naming ! .. How on earth did this get unnoticed for so long?

        Show
        Philip Luppens added a comment - Wow - I never noticed that .. talk about poor naming ! .. How on earth did this get unnoticed for so long?
        Hide
        Travis Newby added a comment - - edited

        I'm not sure. The semantics get a bit strange when talking about min and max values for floating point numbers. Unlike integers that - when you fill up your allotted number of bits - you've reached a min or a max, with floating points you can fill up your bits by representing lots of numbers that are nowhere near the min or max. However, a pedantic discussion about those semantics doesn't help Mr. Lee.

        As a temporary patch, you can modify the first two if's in the isInRange method to something like...

        if (double.class == toType || Double.class == toType)

        { bigValue = new BigDecimal(stringValue); lowerBound = BigDecimal.valueOf(-Double.MAX_VALUE); upperBound = BigDecimal.valueOf(Double.MAX_VALUE); }

        else if (float.class == toType || Float.class == toType)

        { bigValue = new BigDecimal(stringValue); lowerBound = BigDecimal.valueOf(-Float.MAX_VALUE); upperBound = BigDecimal.valueOf(Float.MAX_VALUE); }

        That may or may not be a good long term solution; I must admit that I didn't go looking through the IEEE spec to see what the true "most negative" legal double is. Additionally - and in the long run - the class needs to be refactored because it's a bit sloppy. Perhaps having converters for all the basic types and using the chain of responsibility pattern would clean things up a bit?

        Show
        Travis Newby added a comment - - edited I'm not sure. The semantics get a bit strange when talking about min and max values for floating point numbers. Unlike integers that - when you fill up your allotted number of bits - you've reached a min or a max, with floating points you can fill up your bits by representing lots of numbers that are nowhere near the min or max. However, a pedantic discussion about those semantics doesn't help Mr. Lee. As a temporary patch, you can modify the first two if's in the isInRange method to something like... if (double.class == toType || Double.class == toType) { bigValue = new BigDecimal(stringValue); lowerBound = BigDecimal.valueOf(-Double.MAX_VALUE); upperBound = BigDecimal.valueOf(Double.MAX_VALUE); } else if (float.class == toType || Float.class == toType) { bigValue = new BigDecimal(stringValue); lowerBound = BigDecimal.valueOf(-Float.MAX_VALUE); upperBound = BigDecimal.valueOf(Float.MAX_VALUE); } That may or may not be a good long term solution; I must admit that I didn't go looking through the IEEE spec to see what the true "most negative" legal double is. Additionally - and in the long run - the class needs to be refactored because it's a bit sloppy. Perhaps having converters for all the basic types and using the chain of responsibility pattern would clean things up a bit?
        Hide
        Lukasz Racon added a comment -

        This is xwork converter issue - please check http://jira.opensymphony.com/browse/XW-676

        Show
        Lukasz Racon added a comment - This is xwork converter issue - please check http://jira.opensymphony.com/browse/XW-676
        Hide
        Bob Tiernay added a comment -

        Can someone please confirm that a double/Double value of 0.0 also results in a conversion error? I'm experiencing this from upgrading from 2.0.11 to 2.1.6. I've traced the code to the isInRange method, which fails with an overflow/underflow exception. This should also be a test case.

        Thanks in advance,

        Bob

        Show
        Bob Tiernay added a comment - Can someone please confirm that a double/Double value of 0.0 also results in a conversion error? I'm experiencing this from upgrading from 2.0.11 to 2.1.6. I've traced the code to the isInRange method, which fails with an overflow/underflow exception. This should also be a test case. Thanks in advance, Bob
        Hide
        Dave Newton added a comment -

        IIRC this was fixed in XW trunk.

        Show
        Dave Newton added a comment - IIRC this was fixed in XW trunk.
        Hide
        Wes Wannemacher added a comment -

        This issue is indeed fixed on XWork trunk. Reopen if the problem remains after xwork 2.1.3 is released.

        Show
        Wes Wannemacher added a comment - This issue is indeed fixed on XWork trunk. Reopen if the problem remains after xwork 2.1.3 is released.

          People

          • Assignee:
            Unassigned
            Reporter:
            Allen Lee
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development