Wicket in Action

A comprehensive guide for Java developers building Wicket-based web applications

Detect attached models and entities in your component hierarchy

Adrian Cox asked a great question over at StackOverflow on how to prevent (Hibernate) entities from being attached to your Wicket component tree, thus generating all those nasty exceptions like StaleObjectException, LazyInitException and the like:

JPA managed objects must not be stored in the session. Instead, JPA managed objects are loaded on each request through detachable models.

From  Extending Wickets serialization test – Stack Overflow.

I have previously shown at several Wicket meetups that this is feasible. See slide 23 and onward on this slideshare presentation (the rest of the presentation is also worth your while).

At Topicus we use the same kind of check for our applications as well. Being bitten by entities as fields, or final references, non-detached models or suddenly re-attached models we came to the conclusion that we needed to check for these errors. The EntityAndSerializerChecker was the result of our coding efforts.

Basically what you do is copy Wicket’s serializer checker code and modify it to include your check as well as checking for serialization errors.

The check we created checks for our common base class, and wether or not the entity has been persisted. If so, we flag the error. Here’s the meat of our checker (the check method rewritten from Wicket’s serializer check):

private void check(Object obj) {
    if (obj == null || obj.getClass().isAnnotationPresent(Deprecated.class)
        || obj.getClass().isAnnotationPresent(SkipClass.class)) {
        return;
    }
 
    Class< ? > cls = obj.getClass();
    nameStack.add(simpleName);
    traceStack.add(new TraceSlot(obj, fieldDescription));
 
    if (!(obj instanceof Serializable) && (!Proxy.isProxyClass(cls))) {
        throw new WicketNotSerializableException(toPrettyPrintedStack(obj.getClass().getName())
            .toString(), exception);
    }
    if (obj instanceof IdObject) {
        Serializable id = ((IdObject) obj).getIdAsSerializable();
        if (id != null && !(id instanceof Long && ((Long) id) <= 0)) {
            throw new WicketContainsEntityException(toPrettyPrintedStack(
                obj.getClass().getName()).toString(), exception);
        }
    }
    if (obj instanceof LoadableDetachableModel) {
        LoadableDetachableModel< ? > ldm = (LoadableDetachableModel< ? >) obj;
        if (ldm.isAttached()) {
            throw new WicketContainsAttachedLDMException(toPrettyPrintedStack(
                obj.getClass().getName()).toString(), exception);
        }
    }
}

For Wicket 1.5 we created our own PageStoreManager that performs these checks (and a lot of other things, like enabling a server side browsing history for our users). We provided our own RequestAdapter by overriding PageStoreManager#newRequestAdapter(IPageManagerContext context) and doing the serialization check in the adapter:

class DetachCheckingRequestAdapter extends RequestAdapter {
    public DetachCheckingRequestAdapter(IPageManagerContext context) {
        super(context);
    }
 
    @Override
    protected void storeTouchedPages(List<IManageablePage> touchedPages) {
        super.storeTouchedPages(touchedPages);
        if (Application.get().usesDevelopmentConfig()) {
            for (IManageablePage curPage : touchedPages) {
                if (!((Page) curPage).isErrorPage())
                    testDetachedObjects(curPage);
            }
        }
    }
 
    private void testDetachedObjects(final IManageablePage page) {
        try {
            NotSerializableException exception = new NotSerializableException();
            EntityAndSerializableChecker checker = new EntityAndSerializableChecker(exception);
            checker.writeObject(page);
        }
        catch (Exception ex) {
            log.error("Couldn't test/serialize the Page: " + page + ", error: " + ex);
            Session.get().setDetachException(ex);
        }
    }
}

Additionally we have an Ajax callback in our base page that checks the session attribute to see if there was a serialization error. If so, we redirect to the error page with the serialization failure, to ensure that developers don’t ignore the entity in page hierarchy. You can’t show an error directly because when the check is performed, Wicket has already sent the markup to the browser and closed the connection.

So there you go: checking for serialization errors and persisted entities in your component hierarchy. Works like a charm and will drive your developers nuts at first, but will save a lot of money chasing down production bugs.

With this book, Wicket will become the greatest territory the Dutch have settled since Manhattan.

Nathan Hamblen
Senior Software Engineer, Teachscape Inc.

This is the complete and authoritative guide to Wicket, written and reviewed by the core members of the Apache Wicket team. If there's anything you want to know about Wicket, you are sure to find it in this book.

Jonathan Locke
Founder and Architect of Apache Wicket, Foreword Wicket in Action

Without question, Wicket in Action... is the be-all and end-all when it comes to Wicket.

Geertjan Wielenga, Wicket Netbeans Plugin Author

The tutorial and conversational tone of the writing makes the book very approachable.

Nick Heudecker
System Mobile

Loved the sample application—it tied everything together.

Phil Hanna
Senior Software Developer, SAS Institute

The essential guide for learning and using Wicket.

Erik van Oosten
Lead programmer and Project Manager, JTeam

Finally, the Web Framework of web frameworks, Apache Wicket, now has a bible of its own.

Per Ejeklint
Senior Software Architect, Heimore group

Wicket is an innovative evolution of the MVC programming with simple roots, but without a primer such as this, it can be more challenging than it needs to be.

Brian Topping
Founder, Bill2 Inc.

Wicket In Action glues the areas of web development with Apache Wicket together and gives a great overview of Apache Wicket...it will make a great compendium.

Nino Martinez Wael
Java Specialist, Jayway Denmark