IoC: how to best handle non-serializable fields in wicket

446 views
Skip to first unread message

Andreas Petersson

unread,
Feb 5, 2009, 6:46:50 PM2/5/09
to us...@wicket.apache.org, google...@googlegroups.com
hi!
so, im using wicket together with guice for DI.
i really wondered that the correct approach is here.
at first i thought it way easy to do this, but it turns out it is more
complicated..- at least more complicated to understand.
my typical page looks like this:

public class StartPage extends WebPage {
private transient EmkDao dao;

@Inject
public void setDao(EmkDao dao) {
this.dao = dao;
}


public EmkDao getDao() {
return dao;
}

public Start() {
add( Components that use the dao in various ways (models, onclick etc);
}
}

this seems to work well, in simple cases. BUT! as soon as i press
browser-back and reload most likely the dao member has become null. -> NPE

the expected behavior would be: transient fields are re-injected
whenever the page is deserialized. obviously this is not the case.
im surprised, that my StartPage is often a different instance (as seen
in the debugger) , when using browser-back-reload, but the setter
annotated with @Inject is not called twice.

since WebPage is Serializable and most injected objects are not (they
often contain references to non-serializable classes) they have to be
declared transient.

I use the following guice config:


<filter>
<filter-name>WicketApplication</filter-name>

<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationFactoryClassName</param-name>

<param-value>org.apache.wicket.guice.GuiceWebApplicationFactory</param-value>
</init-param>
<init-param>
<param-name>injectorContextAttribute</param-name>
<param-value>com.google.inject.Injector</param-value>
</init-param>
</filter>

with

bind(WebApplication.class).to(MyWicketApplication.class) in my Module.

i also tried the configuration described at
http://www.wideplay.com/wicketwithwarp-servlet with a simple
WicketFilter (without the GuiceWebApplicationFactory) and
Integrathe.with(this) in the WicketApplication, with the same result.

As I'm writing this mail, it turns out, it appears to work if i just
omit the "transient" keyword.
i wonder: what will that do to wicket pages? will i prevent them to
serialize any more? why doesn't it throw a NotSerializableException ?
then i have to use
@SuppressWarnings({"NonSerializableFieldInSerializableClass"}) for
IntelliJ to omit the warning.
somehow i am missing a coherent documentation on wicket+IoC on this matter.

best regards,
Andreas

Guðmundur Bjarni

unread,
Feb 6, 2009, 4:47:26 AM2/6/09
to google-guice
Hi Andreas,

I have been using Wicket and Guice together for quite some time now
and it works like a charm. There are however a couple of "drawbacks"
if you will:

1) The way Wicket is written, dictates that Wicket constructs the page
classes itself either using the default constructor or a constructor
which has a PageParameter argument. The side-effect of this is that
you can't use constructor injection for your pages.

2) As you rightly point out, Wicket will attempt to serialize the
injected instances which is not good since many of them are proxied by
Guice and not really intended to be serialized. The solution however
is to use the wicket-guice project, which takes over the injection of
pages and injects them during construction (through component
instantiation listeners) and again after serialization.

So the problem that you are getting into is this: The first time you
construct the page via Guice it is properly injected and works, though
not mountable (will have nasty urls). It is then serialized by Wicket
and since the field is marked as transient it will skip that. When you
re-request the page, the transient field will be null, thus wreaking
havoc.

In short, the solution is to use the wicket-guice project, let Wicket
construct the pages, use non-transient fields for the services/daos
and place the @Inject annotation on the fields.


regards,
Guðmundur Bjarni
> i also tried the configuration described athttp://www.wideplay.com/wicketwithwarp-servletwith a simple

Andreas

unread,
Feb 6, 2009, 5:26:26 AM2/6/09
to google-guice
thanks for the input.
i never considered constructing instances of pages using guice, that
would contradict the mounting of pages. - the nasty urls you pointed
out.

i had some good input at the wicket-user mailing list, too.
http://www.nabble.com/IoC%3A-how-to-best-handle-non-serializable-fields-in-wicket-td21863836.html

basically, the issue arises, because other IoC containers do not use
annotations, thus wicket can not figure out which fields would like to
be re-injected upon deserialisation.
my solution is now to use the wicket-ioc and just declare non-
serializable fields in my wicket pages. of course that drives the
IntelliJ inspections mad. - i have to use @SupressWarnings...

regads,
Andreas
Reply all
Reply to author
Forward
0 new messages