Grails databinding with decimal delimiter

前端 未结 3 2043
孤城傲影
孤城傲影 2020-12-31 13:30

I have a problem when I use grail automatic databinding \"ex: Test t = new Test(params)\" with decimal delimiter on Double form field. After few search, I\'ve found that it

相关标签:
3条回答
  • 2020-12-31 13:36

    I have the same problem here. For example a user in Germany will usually enter a , (comma) as a decimal separator but obviously you cannot prevent him from entering a dot instead ;) Also if you fill the value from Javascript it's quite difficult to get a localized number. So I wrote this small helper method for the controller. It might not cover all possible scenarios, but I need it for entering GPS coordinates. Feel free to suggest improvements.

        /**
         * Replaces , in the param with . an converts it to a Double.
         * @param paramName an array of paramater names
         */
        private convertDicimalParamsToDouble(paramName) {
            paramName.each { it
                def val = params[it]
                if(val) {
                    val = val.replace(",", ".")
                    try {
                        params[it] = Double.parseDouble(val)
                    } catch (NumberFormatException) {
                        //ignore
                    }
                    log.debug("Converted decimal param ${it} with value '${params[it]}' to new value '${val}'")
                }
            }
        }
    

    Then call it like this for example:

    def save() {        
        convertDicimalParamsToDouble(["lat", "lng"])
        ...
    
    0 讨论(0)
  • 2020-12-31 13:50

    I've been searching and trying for 2 days. I've finally chosen to define a custom PropertyEditorRegistar. This way, I can fix the Locale only for the Double field format. However, I don't think that it's the best solution because it will be applied to all my Double fields. But in the mean time it does the job pretty well. So if someone have a better solution, I will be glad to test it and update my code.

    So this is how I set this up :

    1 - Create a new groovy class that implements PropertyEditorRegistrar (if you already have one, just add the part of code contained by the method in the existing one)

    import java.text.DecimalFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import org.springframework.beans.PropertyEditorRegistrar;
    import org.springframework.beans.PropertyEditorRegistry;
    import org.springframework.beans.propertyeditors.CustomNumberEditor;
    
    public class CustomDoubleRegistrar implements PropertyEditorRegistrar {
    
        @Override
        public void registerCustomEditors(PropertyEditorRegistry registry) {
                //define new Double format with hardcoded Locale.ENGLISH
            registry.registerCustomEditor(Double.class, 
                     new CustomNumberEditor(Double.class, 
                               DecimalFormat.getInstance(Locale.ENGLISH),true))
        }
    
    }
    

    2- Define the custom registrar into the conf/spring/resources.goovy (if it's not already there of course)

    beans = {
        customPropertyEditorRegistrar(CustomDoubleRegistrar)
    }
    

    3- That's it, the Grails auto data binding will work fine

    Test t = new Test(params); 
    //params contains many Double fields with dot '.' as decimal delimiter
    

    Don't hesitate to post better solutions... Thanks

    EDIT 1

    Since Grails 2.3 this solution is no longer working. If you still want to use this solution, you have to add this configuration to the Config.groovy file

    grails.databinding.useSpringBinder = true

    Or implement one of the new DataBinding. I've tried few of them but nothing seems to solve the decimal delimiter issue. Thank you to post answer if you know how...

    EDIT 2

    Since Grails 2.4+ you can define your own ValueConverter to bypass the basic Locale validation. Note that you must remove the changes made in the initial post and in the EDIT 1. Here's how to implement the custom ValueConverter:

    conf/spring/resources.groovy

    // Place your Spring DSL code here
    beans = {
        "defaultGrailsjava.lang.DoubleConverter"(DoubleValueConverter)
    }
    
    class DoubleValueConverter implements ValueConverter {
    
        public LongValueConverter() {
        }
    
        boolean canConvert(value) {
            value instanceof Double
        }
    
        def convert(value) {
            //In my case returning the same value did the trick but you can define 
            //custom code that takes care about comma and point delimiter...
            return value
        }
    
        Class<?> getTargetType() {
            return Double.class
        }
    }
    
    0 讨论(0)
  • 2020-12-31 13:59

    For Grails 2.3+ you can properly override the default binder/converter, although it is not trivial or intuitive.

    See my answer here: Binding real number values to Grails domain attributes (values sent by Dojo widgets)

    0 讨论(0)
提交回复
热议问题