Buffered$SourceException in Form.commit() using a BeanItemContainer

I am running Vaadin 6.3.0.nightly-20100212-c11297 under JDK 6 on Windows 7.

When I update a field in any of my BeanItems (stored in a BeanItemContainer), I get this exception. It’s the first visible column listed in the Table, which drives my Form. I find I can change the values in all my BeanItem’s except this first one (the name).

When I stepped into commit(), it appeared to set my bean just fine, but dies in that particular AbstractField.commit() call. The field is a TextField with a simple regex validator on it, and that passes the isValid() check.

It succeeds the MethodProperty.invokeSetMethod(value) call, which I stepped into and noted that it successfully called my bean’s set method for this property, and all looks fine.

But right after that, MethodProperty.fireValueChange() is called, and it dies in there eventually with this exception:

2010-02-12 18:11:00,300 ERROR (com.esignforms.open.vaadin.EsfVaadinApplication) terminalError()^M
com.vaadin.event.ListenerMethod$MethodException
Cause: com.vaadin.data.Buffered$SourceException^M
        at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:507)^M
        at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:161)^M
        at com.vaadin.ui.AbstractComponent.fireEvent(AbstractComponent.java:1110)^M
        at com.vaadin.ui.Button.fireClick(Button.java:341)^M
        at com.vaadin.ui.Button.changeVariables(Button.java:177)^M
        at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariables(AbstractCommunicationManager.java:1060)^M
        at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.doHandleUidlRequest(AbstractCommunicationManager.java:561)^M
        at com.vaadin.terminal.gwt.server.CommunicationManager.handleUidlRequest(CommunicationManager.java:260)^M
        at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:438)^M
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)^M
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)^M
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)^M
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)^M
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)^M
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)^M
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)^M
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)^M
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)^M
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)^M
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)^M
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)^M
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)^M
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)^M
        at java.lang.Thread.run(Unknown Source)^M
Caused by: com.vaadin.data.Buffered$SourceException^M
        at com.vaadin.ui.Form.commit(Form.java:338)^M
        at com.esignforms.open.vaadin.config.group.GroupForm.buttonClick(GroupForm.java:289)^M
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)^M
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)^M
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)^M
        at java.lang.reflect.Method.invoke(Unknown Source)^M
        at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:487)^M
        ... 21 more^M
Caused by: com.vaadin.data.Buffered$SourceException^M
        at com.vaadin.ui.AbstractField.commit(AbstractField.java:231)^M
        at com.vaadin.ui.Form.commit(Form.java:312)^M
        ... 27 more^M
Caused by: java.lang.NullPointerException^M
        at com.vaadin.data.util.BeanItemContainer.getContainerProperty(BeanItemContainer.java:303)^M
        at com.vaadin.ui.AbstractSelect.getContainerProperty(AbstractSelect.java:719)^M
        at com.vaadin.ui.Table.refreshRenderedCells(Table.java:1462)^M
        at com.vaadin.ui.AbstractSelect.getContainerProperty(AbstractSelect.java:719)^M
        at com.vaadin.ui.Table.refreshRenderedCells(Table.java:1462)^M
        at com.vaadin.ui.Table.valueChange(Table.java:2505)^M
        at com.vaadin.data.util.MethodProperty.fireValueChange(MethodProperty.java:951)^M
        at com.vaadin.data.util.MethodProperty.setValue(MethodProperty.java:715)^M
        at com.vaadin.ui.AbstractField.commit(AbstractField.java:226)^M
        ... 28 more^M
2010-02-12 18:11:00,302 ERROR (com.esignforms.open.vaadin.EsfVaadinApplication) terminalError()^M
java.lang.NullPointerException^M
        at com.vaadin.data.util.BeanItemContainer.getContainerProperty(BeanItemContainer.java:303)^M
        at com.vaadin.ui.AbstractSelect.getContainerProperty(AbstractSelect.java:719)^M
        at com.vaadin.ui.Table.refreshRenderedCells(Table.java:1462)^M
        at com.vaadin.ui.Table.getVisibleCells(Table.java:2380)^M
        at com.vaadin.ui.Table.paintContent(Table.java:2038)^M
        at com.vaadin.ui.AbstractComponent.paint(AbstractComponent.java:710)^M
        at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.paintAfterVariableChanges(AbstractCommunicationManager.java:779)^M
        at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.doHandleUidlRequest(AbstractCommunicationManager.java:592)^M
        at com.vaadin.terminal.gwt.server.CommunicationManager.handleUidlRequest(CommunicationManager.java:260)^M
        at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:438)^M
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)^M
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)^M
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)^M
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)^M
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)^M
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)^M
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)^M
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)^M
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)^M
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)^M
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)^M
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)^M
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)^M
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)^M
        at java.lang.Thread.run(Unknown Source)^M

What might be causing this?

Though I’d add this bit of info since it’s one of the oddities of this particular bean I have.

The name of the bean is used in TwinColSelect lists, so if I change the name, I have to reload the selection lists. I do set the mapping between the ID and the NAME using code like:

		// Set all the possible ID values (all are UUIDs)
		for( int i=0; i < allGroupListIds.length; ++i ) {
			selectList.addItem(allGroupListIds[i]
);
		}
		// Associate labels (names) with our ID values
		selectList.setItemCaptionMode(TwinColSelect.ITEM_CAPTION_MODE_EXPLICIT);
		for( int i=0; i < allGroupListIds.length; ++i ) {
			selectList.setItemCaption(allGroupListIds[i]
, allGroupListNames[i]
.toString());
		}

So I don’t know if this has created value change listeners of some sort since I would have a mapping like:

ID1 → Name1
ID2 → Name2
…etc…

So in the Form, when I change Name2 to Name2New, for example, I will reset my select boxes so they they reload the values when the form is displayed again. But I don’t ever reach my reset of select boxes in this situation because the commit() call fails before I attempt it. Here’s the snippet of code for handling the SAVE button, and it dies in the commit() call before it reaches anything else (which all works except when I change the NAME). In fact, my bean is even saved correctly since when I relogin after the terminal error, the beans have the updated value as expected.

	public void buttonClick(ClickEvent event) {
    	Button source = event.getButton();
    	if ( source == saveButton ) {
    		/* If the given input is not valid there is no point in continuing */
    		if ( ! isValid() ) {
    			vaadinApp.showWarning(null, vaadinApp.getVaadinMessages().getString("form.save.invalid"));
    			return;
        	}
			commit();
    			
    		// If we're saving a new group bean
    		if ( newGroupBean != null ) {
        		if ( newGroupBean.save() ) {
        			vaadinApp.showStatus( vaadinApp.getVaadinMessages().getString("form.saveNew.success.message",newGroupBean.getEsfName()) );
            		// We need to add the new GroupBean to the container
            		groupContainer.addItem(newGroupBean);
            		groupView.select(newGroupBean);
            		resetGroupCaches();
            		prevGroupBean = newGroupBean = null; // and we're not longer working on a new group
        		} else {
        			vaadinApp.showError(vaadinApp.getVaadinMessages().getString("form.save.failed.caption"), vaadinApp.getVaadinMessages().getString("form.save.failed.message"));
        		}
    		} else {
    			GroupBean currGroup = getCurrentGroupBean();
        		if ( currGroup.save() ) {
        			vaadinApp.showStatus( vaadinApp.getVaadinMessages().getString("form.save.success.message",currGroup.getEsfName()) );
        			setHeaders(currGroup);
            		setReadOnly( ! currGroup.hasPermGroupChange() ); // presumably they can edit, we keep them in edit mode
        		} else {
        			vaadinApp.showError(vaadinApp.getVaadinMessages().getString("form.save.failed.caption"), vaadinApp.getVaadinMessages().getString("form.save.failed.message"));
        		}
    		}

I seem to have tracked it down to this method in BeanItemContainer.

public Property getContainerProperty(Object itemId, Object propertyId) {
    return getItem(itemId).getItemProperty(propertyId);
}

The call get getItem is:

public BeanItem<BT> getItem(Object itemId) {
    return beanToItem.get(itemId);
}

But that routine fails because it calls the hashCode() method on my bean, which my bean implements and takes into account the NAME property of the bean, so when the name changes, I think, the hashCode itself changes, and then it’s no longer found.

Is this just a bug in my hashCode method? I’ve not written much before. I do have a UUID ‘id’ property. Should I use that since it never changes? I understand that hashCode and equals need to work in tandem, and we used the ‘name’ because we want to detect duplicates based on name to avoid having two objects with different UUIDs but the same name from being created and stored in our various sets that rely on the ‘contains’ check, to retrieve them

I’m know this is the issue, but what do people do when a given object should be unique (“equals”) on two distinct keys (ID and NAME, each of which must be unique)? For a quick check, I changed equals/hashCode to work against the UUID instead of NAME and this worked, but I no longer have the ability to easily check if a newly created object (which will always have a unique UUID) has a name that matches.

Do people use two HashSets, one by ID and one by NAME? Do you just hashset by ID and then iterate to check for duplicate names? The main problem is that most of our code uses name at runtime since users reference names and not ids.

Hi

I have the same problem.
Did you resolve this problem?

Looks like this question went unanswered, you probably shouldn’t have supplemented the question, threads with just one post appear more likely unanswered :blink:. Did you solve the problem? The new BeanContainer helps with some problems with BeanItemContainer that involve custom hashCode() and equals().