Using HbnContainer with Combox has odd behaviour

Hi

I’m using the HbnContainer as datasource for a ComboBox in a Form.
It fetches and matches data correct (after having played around with BeanItem and MethodProperty so that they handle ComboBox ItemId to Item mapping), BUT everytime I display the form the ComboBox states “null” as value UNTIL I press the Drop button after which is correctly shows the value that the Form objects property points to and the Combox “text” value corrected.
Is this a known bug or do I need to do something more?


private class UserFieldFactory extends DefaultFieldFactory {
   public Field createField(Item item, Object propertyId,
                Component uiContext) {
            if ("country".equals(propertyId)) {
                final ComboBox countries = new ComboBox("Country");
                countries.setWidth("30em");
                countries.setContainerDataSource(new HbnContainer(Country.class, applicationManager));
                countries.setItemCaptionPropertyId("name");
                countries.setFilteringMode(ComboBox.FILTERINGMODE_STARTSWITH);
                countries.setNullSelectionAllowed(false);
                return countries;
            }
           ...
   }
}

Hi!

Sorry for the long delayed answer. I have been too busy lately to learn to use our new forum.

Which version of HbnContainer are you using? Also the relation type would might help.

It was just during the spring when I typed some proper relation support for it. Until that related entities where handled differently and getting things working with Form needed some serious hacks.

In the version currently in SVN, HbnContainers properties “wrapping” a referenced entity now returns the identifier of the referenced entity. Previously actual entity objects where returned. The new behavior makes it much easier to work with Forms, Tables and FieldFactories. In the example app, there is no example of using ComboBox in Form, but there is some examples of using referenced entities in the Table using FieldFactory.

BTW. I don’t remember if all relation types are yet supported, but at least manyToOne and manyToMany are used in the example.

Hi

I’m using the version which has support for associations. I think I forked it 3 weeks before the name switch from IT Mill to Vaadin.

It’s a Many-To-One association.

The weird thing is that after the View is loaded the combobox displays null. But if I press the drop down button it shows the correct selected value.
So I’m wondering if it’s the combobox control that has a problem?

The fact that it uses entity identifier for instead of the entity tripped me a bit and forced a work around since homeAdress.getCountry() returns a Country instance, but HbnContainer works with Country’s Id’s. So I changed BeanItem to, first support nested properties (like user.getHomeAdress().getCountry()), and then internally use a different Property handling to work with Entity id’s for properties involving Hibernate entities.

/Jeppe

Just out of curiosity - have you considered upgrading to Vaadin 6.0.0? I just (yesterday) upgraded one (small) application from 5.2.x-pre to 6.0.0. The process was a breeze - search/replace com.itmill.toolkit → com.vaadin, renamed ITMILL dir to VAADIN and updated web.xml. As I was upgrading from 5.2 series, my application still had some OrderedLayout:s and ExpandLayouts. Replaced them with Vertical/HorzontalLayouts.

Hi!

The code quality in ComboBox isn’t anything nice to see, but I’d still guess the issue is in relation handling rather than in ComboBox. ComboBox has (a buggy, but ) much longer history than HbnContainer.

One new colleague of mine just fixed some null related issues at the end of May. Those might be related to this somehow. Do you have a lot of changes made to HbnContainer? It might help, if you’d try the most recent version of HbnContainer and without any special hacks (just replace textfield with combobox in FieldFactory). But as Joonas suggested it might be easier if you upgrade to Vaadin 6.0 at the same time.

I hope to find some time to finalize HbnContainer and make some example applications. Widening it to more generic JPA container is also planned.

cheers,
matti

Hi

Thanks for your answers :slight_smile:

I updated to Vaadin 6 a week after it was released (I’m actually running off of trunk at the moment to have sourcecode available while coding).

I will try and merge your updated HbnContainer with my forked version of HbnContainer to see if that fixes the null problem.
Also I wouldn’t mind sharing my expanded HbnContainer with you if you’re interested.
The features I’ve added so far are:

All searching is now based on Criteria and a HbnContainer user can subclass it and specify custom handling for the following things (at the moment, more is planned):


Modify base criteria
: Modifies the criteria that HbnContainer creates to support owned data. Example, I only want to show the vehicles that are associated with the currently logged in user.


Modify New Item
: Provide default values, setup associations to for instance the currently logged in user


Handle Remove Item
: Remove the entity from associations.

Apart from that you can also explicitly specify Properties to exclude or include (as there always will be properties you don’t want to display):

Example of a Container which shows all the currently logged in Users vehicles in a Table (User has a many-to-many association to Vehicle):


container = new HbnContainer<Vehicle>(Vehicle.class, applicationManager) {
                @Override
                protected void modifyBaseCriteria(Criteria criteria) {
                    criteria.createCriteria("userCollection").add(Restrictions.in("uuid", new Object[] {MyApp.getInstance().getContextUserUuid()}));
                }

                @Override
                protected void modifyNewItem(Vehicle newItem) {
                    newItem.withLicensePlateNumber("<License plate number>").withName("<Name>").withStartMileage(BigDecimal.ZERO);
                    MyApp.getInstance().getContextUser().addToVehicleCollection(newItem);
                }


                @Override
                protected void handleRemoveItem(Vehicle itemToBeRemoved) {
                    itemToBeRemoved.getUserCollection().clear();
                    super.handleRemoveItem(itemToBeRemoved);
                }


            };

            container.excludeProperties(
                asPropertyStringArray(
                    property(Vehicle.class).getCreated(),
                    property(Vehicle.class).getLastUpdated(),
                    property(Vehicle.class).getUuid(),
                    property(Vehicle.class).getUserCollection()
                )
            );

The last asPropertyStringArray and property() uses some smart class proxying to record properties while supporting code completion and refactoring (the same goes for our custom Form and BeanItem).

/Jeppe

Hi Jeppe!

I’d be very happy to receive some contributions to HbnContainer. And I suppose you’d also be happy to use the “standard” version. So please submit your pathes. Create a new enhancement ticket to dev.vaadin.com and add patches as attachments. You can assign the ticket straight to me. I’ll review and commit them asap.

cheers,
matti

Cool - I will finish it up and send you the patch when I’ve tested the latest feature additions.

I found the cause of the problem. Because Hibernate already had loaded the entity (address), which I wanted to display in the Form (and provide the ComboBox for Adress’ Country association), then POJO that Hibernate returned in HbnContainer and which was used in EntityItemProperty.getValue() was an uninitialized PROXY.

For some reason Hibernate didn’t think of handling proxy lazy initialization in AbstractEntityPersister (which implements ClassMetadata().getPropertyValue()), so it returns null for the Country item that the Address’s country property points to. Which explains why I didn’t see a selected value (and before the null patch to HbnContainer saw “null”).

Here’s the problematic code:


public class EntityItemProperty implements Property, Property.ValueChangeNotifier {
    ...
    public Object getValue() {
       // TODO clean, optimize, review
      Type propertyType = getClassMetadata().getPropertyType(propertyName);
--->      Object propertyValue = getClassMetadata().getPropertyValue(pojo, propertyName, EntityMode.POJO);

A quick fix for this is to just use ordinary reflection to fetch the property value:
Like this: Object propertyValue = ReflectUtils.getPropertyValue(pojo, propertyName);

Where ReflectUtils (our internal, I assume Vaadin has a class similar which I could use instead to keep HbnContainer compatible with the incubator?) uses PropertyDescriptors and reflection underneath.

/Jeppe

Hi!

How is it going with your HbnContainer patch?

Great to hear you have found the cause of your mysterious null isse. I think we don’t have any generic reflection utilities in Vaadin, so I believe you need to introduce a static helper method in HbnContainer if it is not possible to workaround the issue somehow with Hibernates utilities.

I just landed another patch from Down Under to HbnContainer. If it is not too difficult, please try to merge your upcoming patch to the latest version from svn.

cheers,
matti

Hi

The patch has been in hibernation, but I’ve just upgraded it to the latest HbnContainer from your SVN.
I’ve got SVN access now, should I just commit it directly or do you want to to have a go at the patch before its comitted?

/Jeppe

Hi!

Great to hear from you. I was already missing your patch some moths ago, but we did some similar changes with Henri.

There are quite a lot of changes done since the last summer, that you probably noticed. So I’d be happy to try out your patch in some of our projects before landing it to svn. You can send it via email (matti.tahvonen ät itmill dot com).

Although HbnContainer was initially supposed to be just an example, it is now used in such a many places and patches coming from so many developers that we’d really need some basic tests for it. For example I have no guarantees that we have not broken support for composite keys implemented by Daniel Bell. So if you have some, please send them too.

cheers,
matti

Hi

The latest improvements actually broke some other part of our program, so there are a couple of fixes in the there together with some additional new features. I will try and wrap it up this weekend (still have some extra features I would like in there) and send it to you by email.

/Jeppe

Hey,

Any news on that front? That seems pretty interesting!