Problem with TextField and Null Representation

Hi all!

I have a TextField, with a setNullRepresentation(“”).

This field, is binded to a Integer field, via BeanItem.

I have a IntegerValidator on this field, that only try to do a Integer.parsetInt on the value, otherwise, it returns the error.

After the validator is invoked, if the user removes all chars of the field (that is allowed to be null), via reflection, the BeanItem try to put the null representation as a empty string, on the Bean Integer field, causing a exception:


Cause: com.vaadin.data.Buffered$SourceException
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:162)
	at com.vaadin.ui.AbstractComponent.fireEvent(AbstractComponent.java:1166)
	at com.vaadin.ui.Button.fireClick(Button.java:380)
	at com.vaadin.ui.Button.changeVariables(Button.java:196)
	at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariableBurst(AbstractCommunicationManager.java:1297)
	at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariables(AbstractCommunicationManager.java:1217)
	at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.doHandleUidlRequest(AbstractCommunicationManager.java:733)
	at com.vaadin.terminal.gwt.server.CommunicationManager.handleUidlRequest(CommunicationManager.java:296)
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:483)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:83)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
	at java.lang.Thread.run(Thread.java:662)
Caused by: com.vaadin.data.Buffered$SourceException
	at com.vaadin.ui.Form.commit(Form.java:365)
	at br.com.simus.supera.ciclonev2gui.views.atividade.modelo.CampoBaseForm$2.buttonClick(CampoBaseForm.java:130)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:490)
	... 26 more
Caused by: com.vaadin.data.Buffered$SourceException
	at com.vaadin.ui.AbstractField.commit(AbstractField.java:246)
	at com.vaadin.ui.Form.commit(Form.java:339)
	... 32 more
Caused by: com.vaadin.data.Property$ConversionException: java.lang.reflect.InvocationTargetException
	at com.vaadin.data.util.MethodProperty.setValue(MethodProperty.java:725)
	at com.vaadin.ui.AbstractField.commit(AbstractField.java:241)
	... 33 more
Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at com.vaadin.data.util.MethodProperty.setValue(MethodProperty.java:721)
	... 34 more
Caused by: java.lang.NumberFormatException: For input string: ""
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
	at java.lang.Integer.parseInt(Integer.java:470)
	at java.lang.Integer.<init>(Integer.java:660)
	... 39 more

How can I avoid that?

You could use a simple PropertyFormatter:

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;
    }
}

...
    Form form =
    ...
    Field countField = form.getField("count"); 
    countField.setPropertyDataSource(
            new LenientIntegerFormatter(
                    countField.getPropertyDataSource()));

There could be some other way as well, I’m not sure.

Maybe it would be usefull for somebody.

I had the similar issue. And I found the solution in example http://demo.vaadin.com/sampler#FormAdvancedLayout. All that I needed was: add line with TextField.setNullSettingAllowed(true) in createField() method.

Hi,

I have the same problem. I use following field definition.

TextField field = new TextField(caption);
field.setWidth(COMMON_FIELD_WIDTH);
field.setNullSettingAllowed(true);
field.setNullRepresentation(“0”);
field.addValidator(new IntegerValidator(“This is not an integer!!!”));

I have debugged into class AbstractField.setValue(). Here the value is set, but the given “NullRepresentation” is not used here.

So, from my point of view one can derive from TextField and overwrite the setValue method to invoke the real setValue with
the desired “NullSetValueRepresentation” !!??

so long,
falko

I’m using VAADIN 6.7.9

I forgot to write that I use the TextField in a Form with following behavior …

setImmediate(true);
setValidationVisible(true);
setWriteThrough(true);
setInvalidCommitted(true);

It seems that my problem is solved with following solution …

I use following Field definition now …

TextField field = new IntegerTextField(caption);
field.addValidator(new IntegerValidator(“This is not an Integer!”));

I use following derived Field class …

public class IntegerTextField extends TextField
{
private static final long serialVersionUID = 1L;

public IntegerTextField(String caption)
{
	super(caption);
}

/**
 * Sets the value of the field.
 * 
 * @param newValue
 *            the New value of the field.
 * @param repaintIsNotNeeded
 *            True iff caller is sure that repaint is not needed.
 * @throws Property.ReadOnlyException
 * @throws Property.ConversionException
 */
protected void setValue(Object newValue, boolean repaintIsNotNeeded)
        throws Property.ReadOnlyException, Property.ConversionException {
	
	if( newValue instanceof String)
	{
    	String value = (String) newValue;
    	if(StringUtils.isEmpty(value))
    	{
    		super.setValue("0", repaintIsNotNeeded);	
    		return;
    	}
	}
	
	super.setValue(newValue, repaintIsNotNeeded);
}

}

The nice effect is now, when I type a blank string into the field, this empty string is changed into “0”.
The TextField implementation now can set this “0” value to my Integer property. And after that no
validation error is raised.

What is missing here in the TextField implementation is a possibility to say …

→ If the value is a special value (empty String ot null) than set a default value

My solution is the following:

TextField field = new TextField();
field.setNullRepresentation(“”);

field.setNullSettingAllowed(true);

OR 2.
Overide the form’s commit() method:
@Override
public void commit() throws Buffered.SourceException, InvalidValueException {
// handle the “” string, i.e.
String myPropertyField = (String) getField(“myProperty”).getValue();
if (myPropertyField != null && “”.equals(myPropertyField.trim())) {
getField(“myPropertyField”).setValue(null);
}
super.commit();
}