Spring CustomNumberEditor parses numbers that are not numbers
Asked Answered
M

3

5

I'm using Spring CustomNumberEditor editor to bind my float values and I've experimented that if in the value is not a number sometimes it can parse the value and no error is returned.

  • number=10 ...... then the number is 10 and there's no errors
  • number=10a ...... then the number is 10 and there's no errors
  • number=10a25 ...... then the number is 10 and there's no errors
  • number=a ...... error because the number is not valid

So it seems that the editor parses the value until it can and omit the rest. Is there any way to configure this editor so the validation is strict (so numbers like 10a or 10a25 result in error) or do I have to build my custom implementation. I'm looking something like setting lenient to false in CustomDateEditor/DateFormat so dates cannot be parsed to the most probable one.

The way I register the editor is:

@InitBinder
public void initBinder(WebDataBinder binder){
    NumberFormat numberFormat = NumberFormat.getInstance();
    numberFormat.setGroupingUsed(false);
    binder.registerCustomEditor(Float.class, new CustomNumberEditor(Float.class, numberFormat, true));
}

Thanks.

Mcclean answered 18/1, 2011 at 17:9 Comment(0)
M
4

Since it relies on the NumberFormat class, which stops parsing the input string at the first invalid character I think you'll have to extend the NumberFormat class.

First blush would be

public class StrictFloatNumberFormat extends NumberFormat {

  private void validate(in) throws ParseException{
     try {
       new Float(in);
     }
     catch (NumberFormatException nfe) {
       throw new ParseException(nfe.getMessage(), 0);     
  }


  public Number parse(String in) throws ParseException {
    validate(in);
    super.parse(in);
  }
  ..... //any other methods
}
Mogerly answered 18/1, 2011 at 17:48 Comment(1)
Thanks. But if I have make my custom implementation I think that I can extend CustomNumberEditor class and override setAsText method checking if the value is a number as you do and if it is going on with super.setAsTextMcclean
B
7

You can not do this whith NumberFormat.

The documentation is clear about this fact:

/**
 * Parses text from the beginning of the given string to produce a number.
 * The method may not use the entire text of the given string.
 * <p>
 * See the {@link #parse(String, ParsePosition)} method for more information
 * on number parsing.
 *
 * @param source A <code>String</code> whose beginning should be parsed.
 * @return A <code>Number</code> parsed from the string.
 * @exception ParseException if the beginning of the specified string
 *            cannot be parsed.
 */
public Number parse(String source) throws ParseException {

When you acceept this API it would even be even invalid to write a parser that does what you want and implement the NumberFormat interface. This mean you have to implment your own Property Editor instead.

/* untested */
public class StrictNumberPropertyEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
       super.setValue(Float.parseFloat(text));
    }

    @Override
    public String getAsText() {
        return ((Number)this.getValue()).toString();
    }    
}
Beastly answered 18/1, 2011 at 18:18 Comment(0)
M
4

Since it relies on the NumberFormat class, which stops parsing the input string at the first invalid character I think you'll have to extend the NumberFormat class.

First blush would be

public class StrictFloatNumberFormat extends NumberFormat {

  private void validate(in) throws ParseException{
     try {
       new Float(in);
     }
     catch (NumberFormatException nfe) {
       throw new ParseException(nfe.getMessage(), 0);     
  }


  public Number parse(String in) throws ParseException {
    validate(in);
    super.parse(in);
  }
  ..... //any other methods
}
Mogerly answered 18/1, 2011 at 17:48 Comment(1)
Thanks. But if I have make my custom implementation I think that I can extend CustomNumberEditor class and override setAsText method checking if the value is a number as you do and if it is going on with super.setAsTextMcclean
M
3

I think the most elegant approach would be to use NumberFormat.parse(String,ParsePosition), something like this:

public class MyNumberEditor extends PropertyEditorSupport {
    private NumberFormat f;
    public MyNumberEditor(NumberFormat f) {
        this.f = f;
    }

    public void setAsText(String s) throws IllegalArgumentException {
        String t = s.trim();
        try {
            ParsePosition pp = new ParsePosition(0);
            Number n = f.parse(t, pp);
            if (pp.getIndex() != t.length()) throw new IllegalArgumentException();
            setValue((Float) n.floatValue());
        } catch (ParseException ex) {
            throw new IllegalArgumentException(ex);
        }
    }

    ...
}
Monti answered 18/1, 2011 at 18:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.