Repository: avaje/avaje-inject
Pull request #106 (2021-05-14 21:46:09)

Refactor/simplify to single builder - remove parent/child part


Patch:
diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/Constants.java b/inject-generator/src/main/java/io/avaje/inject/generator/Constants.java
index 61fa7cdf..701dd38c 100644
--- a/inject-generator/src/main/java/io/avaje/inject/generator/Constants.java
+++ b/inject-generator/src/main/java/io/avaje/inject/generator/Constants.java
@@ -16,16 +16,16 @@ class Constants {
   static final String AT_GENERATED = "@Generated(\"io.avaje.inject.generator\")";
   static final String META_INF_FACTORY = "META-INF/services/io.avaje.inject.spi.BeanContextFactory";
 
-  static final String BEANCONTEXT = "io.avaje.inject.BeanContext;";
-  static final String CONTEXTMODULE = "io.avaje.inject.ContextModule;";
+  static final String BEANCONTEXT = "io.avaje.inject.BeanContext";
+  static final String CONTEXTMODULE = "io.avaje.inject.ContextModule";
 
   static final String GENERATED = "io.avaje.inject.spi.Generated";
   static final String BEAN_FACTORY = "io.avaje.inject.spi.BeanFactory";
   static final String BEAN_FACTORY2 = "io.avaje.inject.spi.BeanFactory2";
   static final String BEAN_LIFECYCLE = "io.avaje.inject.spi.BeanLifecycle";
   static final String BUILDER = "io.avaje.inject.spi.Builder";
-  static final String DEPENDENCYMETA = "io.avaje.inject.spi.DependencyMeta;";
-  static final String BEANCONTEXTFACTORY = "io.avaje.inject.spi.BeanContextFactory;";
+  static final String DEPENDENCYMETA = "io.avaje.inject.spi.DependencyMeta";
+  static final String BEANCONTEXTFACTORY = "io.avaje.inject.spi.BeanContextFactory";
 
   static boolean isBeanLifecycle(String type) {
     return BEAN_LIFECYCLE.equals(type);
diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/ProcessingContext.java b/inject-generator/src/main/java/io/avaje/inject/generator/ProcessingContext.java
index 79e4a035..7c29d0de 100644
--- a/inject-generator/src/main/java/io/avaje/inject/generator/ProcessingContext.java
+++ b/inject-generator/src/main/java/io/avaje/inject/generator/ProcessingContext.java
@@ -142,12 +142,13 @@ class ProcessingContext {
   }
 
   void buildNewBuilder(Append writer) {
-    writer.append("    this.builder = Builder.newBuilder(\"%s\"", contextName);
-    writer.append(", ");
+    writer.append("    this.name = \"%s\";", contextName).eol();
+    writer.append("    this.provides = ", contextProvides);
     buildStringArray(writer, contextProvides, true);
-    writer.append(", ");
+    writer.append(";").eol();
+    writer.append("    this.dependsOn = ", contextDependsOn);
     buildStringArray(writer, contextDependsOn, true);
-    writer.append(");").eol();
+    writer.append(";").eol();
   }
 
   void buildAtContextModule(Append writer) {
diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleFactoryWriter.java b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleFactoryWriter.java
index dc38e47e..76d186f0 100644
--- a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleFactoryWriter.java
+++ b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleFactoryWriter.java
@@ -102,14 +102,13 @@ class SimpleFactoryWriter {
   private void writeCreateMethod() {
     writer.append(CODE_COMMENT_CREATE_CONTEXT).eol();
     writer.append("  @Override").eol();
-    writer.append("  public BeanContext createContext(Builder parent) {").eol();
-    writer.append("    builder.setParent(parent);").eol();
+    writer.append("  public void build(Builder builder) {").eol();
+    writer.append("    this.builder = builder;").eol();
     writer.append("    // create beans in order based on constructor dependencies").eol();
     writer.append("    // i.e. \"provides\" followed by \"dependsOn\"").eol();
     for (MetaData metaData : ordering.getOrdered()) {
       writer.append("    build_%s();", metaData.getBuildName()).eol();
     }
-    writer.append("    return builder.build();").eol();
     writer.append("  }").eol();
     writer.eol();
   }
@@ -143,7 +142,10 @@ class SimpleFactoryWriter {
     context.buildAtContextModule(writer);
 
     writer.append("public class %s implements BeanContextFactory {", factoryShortName).eol().eol();
-    writer.append("  private final Builder builder;").eol().eol();
+    writer.append("  private final String name;").eol();
+    writer.append("  private final String[] provides;").eol();
+    writer.append("  private final String[] dependsOn;").eol();
+    writer.append("  private Builder builder;").eol().eol();
 
     writer.append("  public %s() {", factoryShortName).eol();
     context.buildNewBuilder(writer);
@@ -151,17 +153,17 @@ class SimpleFactoryWriter {
 
     writer.append("  @Override").eol();
     writer.append("  public String getName() {").eol();
-    writer.append("    return builder.getName();").eol();
+    writer.append("    return name;").eol();
     writer.append("  }").eol().eol();
 
     writer.append("  @Override").eol();
     writer.append("  public String[] getProvides() {").eol();
-    writer.append("    return builder.getProvides();").eol();
+    writer.append("    return provides;").eol();
     writer.append("  }").eol().eol();
 
     writer.append("  @Override").eol();
     writer.append("  public String[] getDependsOn() {").eol();
-    writer.append("    return builder.getDependsOn();").eol();
+    writer.append("    return dependsOn;").eol();
     writer.append("  }").eol().eol();
   }
 
diff --git a/inject/src/main/java/io/avaje/inject/BeanContext.java b/inject/src/main/java/io/avaje/inject/BeanContext.java
index b983248e..fa3ea4f0 100644
--- a/inject/src/main/java/io/avaje/inject/BeanContext.java
+++ b/inject/src/main/java/io/avaje/inject/BeanContext.java
@@ -77,27 +77,6 @@ public interface BeanContext extends Closeable {
     return new DBeanContextBuilder();
   }
 
-  /**
-   * Return the module name of the bean context.
-   *
-   * @see ContextModule
-   */
-  String getName();
-
-  /**
-   * Return the names of module features this bean context provides.
-   *
-   * @see ContextModule
-   */
-  String[] getProvides();
-
-  /**
-   * Return the names of modules this bean context depends on.
-   *
-   * @see ContextModule
-   */
-  String[] getDependsOn();
-
   /**
    * Return a single bean given the type.
    *
diff --git a/inject/src/main/java/io/avaje/inject/DBeanContextBuilder.java b/inject/src/main/java/io/avaje/inject/DBeanContextBuilder.java
index 5918bb2c..6f3cf019 100644
--- a/inject/src/main/java/io/avaje/inject/DBeanContextBuilder.java
+++ b/inject/src/main/java/io/avaje/inject/DBeanContextBuilder.java
@@ -8,15 +8,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.lang.annotation.Annotation;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.ServiceLoader;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
 
@@ -120,12 +112,12 @@ class DBeanContextBuilder implements BeanContextBuilder {
         " Refer to https://avaje.io/inject#gradle");
     }
     log.debug("building context with modules {}", moduleNames);
-    Builder rootBuilder = Builder.newRootBuilder(suppliedBeans, enrichBeans);
+    Builder builder = Builder.newBuilder(suppliedBeans, enrichBeans);
     for (BeanContextFactory factory : factoryOrder.factories()) {
-      rootBuilder.addChild(factory);
+      factory.build(builder);
     }
 
-    BeanContext beanContext = rootBuilder.build();
+    BeanContext beanContext = builder.build();
     // entire graph built, fire postConstruct
     beanContext.start();
     if (shutdownHook) {
@@ -180,21 +172,6 @@ class DBeanContextBuilder implements BeanContextBuilder {
       Runtime.getRuntime().addShutdownHook(hook);
     }
 
-    @Override
-    public String getName() {
-      return context.getName();
-    }
-
-    @Override
-    public String[] getProvides() {
-      return context.getProvides();
-    }
-
-    @Override
-    public String[] getDependsOn() {
-      return context.getDependsOn();
-    }
-
     @Override
     public <T> T getBean(Class<T> beanClass) {
       return context.getBean(beanClass);
diff --git a/inject/src/main/java/io/avaje/inject/spi/BeanContextFactory.java b/inject/src/main/java/io/avaje/inject/spi/BeanContextFactory.java
index 1af0ffdb..88a5e7dd 100644
--- a/inject/src/main/java/io/avaje/inject/spi/BeanContextFactory.java
+++ b/inject/src/main/java/io/avaje/inject/spi/BeanContextFactory.java
@@ -1,7 +1,5 @@
 package io.avaje.inject.spi;
 
-import io.avaje.inject.BeanContext;
-
 /**
  * This is the service loader interface defining the bean contexts that can be created.
  */
@@ -23,7 +21,7 @@ public interface BeanContextFactory {
   String[] getDependsOn();
 
   /**
-   * Create and return the BeanContext.
+   * Build all the beans.
    */
-  BeanContext createContext(Builder parent);
+  void build(Builder builder);
 }
diff --git a/inject/src/main/java/io/avaje/inject/spi/Builder.java b/inject/src/main/java/io/avaje/inject/spi/Builder.java
index 4e1438a0..6eb74e16 100644
--- a/inject/src/main/java/io/avaje/inject/spi/Builder.java
+++ b/inject/src/main/java/io/avaje/inject/spi/Builder.java
@@ -21,7 +21,7 @@ public interface Builder {
    * @param enrichBeans   The list of classes we want to have with mockito spy enhancement
    */
   @SuppressWarnings("rawtypes")
-  static Builder newRootBuilder(List<SuppliedBean> suppliedBeans, List<EnrichBean> enrichBeans) {
+  static Builder newBuilder(List<SuppliedBean> suppliedBeans, List<EnrichBean> enrichBeans) {
     if (suppliedBeans.isEmpty() && enrichBeans.isEmpty()) {
       // simple case, no mocks or spies
       return new DBuilder();
@@ -29,37 +29,6 @@ public interface Builder {
     return new DBuilderExtn(suppliedBeans, enrichBeans);
   }
 
-  /**
-   * Create a Builder for the named context (module).
-   *
-   * @param name      the name of the module / bean context
-   * @param provides  the module features this module provides
-   * @param dependsOn the names of modules this module is depends on.
-   */
-  static Builder newBuilder(String name, String[] provides, String[] dependsOn) {
-    return new DBuilder(name, provides, dependsOn);
-  }
-
-  /**
-   * Return the name of the (module) context this builder is creating.
-   */
-  String getName();
-
-  /**
-   * Return the names of module features that this module provides.
-   */
-  String[] getProvides();
-
-  /**
-   * Return the names of modules that this module depends on.
-   */
-  String[] getDependsOn();
-
-  /**
-   * Set a parent builder that can provide cross-module dependencies.
-   */
-  void setParent(Builder parent);
-
   /**
    * Return true if the bean should be created and registered with the context.
    * <p/>
@@ -108,11 +77,6 @@ public interface Builder {
    */
   void addInjector(Consumer<Builder> injector);
 
-  /**
-   * Add a child context.
-   */
-  void addChild(BeanContextFactory factory);
-
   /**
    * Get an optional dependency.
    */
diff --git a/inject/src/main/java/io/avaje/inject/spi/DBeanContext.java b/inject/src/main/java/io/avaje/inject/spi/DBeanContext.java
index 59bfe217..4b2a8dc7 100644
--- a/inject/src/main/java/io/avaje/inject/spi/DBeanContext.java
+++ b/inject/src/main/java/io/avaje/inject/spi/DBeanContext.java
@@ -10,7 +10,6 @@ import java.lang.annotation.Annotation;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.locks.ReentrantLock;
 
 class DBeanContext implements BeanContext {
@@ -18,43 +17,14 @@ class DBeanContext implements BeanContext {
   private static final Logger log = LoggerFactory.getLogger(DBeanContext.class);
 
   private final ReentrantLock lock = new ReentrantLock();
-
-  private final String name;
-
-  private final String[] provides;
-
-  private final String[] dependsOn;
-
   private final List<BeanLifecycle> lifecycleList;
-
   private final DBeanMap beans;
 
-  private final Map<String, BeanContext> children;
-
   private boolean closed;
 
-  DBeanContext(String name, String[] provides, String[] dependsOn, List<BeanLifecycle> lifecycleList, DBeanMap beans, Map<String, BeanContext> children) {
-    this.name = name;
-    this.provides = provides;
-    this.dependsOn = dependsOn;
+  DBeanContext(List<BeanLifecycle> lifecycleList, DBeanMap beans) {
     this.lifecycleList = lifecycleList;
     this.beans = beans;
-    this.children = children;
-  }
-
-  @Override
-  public String getName() {
-    return name;
-  }
-
-  @Override
-  public String[] getProvides() {
-    return provides;
-  }
-
-  @Override
-  public String[] getDependsOn() {
-    return dependsOn;
   }
 
   @Override
@@ -67,9 +37,6 @@ class DBeanContext implements BeanContext {
     // sort candidates by priority - Primary, Normal, Secondary
     EntrySort<T> entrySort = new EntrySort<>();
     entrySort.add(beans.candidate(type, name));
-    for (BeanContext childContext : children.values()) {
-      entrySort.add(childContext.candidate(type, name));
-    }
     return entrySort.get();
   }
 
@@ -83,9 +50,6 @@ class DBeanContext implements BeanContext {
   public <T> List<T> getBeans(Class<T> interfaceType) {
     List<T> list = new ArrayList<>();
     beans.addAll(interfaceType, list);
-    for (BeanContext childContext : children.values()) {
-      list.addAll(childContext.getBeans(interfaceType));
-    }
     return list;
   }
 
@@ -133,9 +97,6 @@ class DBeanContext implements BeanContext {
   public List<Object> getBeansWithAnnotation(Class<?> annotation) {
     List<Object> list = new ArrayList<>();
     beans.addAll(annotation, list);
-    for (BeanContext childContext : children.values()) {
-      list.addAll(childContext.getBeansWithAnnotation(annotation));
-    }
     return list;
   }
 
@@ -143,15 +104,10 @@ class DBeanContext implements BeanContext {
   public void start() {
     lock.lock();
     try {
-      if (name != null) {
-        log.debug("firing postConstruct on beans in context:{}", name);
-      }
+      log.trace("firing postConstruct");
       for (BeanLifecycle bean : lifecycleList) {
         bean.postConstruct();
       }
-      for (BeanContext childContext : children.values()) {
-        childContext.start();
-      }
     } finally {
       lock.unlock();
     }
@@ -164,15 +120,10 @@ class DBeanContext implements BeanContext {
       if (!closed) {
         // we only allow one call to preDestroy
         closed = true;
-        if (name != null) {
-          log.debug("firing preDestroy on beans in context:{}", name);
-        }
+        log.trace("firing preDestroy");
         for (BeanLifecycle bean : lifecycleList) {
           bean.preDestroy();
         }
-        for (BeanContext childContext : children.values()) {
-          childContext.close();
-        }
       }
     } finally {
       lock.unlock();
diff --git a/inject/src/main/java/io/avaje/inject/spi/DBuilder.java b/inject/src/main/java/io/avaje/inject/spi/DBuilder.java
index 76568e45..e11fd5ac 100644
--- a/inject/src/main/java/io/avaje/inject/spi/DBuilder.java
+++ b/inject/src/main/java/io/avaje/inject/spi/DBuilder.java
@@ -2,23 +2,13 @@ package io.avaje.inject.spi;
 
 import io.avaje.inject.BeanContext;
 import io.avaje.inject.BeanEntry;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import jakarta.inject.Provider;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
+
+import java.util.*;
 import java.util.function.Consumer;
 
 class DBuilder implements Builder {
 
-  private static final Logger log = LoggerFactory.getLogger(DBuilder.class);
-
   /**
    * List of Lifecycle beans.
    */
@@ -34,23 +24,6 @@ class DBuilder implements Builder {
    */
   final DBeanMap beanMap = new DBeanMap();
 
-  /**
-   * The context/module name.
-   */
-  private final String name;
-
-  /**
-   * The module features this context provides.
-   */
-  private final String[] provides;
-
-  /**
-   * The other modules this context dependsOn (that should be built prior).
-   */
-  private final String[] dependsOn;
-
-  private final Map<String, BeanContext> children = new LinkedHashMap<>();
-
   /**
    * Debug of the current bean being wired - used in injection errors.
    */
@@ -61,46 +34,6 @@ class DBuilder implements Builder {
    */
   private boolean runningPostConstruct;
 
-  Builder parent;
-
-  /**
-   * Create a named context for non-root builders.
-   */
-  DBuilder(String name, String[] provides, String[] dependsOn) {
-    this.name = name;
-    this.provides = provides;
-    this.dependsOn = dependsOn;
-  }
-
-  /**
-   * Create for the root builder.
-   */
-  DBuilder() {
-    this.name = null;
-    this.provides = null;
-    this.dependsOn = null;
-  }
-
-  @Override
-  public String getName() {
-    return name;
-  }
-
-  @Override
-  public String[] getProvides() {
-    return provides;
-  }
-
-  @Override
-  public String[] getDependsOn() {
-    return dependsOn;
-  }
-
-  @Override
-  public void setParent(Builder parent) {
-    this.parent = parent;
-  }
-
   @Override
   public boolean isAddBeanFor(Class<?>... types) {
     return isAddBeanFor(null, types);
@@ -108,12 +41,13 @@ class DBuilder implements Builder {
 
   @Override
   public boolean isAddBeanFor(String name, Class<?>... types) {
+    next(name, types);
+    return true;
+  }
+
+  protected void next(String name, Class<?>... types) {
+    injectTarget = firstOf(types);
     beanMap.nextBean(name, types);
-    if (parent == null) {
-      return true;
-    }
-    this.injectTarget = firstOf(types);
-    return parent.isAddBeanFor(name, types);
   }
 
   private Class<?> firstOf(Class<?>[] types) {
@@ -130,12 +64,6 @@ class DBuilder implements Builder {
   public <T> List<T> getList(Class<T> interfaceType) {
     List list = new ArrayList<>();
     beanMap.addAll(interfaceType, list);
-    for (BeanContext childContext : children.values()) {
-      list.addAll(childContext.getBeansWithAnnotation(interfaceType));
-    }
-    if (parent != null) {
-      list.addAll(parent.getList(interfaceType));
-    }
     return (List<T>) list;
   }
 
@@ -143,13 +71,6 @@ class DBuilder implements Builder {
   public <T> BeanEntry<T> candidate(Class<T> cls, String name) {
     DBeanContext.EntrySort<T> entrySort = new DBeanContext.EntrySort<>();
     entrySort.add(beanMap.candidate(cls, name));
-    for (BeanContext childContext : children.values()) {
-      entrySort.add(childContext.candidate(cls, name));
-    }
-    if (parent != null) {
-      // look in parent context (cross-module dependency)
-      entrySort.add(parent.candidate(cls, name));
-    }
     return entrySort.get();
   }
 
@@ -158,12 +79,6 @@ class DBuilder implements Builder {
     return (entry == null) ? null : entry.getBean();
   }
 
-  @Override
-  public void addChild(BeanContextFactory factory) {
-    final BeanContext context = factory.createContext(this);
-    children.put(context.getName(), context);
-  }
-
   /**
    * Return the bean to register potentially with spy enhancement.
    */
@@ -189,10 +104,7 @@ class DBuilder implements Builder {
   }
 
   private <T> T register(int flag, T bean) {
-    if (parent != null) {
-      // enrichment only exist on top level builder
-      bean = parent.enrich(bean, beanMap.types());
-    }
+    bean = enrich(bean, beanMap.types());
     beanMap.register(flag, bean);
     return bean;
   }
@@ -267,9 +179,6 @@ class DBuilder implements Builder {
   }
 
   private void runInjectors() {
-    if (name != null) {
-      log.debug("perform field injection in context:{}", name);
-    }
     runningPostConstruct = true;
     for (Consumer<Builder> injector : injectors) {
       injector.accept(this);
@@ -278,6 +187,6 @@ class DBuilder implements Builder {
 
   public BeanContext build() {
     runInjectors();
-    return new DBeanContext(name, provides, dependsOn, lifecycleList, beanMap, children);
+    return new DBeanContext(lifecycleList, beanMap);
   }
 }
diff --git a/inject/src/main/java/io/avaje/inject/spi/DBuilderExtn.java b/inject/src/main/java/io/avaje/inject/spi/DBuilderExtn.java
index dff471db..21c07592 100644
--- a/inject/src/main/java/io/avaje/inject/spi/DBuilderExtn.java
+++ b/inject/src/main/java/io/avaje/inject/spi/DBuilderExtn.java
@@ -28,13 +28,9 @@ class DBuilderExtn extends DBuilder {
     }
   }
 
-  @Override
-  public boolean isAddBeanFor(Class<?>... types) {
-    return isAddBeanFor(null, types);
-  }
-
   @Override
   public boolean isAddBeanFor(String qualifierName, Class<?>... types) {
+    next(qualifierName, types);
     if (hasSuppliedBeans) {
       return !beanMap.isSupplied(qualifierName, types);
     }


Test patch:
diff --git a/inject-test/src/test/java/io/avaje/inject/BeanContextBuilderTest.java b/inject-test/src/test/java/io/avaje/inject/BeanContextBuilderTest.java
index 8fc7e752..49297b15 100644
--- a/inject-test/src/test/java/io/avaje/inject/BeanContextBuilderTest.java
+++ b/inject-test/src/test/java/io/avaje/inject/BeanContextBuilderTest.java
@@ -128,8 +128,8 @@ public class BeanContextBuilderTest {
     }
 
     @Override
-    public BeanContext createContext(Builder parent) {
-      return null;
+    public void build(Builder parent) {
+
     }
   }
 }
diff --git a/inject/src/test/java/io/avaje/inject/BeanContextBuilderTest.java b/inject/src/test/java/io/avaje/inject/BeanContextBuilderTest.java
index 8fc7e752..49297b15 100644
--- a/inject/src/test/java/io/avaje/inject/BeanContextBuilderTest.java
+++ b/inject/src/test/java/io/avaje/inject/BeanContextBuilderTest.java
@@ -128,8 +128,8 @@ public class BeanContextBuilderTest {
     }
 
     @Override
-    public BeanContext createContext(Builder parent) {
-      return null;
+    public void build(Builder parent) {
+
     }
   }
 }