(no commit message)
[utils] / test / enterprise / src / main / java / org / wamblee / test / inject / JavaEETestInjector.java
index 9ea0517506fea7357937117ac1bb0fe571ef253e..8fe52ac10203de9030c599709c430d8b4fd85584 100644 (file)
  */
 package org.wamblee.test.inject;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
@@ -23,37 +27,98 @@ import javax.persistence.PersistenceContext;
 import org.wamblee.inject.Injector;
 import org.wamblee.reflection.Accessor;
 import org.wamblee.reflection.AnnotationUtils;
+import org.wamblee.reflection.ObjectTraversal;
+import org.wamblee.reflection.ObjectTraversal.ObjectVisitor;
 
 /**
- * Injector that performs additional injection on top of the injections that are standard
- * available (e.g. entity manager in Java SE environment).
+ * <p>
+ * Injector that performs additional injection on top of the injections that are
+ * standard available (e.g. entity manager in Java SE environment).
+ * </p>
+ * 
+ * <p>
+ * It works by first delegating to the default injector (typically CDI). Afterwards it traverses the
+ * object graph of the injected object and performs custom injection of test objects as specified by the
+ * {@link Binding} class. This approach makes sure that test dependencies also find their way into 
+ * objects that were created by the injection framework. 
+ * </p>
  * 
  * @author Erik Brakkee
  */
 public class JavaEETestInjector implements Injector {
 
-    private EntityManager entityManager;
+    private class InjectionVisitor implements ObjectVisitor {
+        @Override
+        public boolean mustVisit(Class aClass) {
+            if (EntityManager.class.isAssignableFrom(aClass)) { 
+                return false;
+            }
+            return true;
+        }
+        @Override
+        public boolean mustVisit(Field aField) {
+            // just process any field with annotations
+            return aField.getAnnotations().length > 0;  
+        }
+        @Override
+        public boolean mustVisit(Method aMethod) {
+            return false;
+        }
+        @Override
+        public boolean visitArray(Object aArray) {
+            return true;
+        }
+        @Override
+        public boolean visitList(List aObject) {
+            return true;
+        }
+        @Override
+        public boolean visitMap(Map aObject) {
+            return true;
+        }
+        @Override
+        public boolean visitPlainObject(Object aObject) {
+            performTestInjections(aObject);
+            return true;
+        }
+        @Override
+        public boolean visitSet(Set aSet) {
+            return true;
+        }
+    }
+
+    private List<Binding> bindings;
     private Injector delegate;
-    private List<Accessor> accessors;
 
     /**
-     * Constructs the injector. 
-     * @param aClass Class to inject for. 
-     * @param aEntityManager Entity manager. 
-     * @param aDelegate Injecto to delegate to to perform the standard injections. 
+     * Constructs the injector.
+     * 
+     * @param aClass
+     *            Class to inject for.
+     * @param aBindings
+     *            Binding of an object value.
+     * @param aDelegate
+     *            Injecto to delegate to to perform the standard injections.
      */
-    public JavaEETestInjector(Class aClass, EntityManager aEntityManager,
+    public JavaEETestInjector(Class aClass, List<Binding> aBindings,
         Injector aDelegate) {
-        entityManager = aEntityManager;
+        bindings = aBindings;
         delegate = aDelegate;
-        accessors = AnnotationUtils.analyse(aClass, PersistenceContext.class);
     }
 
     @Override
     public void inject(Object aComponent) {
+        // basic injection
         delegate.inject(aComponent);
-        for (Accessor accessor: accessors) {
-            accessor.set(aComponent, entityManager);
+        
+        // Now perform test injections.
+        ObjectTraversal traversal = new ObjectTraversal(new InjectionVisitor());
+        traversal.accept(aComponent);
+    }
+
+    private void performTestInjections(Object aComponent) {
+        for (Binding binding : bindings) {
+            binding.inject(aComponent);
         }
     }