Any purpose of using a LoadableDetachableModel in a DataProvider?

2.1k views Asked by At

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?

2

There are 2 answers

6
tetsuo On BEST ANSWER

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.

1
bert On

For the LDM to work, you will have to actually detach the data in the detach() method. LDMs are meant to be used with databases, where you can restore / load the data on the next request with only the knowledge of an ID. So, in detach() you would trow away all data but the ID (or watever you need to relaod the data when needed) and in the load() (is this right? can't lock up the api right now) you will restore the data.

Hope that helps.