Struts 2
  1. Struts 2
  2. WW-2176

In Turkish locale "TR" double values are multiplied by ten on every page load

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Critical Critical
    • Resolution: Duplicate
    • Affects Version/s: 2.0.0, 2.0.1, 2.0.2, 2.0.3, 2.0.4, 2.0.5, 2.0.6, 2.0.7, 2.0.8, 2.0.9, 2.1.0
    • Fix Version/s: 2.1.8
    • Component/s: None
    • Labels:
      None
    • Environment:

      Windows XP, java 5 and java 6

      Description

      The steps to get the error.

      1 - Change your locale to "TR" (Turkish)
      2 - go to edit employee page on showcase application - http://www.planetstruts.org/struts2-showcase/employee/save.action
      3 - Fill only the salary field with "10"
      4 - Press Save, it shows the required fields and makes the salary field "10.0"
      5 - Press Save again without editing anything, it gives the error for required fields and makes the salary field "100.0"
      6 - Alter the salary field. Make it "100,0" (change dot with comma)
      7 - press save, here it is not multiplied by 10, but it changes the salary field value from "100,0" to "100.0" again.

      Here is the problem. In Turkish(TR) locale the decimal separator is "comma", not "dot". So it doesn't convert them according to the TR locale which is the locale of my browser. When I press save at the 4th and 5th steps it should write "10,0" using the locale of the browser.

      Note : When I change my locale to "EN" everything works fine.

        Issue Links

          Activity

          Hide
          Ömer Başar added a comment -

          Here is the video file giving this error

          Show
          Ömer Başar added a comment - Here is the video file giving this error
          Hide
          Amaury Crickx added a comment -

          Same is true for quite a few other European locales (French, Danish, ...)

          Due to some nasty feature of the java platform, parsing 10,0 with English locale succeeds with a value of 100.
          So what we have here is when your locale has '.' as thousand separator, your number becomes 100.
          The real problem is actually that the number is not formatted back to string using your locale.

          This issue is related to known issues in xwork :
          http://jira.opensymphony.com/browse/XW-490 : XWorkBasicConverter.doConvertToString(...) ignores Locale for instances of Number
          http://jira.opensymphony.com/browse/XW-543 : XWorkBasicConverter broken with primitives

          XW-490 comments state it clear : locale is used when parsing from String to Float or Double objects (not primitives) but NOT when formatting from Double/Float to String
          Fixing the problem brought nasty side effect like url params being formatted with the thousand separator : ?id=1,234 instead of ?id=1234
          Bringing locale specific formatting into bookmarkable urls is IMHO not a good idea.
          This bug has been rescheduled to xwork 2.1 with a possible outcome of won't fix , let the view handle this.
          Personally, I'd say that parsing using locale and formatting without is not an intuitive behavior either.
          Actually, it will be difficult to document without giving a feeling of code smell

          I also mentioned issue XW-543 because it appears that for the moment primitive numbers are not parsed using the same code in XWorkBasicConverter but rather delegated to OGNL which doesn't handle locale at all...

          Back to this bug : there is a way to fix this, but I wouldn't call it elegant.

          In the showCase app, there is a resource bundle called globalMessages.properties where the following line should be added
          (no need to add it to all locales : I don't add text and the formatting will use the current locale):
          number=

          {0,number}

          Then modify editEmployee.jsp and replace the line
          <s:textfield label="Salary" name="currentEmployee.salary"/>

          with

          <s:text name="number" var="formattedSalary"><s:param value="currentEmployee.salary"/></s:text>
          <s:textfield label="Salary" name="currentEmployee.salary" value="%

          {formattedSalary}

          "/>

          Note that depending on your version you may have to use "id" instead of "var" as text tag attribute.
          Which basically means:

          1. get the salary Float object from current employee and have it added to a List of arguments,
          search resource bundles to find the key 'number',
          parse the given message value and replace parameters with converted/formatted value
          push result to formattedSalary on the stack

          2. when displaying textfield, use the stack value.

          It works but... I wished I could specify a formatter directly into the textfield tag or have a FormattedTextField tag (à la Swing) or ... anything that could ease the pain of localized numbers
          I'm wishing to help if I can...

          Show
          Amaury Crickx added a comment - Same is true for quite a few other European locales (French, Danish, ...) Due to some nasty feature of the java platform, parsing 10,0 with English locale succeeds with a value of 100. So what we have here is when your locale has '.' as thousand separator, your number becomes 100. The real problem is actually that the number is not formatted back to string using your locale. This issue is related to known issues in xwork : http://jira.opensymphony.com/browse/XW-490 : XWorkBasicConverter.doConvertToString(...) ignores Locale for instances of Number http://jira.opensymphony.com/browse/XW-543 : XWorkBasicConverter broken with primitives XW-490 comments state it clear : locale is used when parsing from String to Float or Double objects (not primitives) but NOT when formatting from Double/Float to String Fixing the problem brought nasty side effect like url params being formatted with the thousand separator : ?id=1,234 instead of ?id=1234 Bringing locale specific formatting into bookmarkable urls is IMHO not a good idea. This bug has been rescheduled to xwork 2.1 with a possible outcome of won't fix , let the view handle this. Personally, I'd say that parsing using locale and formatting without is not an intuitive behavior either. Actually, it will be difficult to document without giving a feeling of code smell I also mentioned issue XW-543 because it appears that for the moment primitive numbers are not parsed using the same code in XWorkBasicConverter but rather delegated to OGNL which doesn't handle locale at all... Back to this bug : there is a way to fix this, but I wouldn't call it elegant. In the showCase app, there is a resource bundle called globalMessages.properties where the following line should be added (no need to add it to all locales : I don't add text and the formatting will use the current locale): number= {0,number} Then modify editEmployee.jsp and replace the line <s:textfield label="Salary" name="currentEmployee.salary"/> with <s:text name="number" var="formattedSalary"><s:param value="currentEmployee.salary"/></s:text> <s:textfield label="Salary" name="currentEmployee.salary" value="% {formattedSalary} "/> Note that depending on your version you may have to use "id" instead of "var" as text tag attribute. Which basically means: 1. get the salary Float object from current employee and have it added to a List of arguments, search resource bundles to find the key 'number', parse the given message value and replace parameters with converted/formatted value push result to formattedSalary on the stack 2. when displaying textfield, use the stack value. It works but... I wished I could specify a formatter directly into the textfield tag or have a FormattedTextField tag (à la Swing) or ... anything that could ease the pain of localized numbers I'm wishing to help if I can...
          Hide
          Jørgen Larsen added a comment -

          Norwegians are having the same experience.

          I don't think the above solution will work for <s:selects, so my fix on this problem was to add an helper method in my BaseAction (all other actions extends this action).
          I.e for doubles I added BaseAction.formatDouble method that uses the default locale. So my <s:select ended up like this:

          <s:select
          tooltip="Choose discount"
          label="Discount"
          list="contractDiscounts"
          name="contract.discountFactor"
          listKey="formatDouble(discountFactor)"
          listValue="description"
          emptyOption="false"
          headerKey="-1"
          headerValue="-- No discount --"/>

          This seems to solve my problem regarding doubles and dates "roundtrip" from object to form and back again

          Show
          Jørgen Larsen added a comment - Norwegians are having the same experience. I don't think the above solution will work for <s:selects, so my fix on this problem was to add an helper method in my BaseAction (all other actions extends this action). I.e for doubles I added BaseAction.formatDouble method that uses the default locale. So my <s:select ended up like this: <s:select tooltip="Choose discount" label="Discount" list="contractDiscounts" name="contract.discountFactor" listKey="formatDouble(discountFactor)" listValue="description" emptyOption="false" headerKey="-1" headerValue="-- No discount --"/> This seems to solve my problem regarding doubles and dates "roundtrip" from object to form and back again
          Hide
          Amaury Crickx added a comment -

          Yes, you're right.

          But I'd like to mention I went down the road of adding methods to my base action and found my class bloated with all kinds of things that really didn't belong there...
          IMHO, OGNL is really great but can bring bad habits...

          When the business requirements changed and changed again while the presentation still had to remain approximatively the same and I realized I should really have used some kind of presentation model specific to my web app. So I refactored it out injecting the locale into that view model and suddenly these view objects became the perfect place to place for the required formatting (Sometimes using static helper methods in a common util class).

          I also use specific form classes when it comes to updating the model.

          This brings lots of boiler plate code (get/set mostly delegating to the wrapped object for the views, form class hierarchy/relationships that often mimics the business model hierarchy/relationships)
          But in the end the flexibility gained is well worth the price.

          In the end, nothing really astonishing I think: I just placed my presentation logic into my presentation model instead of the controller.

          Yet: I'd say IMHO parsing using locale and formatting without is not an intuitive behavior for a framework like Struts.

          Show
          Amaury Crickx added a comment - Yes, you're right. But I'd like to mention I went down the road of adding methods to my base action and found my class bloated with all kinds of things that really didn't belong there... IMHO, OGNL is really great but can bring bad habits... When the business requirements changed and changed again while the presentation still had to remain approximatively the same and I realized I should really have used some kind of presentation model specific to my web app. So I refactored it out injecting the locale into that view model and suddenly these view objects became the perfect place to place for the required formatting (Sometimes using static helper methods in a common util class). I also use specific form classes when it comes to updating the model. This brings lots of boiler plate code (get/set mostly delegating to the wrapped object for the views, form class hierarchy/relationships that often mimics the business model hierarchy/relationships) But in the end the flexibility gained is well worth the price. In the end, nothing really astonishing I think: I just placed my presentation logic into my presentation model instead of the controller. Yet: I'd say IMHO parsing using locale and formatting without is not an intuitive behavior for a framework like Struts.
          Hide
          Gleison Caetano added a comment - - edited

          We should to turn in pattern inside entity or inside action for example down. I solved this problem like this:

          1) in entity:
          ...
          public Double getVlCust()

          { return vlCust; }

          public String getVlCustFormatted()

          { return Utils.convertDoubleToString(vlCust); }

          ...

          2) in some class util like Utils:
          ...
          public static String convertDoubleToString(Double value)

          { return (String) new CurrencyConverter().convert(String.class, value); }

          ...

          3) in jsp form:
          <s:textfield key="produto.vlCust" value="%

          {produto.vlCustFormatted}

          " required="false" cssClass="text medium"/>

          4) in jsp list:
          <display:column property="vlCustFormatted" sortable="true" titleKey="produto.vlCust"/>

          Show
          Gleison Caetano added a comment - - edited We should to turn in pattern inside entity or inside action for example down. I solved this problem like this: 1) in entity: ... public Double getVlCust() { return vlCust; } public String getVlCustFormatted() { return Utils.convertDoubleToString(vlCust); } ... 2) in some class util like Utils: ... public static String convertDoubleToString(Double value) { return (String) new CurrencyConverter().convert(String.class, value); } ... 3) in jsp form: <s:textfield key="produto.vlCust" value="% {produto.vlCustFormatted} " required="false" cssClass="text medium"/> 4) in jsp list: <display:column property="vlCustFormatted" sortable="true" titleKey="produto.vlCust"/>
          Hide
          Sebastian Mittelstädt added a comment -

          I am writing a German localized application and encountered the same issue. I took me unneccssary hours of time to localize the problem and fix it with a workaround (thanks, Amaury, now I also use the text input tag).

          I agree that parsing using locale and formatting without is not an intuitive behavior and is bad design.

          Show
          Sebastian Mittelstädt added a comment - I am writing a German localized application and encountered the same issue. I took me unneccssary hours of time to localize the problem and fix it with a workaround (thanks, Amaury, now I also use the text input tag). I agree that parsing using locale and formatting without is not an intuitive behavior and is bad design.
          Hide
          Don Brown added a comment -

          I agree this is a serious XWork issue and when I last talked to Rainer, he planned to overhaul this area to fix the root issues.

          Show
          Don Brown added a comment - I agree this is a serious XWork issue and when I last talked to Rainer, he planned to overhaul this area to fix the root issues.
          Hide
          Rene Gielen added a comment -

          The first part of the original issue description is fixed by WW-3028

          Show
          Rene Gielen added a comment - The first part of the original issue description is fixed by WW-3028
          Hide
          Rene Gielen added a comment -

          The second part of the original issue description is fixed by WW-3027

          Show
          Rene Gielen added a comment - The second part of the original issue description is fixed by WW-3027
          Hide
          Rene Gielen added a comment -

          Fixed by WW-3027 and WW-3028.

          Nevertheless, we have to think about handier solutions

          Show
          Rene Gielen added a comment - Fixed by WW-3027 and WW-3028 . Nevertheless, we have to think about handier solutions
          Hide
          Erhan Aşıkoğlu added a comment -

          I faced the same problem. Convert from primitive wrapper (Double) to primitive type (double) in holder bean works for my case.

          Show
          Erhan Aşıkoğlu added a comment - I faced the same problem. Convert from primitive wrapper (Double) to primitive type (double) in holder bean works for my case.

            People

            • Assignee:
              Rene Gielen
              Reporter:
              Ömer Başar
            • Votes:
              1 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development