Eel Lee
Eel Lee

Reputation: 3543

Grails locale-independent decimal databinding

What is the problem:

In my application, numbers on the front-end are always presented with a , as a decimal separator. The problem with wrong binding occurs when an user changes his locale and edits the entity with ?lang=en_EN parameter. What happens is that with en_EN locale, the decimal separator is . which makes value on the input 11,00, 1100 in the database, instead of 11.00 - critical problem when it comes to money.

Software used:

Grails 2.3.8
Groovy 2.2.1

What I want to do:

In my case the default "locale aware" approach in converters is very problematic, and I want them to be binded always the same way, which should be locale-independent.

What I have already tried:

I found that what makes the job by default is LocaleAwareNumberConverter and more specifically LocaleAwareBigDecimalConverter, so I wrote a simple implementation which simply uses one locale (in this case GERMAN, as it uses , as a decimal separator)

@CompileStatic
class MyBigDecimalConverter extends LocaleAwareNumberConverter {

    @Override
    protected NumberFormat getNumberFormatter() {
        NumberFormat.getInstance(Locale.GERMAN)
    }
}

included it in the resources.groovy:

myBigDecimalConverter com.company.converters.MyBigDecimalConverter

But it just doesn't work. Values are still converted with LocaleAwareBigDecimalConverter.

EDIT:

I've changed my converter to directly implement ValueConverter:

@CompileStatic
class MyBigDecimalConverter implements ValueConverter {

    @Override
    boolean canConvert(Object value) {
        value instanceof String
    }

    @Override
    Object convert(Object value) {
        def numberFormatter = NumberFormat.getInstance(Locale.GERMAN)
        numberFormatter.parse((String)value).asType(getTargetType())
    }

    @Override
    Class<?> getTargetType() {
        BigDecimal
    }
}

And this converter also doesn't get called. I made no changes to the resources.groovy

Upvotes: 4

Views: 919

Answers (1)

wwwclaes
wwwclaes

Reputation: 1152

Ok, I think I got it working now. It is based on my code, but should work for you as well.

To register your own ValueConverter for BigDecimal, you should add defaultGrailsBigDecimalConverter(YourBigDecimalValueConverter) to resources.groovy. I derived that conclusion from DataBindingGrailsPlugin.groovy for Grails 2.3.11.

If you have grails.databinding.useSpringBinder = true in Config.groovy, you need to remove that to enable the new data binding for Grails 2.3.

My ValueConverter is similar to your your second sample that implements it directly, so use that one first to minimize other problems that might occur.

That's all there is to it. I have implemented a ValueConverter that accepts both dot and comma as separator and then presents it according to the user's locale. It is working, the tricky part was figuring out the correct name for resources.groovy and at the same time have the Spring binder disabled.

Upvotes: 5

Related Questions