io.datakernel.di.module.Modules Maven / Gradle / Ivy
package io.datakernel.di.module;
import io.datakernel.di.core.*;
import io.datakernel.di.impl.BindingLocator;
import io.datakernel.di.util.Trie;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.BiFunction;
import static io.datakernel.di.core.Name.uniqueName;
import static io.datakernel.di.core.Scope.UNSCOPED;
import static io.datakernel.di.util.Utils.*;
import static java.util.Collections.emptyMap;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.*;
/**
* This class contains a set of utilities for working with {@link Module modules}.
*/
public final class Modules {
static final Module EMPTY = new SimpleModule(Trie.leaf(emptyMap()), emptyMap(), emptyMap(), emptyMap());
/**
* Combines multiple modules into one.
*/
public static Module combine(Collection modules) {
if (modules.size() == 1) {
return modules.iterator().next();
}
Trie, Set>>> bindings = Trie.merge(multimapMerger(), new HashMap<>(), modules.stream().map(Module::getBindings));
Map>> bindingTransformers = new HashMap<>();
Map, Set>> bindingGenerators = new HashMap<>();
Map, Multibinder>> multibinders = new HashMap<>();
for (Module module : modules) {
combineMultimap(bindingTransformers, module.getBindingTransformers());
combineMultimap(bindingGenerators, module.getBindingGenerators());
mergeMultibinders(multibinders, module.getMultibinders());
}
return new SimpleModule(bindings, bindingTransformers, bindingGenerators, multibinders);
}
/**
* @see #combine(Collection)
*/
public static Module combine(Module... modules) {
return modules.length == 0 ? Module.empty() : modules.length == 1 ? modules[0] : combine(Arrays.asList(modules));
}
/**
* Consecutively overrides each of the given modules with the next one after it and returns the accumulated result.
*/
public static Module override(List modules) {
return modules.stream().reduce(Module.empty(), Modules::override);
}
/**
* @see #combine(Collection)
*/
public static Module override(Module... modules) {
return override(Arrays.asList(modules));
}
/**
* This method creates a module that has bindings, transformers, generators and multibinders from first module
* replaced with bindings, transformers, generators and multibinders from the second module.
*/
public static Module override(Module into, Module replacements) {
Trie, Set>>> bindings = Trie.merge(Map::putAll, new HashMap<>(), into.getBindings(), replacements.getBindings());
Map>> bindingTransformers = new HashMap<>(into.getBindingTransformers());
bindingTransformers.putAll(replacements.getBindingTransformers());
Map, Set>> bindingGenerators = new HashMap<>(into.getBindingGenerators());
bindingGenerators.putAll(replacements.getBindingGenerators());
Map, Multibinder>> multibinders = new HashMap<>(into.getMultibinders());
multibinders.putAll(replacements.getMultibinders());
return new SimpleModule(bindings, bindingTransformers, bindingGenerators, multibinders);
}
/**
* Creates a module with all trie nodes merged into one and placed at root.
* Basically, any scopes are ignored.
* This is useful for some tests.
*/
public static Module ignoreScopes(Module from) {
Map, Set>> bindings = new HashMap<>();
Map, Scope[]> scopes = new HashMap<>();
from.getBindings().dfs(UNSCOPED, (scope, localBindings) ->
localBindings.forEach((k, b) -> {
bindings.merge(k, b, ($, $2) -> {
Scope[] alreadyThere = scopes.get(k);
String where = alreadyThere.length == 0 ? "in root" : "in scope " + getScopeDisplayString(alreadyThere);
throw new IllegalStateException("Duplicate key " + k + ", already defined " + where + " and in scope " + getScopeDisplayString(scope));
});
scopes.put(k, scope);
}));
return new SimpleModule(Trie.leaf(bindings), from.getBindingTransformers(), from.getBindingGenerators(), from.getMultibinders());
}
static Module export(Module module, Set> exportedKeys) {
Set> originalKeys = new HashSet<>();
module.getBindings().dfs(multimap -> originalKeys.addAll(multimap.keySet()));
Set> missing = new HashSet<>(exportedKeys);
missing.removeAll(originalKeys);
if (!missing.isEmpty()) {
throw new DIException(missing.stream()
.map(Key::getDisplayString)
.collect(joining(", ", "Exporting keys ", " that were not provided by the module")));
}
return doRebind(module,
originalKeys.stream()
.filter(originalKey -> !exportedKeys.contains(originalKey))
.collect(toMap(identity(), originalKey ->
Key.ofType(originalKey.getType(), uniqueName(originalKey.getName())))));
}
static Module rebindExports(Module module, Map, Key>> originalToNew) {
Set> originalKeys = new HashSet<>();
module.getBindings().dfs(multimap -> originalKeys.addAll(multimap.keySet()));
if (originalToNew.keySet().stream().noneMatch(originalKeys::contains)) {
return module;
}
return doRebind(module, originalToNew);
}
@SuppressWarnings("unchecked")
static Module rebindImports(Module module, Map, Binding>> rebinds) {
Map, Key>> originalToNew = new HashMap<>();
rebinds.forEach((k, b) -> {
Key © 2015 - 2025 Weber Informatics LLC | Privacy Policy