Search code examples
javawicketwicket-1.5

Any purpose of using a LoadableDetachableModel in a DataProvider?


Since it is still not 100% clear when a LDM should be used I tried a simple memory test. I created a DataView with a DataProvider that simply creates a list of few 100 entities with some big data inside (long String):

    private class HeavyDataProvider implements IDataProvider<HeavyBean> {

    @Override
    public void detach() {
    }

    @Override
    public Iterator<? extends HeavyBean> iterator(int first, int count) {
        List<HeavyBean> l = newArrayList();
        for (int i = 0; i < this.size(); i++) {
            l.add(new HeavyBean());
        }
        return l.iterator();
    }

    @Override
    public IModel<HeavyBean> model(HeavyBean heavyBean) {
        return new CompoundPropertyModel<HeavyBean>(heavyBean);
    }

    @Override
    public int size() {
        return 500;
    }
}

Using wicket's DebugBar is see this creates a Page with a size of 5MB. In the javadoc of DataProvider it is stated that the model return in above model method is usually a detachable one so I changed this method to:

        @Override
    public IModel<HeavyBean> model(final HeavyBean heavyBean) {
        return new LoadableDetachableModel<HeavyBean>() {

            @Override
            protected HeavyBean load() {
                return heavyBean;
            }
        };
    }

Naively I was expecting the pagesize to be reduced in a big way now since the heavybeans will no longer be part of the model. Actual result: 5MB. Since the model will detach the heavyBean this must mean that something else still has a hold of it (DataView? Item?).

I saw other examples where DataView and DataProvider are combined in a similar fashion but for me it is unclear what the point is since it does not seem to make any difference regarding the pageSize/memory usage.

So, am I understanding/doing something wrong (likely) or are LDM's useless in DataProviders? Side question (sorry), in which scenario would you use an LDM?


Solution

  • Your implementation of LDM is just plain wrong. It is holding a direct reference to the bean itself, and just returning it. This way, the bean will be serialized along the model, making it completely pointless.

    You should do something like this:

    @Override
    public IModel<HeavyBean> model(final HeavyBean heavyBean) {
        final Integer id = heavyBean.getId();
        return new LoadableDetachableModel<HeavyBean>() {
            @Override
            protected HeavyBean load() {
                return ServiceLocator.get(HeavyDao.class).get(id);
            }
        };
    }
    

    If you use the wicket-ioc module, the HeavyDao reference could be injected into the enclosing page/component.

    I think Wicket is really easy to use, but you must understand the basics of Java serialization, or else you may end up with a very bloated http session.