ComboBox LazyQueryContainer Property.ConversionException problem

Hello everyone,

First of all, am new to Vaadin and I like it very much.

Second, is a problem with the ComboBox I’m fighting with for 3 days now. So, here it is :

I am trying to use a ComboBox field in a form, with a LazyQueryContainer as the datasource for the ComboBox.
Here’s extracted samples of code related to my problem :



LazyQueryContainer genresLQC = new LazyQueryContainer(new BeanQueryFactory<GenreBeanQuery>(GenreBeanQuery.class), 10);

ComboBox combobox = new ComboBox("Choose a genre", genresLQC);
combobox.setNewItemsAllowed(false);
combobox.setItemCaptionMode(ComboBox.ITEM_CAPTION_MODE_PROPERTY);
combobox.setItemCaptionPropertyId("name");
combobox.setImmediate(true);

This is all my code related to this ComboBox problem and is a container holding Items made up of domain object Genre and a ComboBox whose datasource is the container and the caption is the “name” property in the container.

The ComboBox displays fine in the form and it also gets populated with the data. The problem occurs when I am trying to select an element in the ComboBox. It throws the following ConversionException :


Exception
com.vaadin.data.Property$ConversionException: java.lang.NoSuchMethodException: com.crsltd.gno.model.Genre.(java.lang.String)
	at com.vaadin.data.util.MethodProperty.setValue(MethodProperty.java:716)
	at com.vaadin.ui.AbstractField.setValue(AbstractField.java:509)
	at com.vaadin.ui.AbstractSelect.setValue(AbstractSelect.java:665)
	at com.vaadin.ui.Select.changeVariables(Select.java:424)
	at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariables(AbstractCommunicationManager.java:1094)
	at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.doHandleUidlRequest(AbstractCommunicationManager.java:590)
	at com.vaadin.terminal.gwt.server.CommunicationManager.handleUidlRequest(CommunicationManager.java:266)
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:476)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:359)
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:275)
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:343)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:272)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:83)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:242)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:243)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:201)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:163)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:108)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:556)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:401)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:242)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:267)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:245)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:260)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:680)
Caused by: java.lang.NoSuchMethodException: com.crsltd.gno.model.Genre.(java.lang.String)
	at java.lang.Class.getConstructor0(Class.java:2706)
	at java.lang.Class.getConstructor(Class.java:1657)
	at com.vaadin.data.util.MethodProperty.setValue(MethodProperty.java:709)
	... 35 more

The good thing is : it’s right, my Genre bean does not have such a constructor.
The bad thing is : Why is it needed when you select/change the value in the ComboBox ?
The worst thing is : If I create such a constructor, when I select an element in the ComboBox, the selected value in the ComboBox is a newly created instance of Genre.

The way I expect it to work is :

As long as I am providing the container, I expect the selected value to be the corresponding Item/itemId/Bean/whatever from the container.

I searched the internet for an example with ComboBox + domain object container to no avail. I could only find ComboBox with containers and collections containing Strings. Is this the only option with a ComboBox ?

I just don’t understand how does this ComboBox work and how to use it …

Is this a bug ? Am I missing anything ?

Thanks very much,

Razvan

The MethodProperty that actually sets a field value checks if the type of the value matches the its property type. If it does, the appropriate setter is called. Otherwise, a String constructor for the value is called.

I see two possible sources for the problem: either the property type is not correct for the container or the values in the combo box are not actually instances of Genre. Also, unsuitable equals() and hashCode() methods could cause problems, but I guess that is not the issue here.

I have not used LazyQueryContainer, and don’t know how it determines the property types - maybe you need to tell it that the property in question is of type Genre.class .

If that does not help, I suggest you set a breakpoint e.g. in AbstractField.setValue() once the application is running, and check that the value is actually an instance of Genre. Knowing whether this is the case or not would help determine which of the potential problems you are having.

For more on the data APIs (Container, Item and Property), see
the book of Vaadin
- but LazyQueryContainer might introduce additional API on top of that.

Hi Henri,

Thanks for your quick reply, but I’m not sure I fully understand your suggestions.

The container type is correct because I am using it somewhere else (in a table) and it’s just fine.
Indeed, LazyQueryContainer adds some API, however the ComboBox uses the Container API, which LQC implements, but anyway, as the implementation may be “faulty”, I’ll try to use a different container and see what’s going on.

Also, as long as I pass the container to the ComboBox, and the ComboBox correctly displays the values, I suppose the objects in the ComboBox must be of the container’s type considering I am not doing anything awkward to the ComboBox… what other type could they be ? … And how would MethodProperty know to call a constructor on Genre (the correct type) … if the type wouldn’t be Genre ?

Will let you know the result of using a different container.

Best Regards,

Razvan

P.S : I’m not having vaadin sources but will try to dig into that class (AbstractField)

Hi Henri,

I tested with BeanItemContainer rather than LazyQueryContainer and no problem at all. Looks like this issue is due to LazyQueryContainer or the way I use LQC.

Thanks very much for your help.

Razvan

The sources are included in the Vaadin JAR - just point your IDE to it if not automatically done.

A separate source JAR is also available in the Maven repositories in case you are using Maven - in that case, just ask your IDE to load the sources from there.

Razvan,

Did you have any success in using the LazyQueryContainer with the ComboBox? I’m experiencing the same problems with CriteriaContainer (a subclass of LazyQueryContainer).

Best Regards,
Vilhelm

LazyQueryContainer returns an integer (the index of the selected item) – it does not return the item itself (contrary to some other containers).

CriteriaContainer is a wrapper around LQC and by default has that same behaviour. In the last release I added the ability to retrieve a specific property from the item (there is a setKeyPropertyId(propertyName) method to do so).

I understand that the expectation of retrieving the item (as opposed to a key or an index) is just as natural, and will try to accomodate the need in an upcoming release of CriteriaContainer

LQC does not have full implementation on the container index interface. It will simply return the index integer. And the Combo box users that interface on the underlying container. It is different from the Table. So to make them work together I had to tweak both the ComboBox (extend it) and LQC to make them work together. The trick is LQC servers the beanitem, while the combobox internally uses a list of beans (not bean items). so there needs to be a PropertyDataSource to server as a bridge.

Hi,
I’m using criteriacontainer (an amazing addon thanks to you) and I just faced this issue, is there any progress regarding this issue cause I don’t want to load 4000 entities into the UI and I want to use criteriacontainer to take care of pagination and buffering in Select(s).

I need more details to understand. As far as I can tell, ComboBox and Select do not even attempt to do Lazy loading - they read the whole container. Am I missing something ?

The latest versions of ComboBox use lazy loading in certain situations (using a property, not toString(), as the caption etc.). In cases where it isn’t possible to use lazy loading, they fall back to loading the whole list of IDs on the server side etc. The default mode of ComboBox is using toString() so no lazy loading there.

In my case I use property mode for captions and as far as I noticed (and Henri confirmed) Select(s) do lazy loading in that case, the only problem is that getValue in the container seems to retyrn the index of the entity not the actual entity.

Ok. That much is true. Returning the index is the behavior inherited from the underlying LazyQueryContainer.

You might try using setKeyPropertyId(propId) which would return the value of the specified property instead of the index. However, in that case, the lazy loading behaviour will be dependent on whether getItemIds() is called. If the ComboBox calls getItemIds, and the key property id is set, then the full set of Ids will be retrieved, and this would nullify the lazy loading behaviour.

So whether using setKeyPropertyId(propId) solves your problem depends whether the actual implementation of ComboBox uses getItemIds() in your specific case.

Hi Tony,
Can you please provide some sample code about how you used LQC with ComboBox. I did not quit get the last part, how exactly to use PropertyDataSource as bridge? Also does the search filter works with LQC and CmboBox?

thanks

Please let me know as well.

Is there any progession here?