Problem with PropertyFormatter

I have created a PropertyFormatter for formatting currency strings in textfields. The idea is that a double should be shown with at least two decimals, and then the currency code should be added (example: 3.95 EUR).

Now I have a form where I wish to use the formatter on some textfields, and I add it in a FormFieldFactory in the createField() method:


public Field createField(Item item, Object propertyId, Component uiContext) {
    Field created = null;
    String pid = (String) propertyId;
    if (pid.equals("internationalRate")) {
        created = new TextField("Voice");
    }
    if (created instanceof TextField) {
        created.setPropertyDataSource(new CurrencyFormatter(created.getPropertyDataSource(), "#0.00 ", currency));
    }
    return created;
}

Now my problem is that the value I get in CurrencyFormatter.format() always is a boolean. I just can’t se why this is happening. The result though is my textfield with the value shown, but as if the property formatter was not called.
Can anyone tell me what is wrong with my code?

The FormFieldFactory.parse() is never called.


Thomas

import com.vaadin.data.Property;
import com.vaadin.data.util.PropertyFormatter;

import java.text.DecimalFormat;

class CurrencyFormatter extends PropertyFormatter {
    private final DecimalFormat currencyFormatter;
    private final String currency;

    public CurrencyFormatter(Property propertyDataSource, String formatString, String currency) {
        super();
        this.currency = currency;

        currencyFormatter = new DecimalFormat(formatString);
        setPropertyDataSource(propertyDataSource);
    }

    @Override
    public String format(Object value) {
        try {
            return currencyFormatter.format(value);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        return value.toString();
    }

    @Override
    public Object parse(String formattedValue) throws Exception {
        String c;
        if (formattedValue.contains(currency)) {
            c = formattedValue.substring(0, formattedValue.indexOf(currency));
            formattedValue = c;
        }
        return Double.parseDouble(formattedValue);
    }
}

Ok, now I got it working, but not as I would like.
It appeared that PropertyFormatter’s dataSource was null, because at the time when I created the TextField in the FormFieldFactory.createField() the propertyDataSource was not set yet.
Instead if I set the porpertyDataSource after the createField method has been called I do not have the problem and the formatter works as expected.

    addCountryRatesForm.setFormFieldFactory(new MyFormFieldFactory());
    Field internationalRate = addCountryRatesForm.getField("internationalRate");
    internationalRate.setPropertyDataSource(new CurrencyFormatter("#0.00 ", currency, internationalRate.getPropertyDataSource()));

I would have liked that I could make a CurrencyTextField that sets its own PropertyFormatter, so I just would have to use that in my FormFieldFactory, but that gives the same problem as with the null propertyDataSource. Does anyone see a workaround for this?


Thomas

Thats due to the following code in Form.setItemDataSource(Item newDataSource, Collection<?> propertyIds):


            final Property property = itemDatasource.getItemProperty(id);
            if (id != null && property != null) {
                final Field f = fieldFactory.createField(itemDatasource, id,
                        this);
                if (f != null) {
                    f.setPropertyDataSource(property);
                    addField(id, f);
                }
            }

Which really is a confusing since normally you would like to set the PropertyDataSource while creating the field in the createField method. But this will get replaced in the inner if by the old property.

The whole DataBinding with validation and convertion looks a bit confusing. Adding a formatter by overriding the property looks like a dirty hack to me since you will need a formatter instance per property.

I might suggest to take a look at other DataBinding solutions like JFace DataBinding.

greetings