FieldGroup with "BeanItem with BigDecimal type" throwing exception

Hello, seems i found a bug.

Simply Bean item


    public class BeanBigDecimal implements Serializable {
        BigDecimal decimal;

        public BeanBigDecimal() {

        }

        public BigDecimal getDecimal() {
            return decimal;
        }

        public void setDecimal(BigDecimal decimal) {
            this.decimal = decimal;
        }
    }

Ui and other stuff


 final VerticalLayout layout = new VerticalLayout();

BeanBigDecimal beanBigDecimal = new BeanBigDecimal();
BeanItem<BeanBigDecimal> beanItem = new BeanItem<BeanBigDecimal>(beanBigDecimal);

FormLayout formLayout = new FormLayout();
TextField textField = new TextField();
formLayout.addComponent(textField2);

final FieldGroup fieldGroup = new FieldGroup(beanItem);
fieldGroup.bind(textField,"decimal");

        Button button = new Button();
        button.addClickListener(new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                try {
                    fieldGroup.commit();
                } catch (FieldGroup.CommitException e) {
                    e.printStackTrace();
                }
            }
        });

layout.addComponent(formLayout);
layout.addComponent(button);

On commit we have this exception


[#|2013-02-14T16:20:53.089+0400|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=88;_ThreadName=Thread-2;|com.vaadin.data.fieldgroup.FieldGroup$CommitException: Commit failed
	at com.vaadin.data.fieldgroup.FieldGroup.commit(FieldGroup.java:463)
	at ru.aeinf.cas.casadmin.MyVaadinUI$2.buttonClick(MyVaadinUI.java:125)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:508)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:167)
	at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:984)
	at com.vaadin.ui.Button.fireClick(Button.java:367)
	at com.vaadin.ui.Button$1.click(Button.java:56)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:170)
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:118)
	at com.vaadin.server.AbstractCommunicationManager.handleBurst(AbstractCommunicationManager.java:1678)
	at com.vaadin.server.AbstractCommunicationManager.handleVariables(AbstractCommunicationManager.java:1564)
	at com.vaadin.server.AbstractCommunicationManager.handleUidlRequest(AbstractCommunicationManager.java:582)
	at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:315)
	at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:201)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1542)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
	at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849)
	at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:746)
	at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1045)
	at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:228)
	at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
	at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
	at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
	at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
	at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
	at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:722)
Caused by: com.vaadin.data.Buffered$SourceException
	at com.vaadin.ui.AbstractField.commit(AbstractField.java:253)
	at com.vaadin.data.fieldgroup.FieldGroup.commit(FieldGroup.java:443)
	... 46 more
Caused by: com.vaadin.data.util.MethodProperty$MethodException
	at com.vaadin.data.util.MethodProperty.invokeSetMethod(MethodProperty.java:690)
	at com.vaadin.data.util.MethodProperty.setValue(MethodProperty.java:661)
	at com.vaadin.data.util.TransactionalPropertyWrapper.setValue(TransactionalPropertyWrapper.java:80)
	at com.vaadin.ui.AbstractField.commit(AbstractField.java:249)
	... 47 more
Caused by: java.lang.IllegalArgumentException: argument type mismatch
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at com.vaadin.data.util.MethodProperty.invokeSetMethod(MethodProperty.java:676)
	... 50 more
|#]

This is simple example which reproduce error.

A ticket

Mb i’m doing something wrong ?

You must attach a
Converter
for converting String to BigDecimal and vice versa.

I created the converter copying and modifying code from standard converter. This worked for me:

public class EnduserBigdecimalConverter implements Converter<String, BigDecimal> {

    protected DecimalFormat getFormat(Locale locale) {
        if (locale == null) {
            locale = Locale.getDefault();
        }
        DecimalFormat dc = (DecimalFormat) NumberFormat.getInstance(locale);
        dc.applyPattern("#,##0.00");
        dc.setParseBigDecimal(true);
        dc.setRoundingMode(RoundingMode.HALF_UP);
        return dc;
    }

    @Override
    public BigDecimal convertToModel(String value, Locale locale)
            throws ConversionException {
        if (value == null) {
            return null;
        }

        // Remove leading and trailing white space
        value = value.trim();

        // Parse and detect errors. If the full string was not used, it is
        // an error.
        ParsePosition parsePosition = new ParsePosition(0);
        BigDecimal parsedValue = (BigDecimal) getFormat(locale).parse(value, parsePosition);
        if (parsePosition.getIndex() != value.length()) {
            throw new ConversionException("Could not convert '" + value
                    + "' to " + getModelType().getName());
        }

        if (parsedValue == null) {
            // Convert "" to null
            return null;
        }
        return parsedValue;
    }

    @Override
    public String convertToPresentation(BigDecimal value, Locale locale)
            throws ConversionException {
        if (value == null) {
            return null;
        }

        return getFormat(locale).format(value);
    }

    @Override
    public Class<BigDecimal> getModelType() {
        return BigDecimal.class;
    }

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

For attaching to field, you shuld do some similar to next:

AbstractField af = (AbstractField) groupFieldInstance.getField("importe");
af.setConverter(new EnduserBigdecimalConverter());

You should pay attentiont to this lines inside
protected DecimalFormat getFormat(Locale locale)
for customization:

DecimalFormat dc = (DecimalFormat) NumberFormat.getInstance(locale); // Or you can create DecimalFormat directly.
dc.applyPattern("#,##0.00");
dc.setParseBigDecimal(true); // IMPORTANT, setting to "true" for always returning BigDecimal
dc.setRoundingMode(RoundingMode.HALF_UP);