UTILS-17
authorErik Brakkee <erik@brakkee.org>
Sat, 12 Oct 2013 12:09:09 +0000 (14:09 +0200)
committerErik Brakkee <erik@brakkee.org>
Sat, 12 Oct 2013 12:09:09 +0000 (14:09 +0200)
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.

wicket/joe/src/main/java/org/wamblee/wicket/inject/ComponentInstantiationInjector.java
wicket/joe/src/main/java/org/wamblee/wicket/inject/InjectionBehavior.java
wicket/joe/src/test/java/org/wamblee/wicket/inject/InjectionBehaviorTest.java

index cdda947daf8d3b4e8ab348e6a325605f499360d7..d4bb39dc5c2e501a1d7fc35932068fa9569f93f8 100644 (file)
@@ -29,12 +29,12 @@ import org.wamblee.inject.SimpleInjector;
  * 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>
  * &#064;Override
  * protected void init() {
@@ -42,11 +42,10 @@ import org.wamblee.inject.SimpleInjector;
  *     addComponentInstantiationListener(new ComponentInstantiationInjector());
  * }
  * </pre>
- * 
+ *
  * @author Erik Brakkee
  */
-public class ComponentInstantiationInjector implements
-    IComponentInstantiationListener {
+public class ComponentInstantiationInjector implements IComponentInstantiationListener {
 
     private SimpleInjector injector;
 
@@ -60,7 +59,6 @@ public class ComponentInstantiationInjector implements
     @Override
     public void onInstantiation(Component aComponent) {
         injector.inject(aComponent);
-        aComponent.add(new InjectionBehavior());
+        aComponent.add(new InjectionBehavior(aComponent));
     }
-
 }
index 659be7a75a3fdbd90cbab7a6be898a8e8cd3fbf7..45da4a98efeb99166e3c02be925271229875ec4a 100644 (file)
@@ -15,6 +15,8 @@
  */
 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;
@@ -22,27 +24,35 @@ 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;
         }
     }
 }
index d54de1ce4265af9f344611e97fc58df40d7e08b0..e9ba180ca6d767e54d0bd12c6d408c153b11d8de 100644 (file)
@@ -53,21 +53,22 @@ public class InjectionBehaviorTest {
 
     @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);