CDI integration in wicket can lead to null pointer exceptions after deserialization
The InjectIonBehavior does injection after deserialization only when beforeRender is called, but beforeRender() is not always the first call done after deserialization. Therefore, InjectionBehavior should do injection straight after deserialization (if needed).
Injection is now done at deserialization.
* for standard Java EE injection into components. Or, other injection
* frameworks can be used.
* </p>
- *
+ * <p/>
* <p>
* To use this injector override {@link WebApplication#init()} and add the
* listener:
* </p>
- *
+ * <p/>
* <pre>
* @Override
* protected void init() {
* addComponentInstantiationListener(new ComponentInstantiationInjector());
* }
* </pre>
- *
+ *
* @author Erik Brakkee
*/
-public class ComponentInstantiationInjector implements
- IComponentInstantiationListener {
+public class ComponentInstantiationInjector implements IComponentInstantiationListener {
private SimpleInjector injector;
@Override
public void onInstantiation(Component aComponent) {
injector.inject(aComponent);
- aComponent.add(new InjectionBehavior());
+ aComponent.add(new InjectionBehavior(aComponent));
}
-
}
*/
package org.wamblee.wicket.inject;
+import java.io.IOException;
+
import org.apache.wicket.Component;
import org.apache.wicket.behavior.AbstractBehavior;
import org.wamblee.inject.InjectorBuilder;
/**
* Injection behavior that performs dependency injection after
* serialization/deserialisation of the object.
- *
+ *
* @author Erik Brakkee
- *
*/
public class InjectionBehavior extends AbstractBehavior {
private static final long serialVersionUID = 7363393083209418693L;
- private transient boolean injectionUptodate;
+ private Component _component;
+ private boolean _injectionUptodate;
/**
* Constructs the behavior.
*/
- public InjectionBehavior() {
- injectionUptodate = true;
+ public InjectionBehavior(Component aComponent) {
+ _component = aComponent;
+ }
+
+ private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ }
+
+ private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ injectIfNeeded(_component);
}
- @Override
- public void beforeRender(Component aComponent) {
- if (!injectionUptodate) {
+ private void injectIfNeeded(Component aComponent) {
+ if (!_injectionUptodate) {
InjectorBuilder.getInjector().inject(aComponent);
- injectionUptodate = true;
+ _injectionUptodate = true;
}
}
}
@Test
public void testNoInjectionInitially() {
- InjectionBehavior behavior = new InjectionBehavior();
+ Component component = mock(Component.class);
+ InjectionBehavior behavior = new InjectionBehavior(component);
behavior.beforeRender(component);
verifyNoMoreInteractions(injector);
}
@Test
public void testInjectOnlyOnceAfterDeserialisation() throws Exception {
- InjectionBehavior behavior = new InjectionBehavior();
+ Component component = mock(Component.class);
+ InjectionBehavior behavior = new InjectionBehavior(component);
behavior = ObjectSerializationUtils.deserialize(
ObjectSerializationUtils.serialize(behavior),
InjectionBehavior.class);
- behavior.beforeRender(component);
- verify(injector).inject(same(component));
+ verify(injector).inject(any(Component.class));
reset(injector);
behavior.beforeRender(component);
verifyNoMoreInteractions(injector);