sokie
sokie

Reputation: 1986

vaadin form float field

I have a vaadin application that has a form,and i use a beanitem as a data source. Inside the beanitem i have a float value that defaults to 0.0.. If i enter a high value like 123123123 and commit(it saves to a db),when i try to edit that field inside the form i get 1.23123123E9 as a value,why? When i edit i still pass the beanitem with the data in it,why doesn't it show my value correctly inside the textfield?

I know if i must display the value i can use decimal format but this is inside the form,and vaadin knows it is a float,so it should handle it accordingly right? Or must i format it inside the form field factory myself?

PS:How can you set a display mode for the values inside the form?I have read you could implement the get of the field inside the bean and have it return a string too,is that the right way to do it?

Upvotes: 2

Views: 3157

Answers (2)

Renat Gilmanov
Renat Gilmanov

Reputation: 17895

Actually Vaadin behaves correctly, but it follows the magnitude rules (already mentioned by Yogendra Singh) please see an example

enter image description here

Please also check the following:

    float value1 = 12.0f;
    float value2 = 123123123;

    BeanItem<Float> item1 = new BeanItem<Float>(value1);
    BeanItem<Float> item2 = new BeanItem<Float>(value2);

    System.out.println(" result 1: " + item1.getBean());
    System.out.println(" result 2: " + item2.getBean());

Result:

result 1: 12.0
result 2: 1.2312312E8

So the correct solution (as I can see it) looks like the following:

  1. Define your own Bean. There is no reason to have a BeanItem wrapping a float value.
  2. Define your PropertyFormatter (example)
  3. Important to note, the one should not return a String instead of the correct data type. It will affect editing, validation, etc.

PropertyFormatter example:

/** Integer formatter that accepts empty values. */
public class LenientIntegerFormatter extends PropertyFormatter {

    public LenientIntegerFormatter(Property propertyDataSource) {
        setPropertyDataSource(propertyDataSource);
    }

    @Override
    public Object parse(String formattedValue) throws Exception {
        if ("".equals(formattedValue))
            return null;
        else
        return Integer.valueOf(formattedValue);
    }

    @Override
    public String format(Object value) {
        if (value == null)
            return "";

        return ((Integer) value).toString();
    }

    @Override
    public Class<?> getType() {
        return String.class;
    }
}

It may look a little bit scary, but this is the cost of flexibility. Custom Bean allows to use table view, forms, etc without any significant changes. Basically, this is the data model behind Vaadin UI.

enter image description here

Chapter 9. Binding Components to Data

Custom Bean example:

public class Bean implements Serializable {
    String name;
    float value;

    public Bean(String name, float newValue) {
        this.name   = name;
        this.value = newValue;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public float getValue() {
        return value;
    }

    public void setValue(float newValue) {
        this.value = newValue;
    }
}

Just to provide all required insights:

 Bean bean = new Bean("Test", value1);
    BeanItem<Bean> beanItem = new BeanItem<Bean>(bean);
    for(Object propertyId: beanItem.getItemPropertyIds()) {
        System.out.println(" Property: '" + propertyId + 
                           "' value: " + beanItem.getItemProperty(propertyId));
    }

Will print:

Property: 'name' value: Test
Property: 'value' value: 12.0

Upvotes: 6

Yogendra Singh
Yogendra Singh

Reputation: 34367

toString() internally calls toString(float) This is what the documentation says for toString(float)

Otherwise, the result is a string that represents the sign and magnitude (absolute value) of the argument. If the sign is negative, the first character of the result is '-' ('\u002D'); if the sign is positive, no sign character appears in the result. As for the magnitude m:

  • If m is greater than or equal to 10-3 but less than 107, then it is represented as the integer part of m, in decimal form with no leading zeroes, followed by '.' ('\u002E'), followed by one or more decimal digits representing the fractional part of m.

  • If m is less than 10-3 or greater than or equal to 107, ** Let n be the unique integer such that 10n ≤ m < 10n+1; then let a be the mathematically exact quotient of m and 10n so that 1 ≤ a < 10. The magnitude is then represented as the integer part of a, as a single decimal digit, followed by '.' ('\u002E'), followed by decimal digits representing the fractional part of a, followed by the letter 'E' ('\u0045'), followed by a representation of n as a decimal integer, as produced by the method Integer.toString(int).

To create localized string representations of a floating-point value, use subclasses of NumberFormat.

Hope this helps you understand WHY and HOW to fix it i.e. use DecimalFormat as you have mentioned inside your field factory and return as string representation for display purpose.

Upvotes: 1

Related Questions