GeneratedPropertyContainer - sorting of generated properties

Hello,

I’m wondering how it is possible to sort generated properties added by GeneratedPropertyContainer.addGeneratedProperty(id, new PropertyValueGenerator<...>()
Book of Vaadin only says (8.5.7. GeneratedPropertyContainer - Sorting)
“Even though the GeneratedPropertyContainer implements Container.Sortable, the wrapped container must also support it or otherwise sorting is disabled. Also, the generated properties are
not
normally
sortable
, but
require special handling to enable sorting
.”

without explaining on what sort of
special handling
is required (I wrapped ye’ olde IndexedContainer is anyone is wondering).

So far I’ve tried to

  • make sure the generated property is included in the sortablePropertyIds by adding
    @Override public SortOrder getSortProperties(final SortOrder order) { return new SortOrder{new SortOrder(this, order.getDirection())}; }
    to the PropertyValueGenerator - debug shows that the generated property is included.
  • implement a CustomItemSorter by extending the DefaultItemSorter, also calling the setSortProperties and passing the GeneratedPropertyContainer to it, but a debug shows that for whatever reason it only picks up the regular property in the container, not the generated one.

Tried it with 7.4.3 as well as 7.5.1.

Does anyone have more insight in this?

Progress! I managed to get my generated property to sort - not sure if there is a better way but for those wondering:

First of all:

return new SortOrder{new SortOrder([b]
this
[/b], order.getDirection())};

of course has to be

return new SortOrder{new SortOrder([b]
actualPropertyId
[/b], order.getDirection())};

with the actualPropertyId (aka the pid of the property I’m - in my case - replacing with the generated one) being passed to the PropertyValueGenerator. I wonder if there is a better/easier way to get the pid?

Next I passed my CustomItemSorter a reference to the GeneratedPropertyContainer and made sure it will always use that one

    @Override
    public void setSortProperties(final Sortable container, final Object propertyId, final boolean ascending) {
      super.setSortProperties(this.myGeneratedPropertyContainer, propertyId, ascending);
    }

this way when
ItemSorter
calls
getSortableContainerPropertyIds()
it will use the
GeneratedPropertyContainer
instead of the underlying
IndexedContainer
and pick up the generatedProperty.

Don’t forget to override the compareProperty(…) method if neccessary.

could you please explain more detials and give some example code.

I know this post is old, but I’ve run into that same issue and here is a way of achieving this in Vaadin 7 (just paste it on a new UI):

protected void init(VaadinRequest vaadinRequest) {
        final VerticalLayout layout = new VerticalLayout();

        List<Item> items = Arrays.asList(new Item[] { new Item("John Doe", new Date(80, 1, 20)),
                new Item("John Smith", new Date(82, 2, 21)), new Item("Dave Doe", new Date(81, 5, 1)) });

        PropertyValueGenerator<Integer> pvg = new PropertyValueGenerator<Integer>() {
            @Override
            public Integer getValue(com.vaadin.data.Item item, Object itemId, Object propertyId) {
                Date birthday = (Date) item.getItemProperty("birthday").getValue();
                Date now = new Date();
                return (int) ((now.getTime() - birthday.getTime()) / (1000 * 60 * 60 * 24 * 365L));
            }

            @Override
            public Class<Integer> getType() {
                return Integer.class;
            }

            @Override
            public SortOrder[] getSortProperties(SortOrder order) {
                return new SortOrder[] { order };
            }
        };

        BeanItemContainer<Item> bic = new BeanItemContainer<Item>(Item.class, items) {
            @Override
            public Collection<?> getSortableContainerPropertyIds() {
                Set<Object> result = new HashSet<>(super.getSortableContainerPropertyIds());
                result.add("age");
                return result;
            }
        };
        bic.setItemSorter(new DefaultItemSorter() {
            @Override
            protected int compareProperty(Object propertyId, boolean sortDirection, com.vaadin.data.Item item1,
                    com.vaadin.data.Item item2) {
                if (propertyId.equals("age")) {
                    Integer value1 = pvg.getValue(item1, null, null);
                    Integer value2 = pvg.getValue(item2, null, null);
                    int c = value1.compareTo(value2);
                    return sortDirection ? c : -1;
                } else {
                    return super.compareProperty(propertyId, sortDirection, item1, item2);
                }
            }
        });

        GeneratedPropertyContainer gpc = new GeneratedPropertyContainer(bic);
        gpc.addGeneratedProperty("age", pvg);

        Grid people = new Grid();
        people.setContainerDataSource(gpc);

        layout.addComponents(people);
        layout.setMargin(true);
        layout.setSpacing(true);

        setContent(layout);
    }

Thank you so much