@SuppressWarnings({"unchecked", "rawtypes"})
  public Configuration build() throws BindException {
    ConfigurationModule c = deepCopy();

    if (!c.reqSet.containsAll(c.builder.reqDecl)) {
      Set<Field> missingSet = new MonotonicHashSet<>();
      for (Field f : c.builder.reqDecl) {
        if (!c.reqSet.contains(f)) {
          missingSet.add(f);
        }
      }
      throw new BindException(
          "Attempt to build configuration before setting required option(s): "
              + builder.toString(missingSet));
    }

    for (Class<?> clazz : c.builder.freeImpls.keySet()) {
      Impl<?> i = c.builder.freeImpls.get(clazz);
      if (c.setImpls.containsKey(i)) {
        c.builder.b.bind(clazz, c.setImpls.get(i));
      } else if (c.setLateImpls.containsKey(i)) {
        c.builder.b.bind(ReflectionUtilities.getFullName(clazz), c.setLateImpls.get(i));
      } else if (c.setImplSets.containsKey(i) || c.setLateImplSets.containsKey(i)) {
        for (Class<?> clz : c.setImplSets.getValuesForKey(i)) {
          c.builder.b.bindSetEntry((Class) clazz, (Class) clz);
        }
        for (String s : c.setLateImplSets.getValuesForKey(i)) {
          c.builder.b.bindSetEntry((Class) clazz, s);
        }
      } else if (c.setImplLists.containsKey(i)) {
        c.builder.b.bindList((Class) clazz, c.setImplLists.get(i));
      }
    }
    for (Class<? extends Name<?>> clazz : c.builder.freeParams.keySet()) {
      Param<?> p = c.builder.freeParams.get(clazz);
      String s = c.setParams.get(p);
      boolean foundOne = false;
      if (s != null) {
        c.builder.b.bindNamedParameter(clazz, s);
        foundOne = true;
      }
      // Find the bound list for the NamedParameter
      List list = c.setParamLists.get(p);
      if (list != null) {
        c.builder.b.bindList((Class) clazz, list);
        foundOne = true;
      }
      for (String paramStr : c.setParamSets.getValuesForKey(p)) {
        c.builder.b.bindSetEntry((Class) clazz, paramStr);
        foundOne = true;
      }
      if (!foundOne) {
        if (!(p instanceof OptionalParameter)) {
          throw new IllegalStateException();
        }
      }
    }
    return c.builder.b.build();
  }
 private ConfigurationModule deepCopy() {
   ConfigurationModule cm = new ConfigurationModule(builder.deepCopy());
   cm.setImpls.putAll(setImpls);
   cm.setImplSets.addAll(setImplSets);
   cm.setLateImplSets.addAll(setLateImplSets);
   cm.setParamSets.addAll(setParamSets);
   cm.setLateImpls.putAll(setLateImpls);
   cm.setParams.putAll(setParams);
   cm.reqSet.addAll(reqSet);
   cm.setImplLists.putAll(setImplLists);
   cm.setParamLists.putAll(setParamLists);
   return cm;
 }
 protected ConfigurationModule(ConfigurationModuleBuilder builder) {
   this.builder = builder.deepCopy();
 }