Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
* It stores a trie of binding graphs and a cache of already made singletons.
*
* Each injector is associated with exactly zero or one instance per {@link Key}.
*
* Injector uses binding graph at the root of the trie to recursively create and then store instances of objects
* associated with some {@link Key keys}.
* Branches of the trie are used to {@link #enterScope enter scopes}.
*/
@SuppressWarnings({"unused", "WeakerAccess"})
public final class Injector {
public static final Key>> INSTANCE_INJECTORS_KEY = new Key>>() {};
private static final class DependencyGraph {
private final Scope[] scope;
private final Map, Binding>> bindings;
private final Map, CompiledBinding>> compiledBindings;
private final Map, Integer> compiledIndexes;
private DependencyGraph(Scope[] scope, Map, Binding>> bindings, Map, CompiledBinding>> compiledBindings, Map, Integer> compiledIndexes) {
this.scope = scope;
this.bindings = bindings;
this.compiledBindings = compiledBindings;
this.compiledIndexes = compiledIndexes;
}
}
private final Map, CompiledBinding>> compiledBindings;
private final Map, Integer> compiledIndexes;
private final AtomicReferenceArray[] scopedInstances;
private final Trie scopeTree;
@Nullable
private final Injector parent;
@SuppressWarnings("unchecked")
private Injector(@Nullable Injector parent, Trie scopeTree) {
this.compiledBindings = scopeTree.get().compiledBindings;
this.compiledIndexes = scopeTree.get().compiledIndexes;
this.scopedInstances = parent == null ? new AtomicReferenceArray[1] : Arrays.copyOf(parent.scopedInstances, parent.scopedInstances.length + 1);
this.scopedInstances[this.scopedInstances.length - 1] = new AtomicReferenceArray(scopeTree.get().compiledIndexes.size());
this.scopedInstances[this.scopedInstances.length - 1].lazySet(0, this);
this.scopeTree = scopeTree;
this.parent = parent;
}
/**
* This constructor combines given modules (along with a {@link DefaultModule})
* and then {@link #compile(Injector, Module) compiles} them.
*/
public static Injector of(Module... modules) {
return compile(null, Modules.combine(Modules.combine(modules), new DefaultModule()));
}
public static Injector of(@Nullable Injector parent, Module... modules) {
return compile(parent, Modules.combine(Modules.combine(modules), new DefaultModule()));
}
/**
* This constructor is a shortcut for threadsafe {@link #compile(Injector, Scope[], Trie, Multibinder, BindingTransformer, BindingGenerator) compile}
* with no instance overrides and no multibinders, transformers or generators.
*/
public static Injector of(@NotNull Trie, Binding>>> bindings) {
return compile(null, UNSCOPED, bindings.map(Utils::toMultimap), ERROR_ON_DUPLICATE, IDENTITY, REFUSING);
}
/**
* This constructor threadsafely {@link #compile(Injector, Scope[], Trie, Multibinder, BindingTransformer, BindingGenerator) compiles}
* given module, extracting bindings and their multibinders, transformers and generators from it, with no instance overrides
*/
public static Injector compile(@Nullable Injector parent, Module module) {
return compile(parent, UNSCOPED, module.getBindings(),
combinedMultibinder(module.getMultibinders()),
combinedTransformer(module.getBindingTransformers()),
combinedGenerator(module.getBindingGenerators()));
}
/**
* The most full-fledged compile method that allows you to create an Injector of any configuration.
*
* Note that any injector always sets a binding of Injector key to provide itself.
*
* @param parent parent injector that is called when this injector cannot fulfill the request
* @param scope the scope of the injector, can be described as 'prefix of the root' of the binding trie,
* used when {@link #enterScope entering scopes}
* @param bindingsMultimap a trie of binding set graph with multiple possible conflicting bindings per key
* that are resolved as part of the compilation.
* @param multibinder a multibinder that is called on every binding conflict (see {@link Multibinder#combinedMultibinder})
* @param transformer a transformer that is called on every binding once (see {@link BindingTransformer#combinedTransformer})
* @param generator a generator that is called on every missing binding (see {@link BindingGenerator#combinedGenerator})
* @see #enterScope
*/
public static Injector compile(@Nullable Injector parent,
Scope[] scope,
@NotNull Trie, Set>>> bindingsMultimap,
@NotNull Multibinder> multibinder,
@NotNull BindingTransformer> transformer,
@NotNull BindingGenerator> generator) {
Trie, Binding>>> bindings = Preprocessor.reduce(bindingsMultimap, multibinder, transformer, generator);
Set> known = new HashSet<>();
known.add(Key.of(Injector.class)); // injector is hardcoded in and will always be present
if (parent != null) {
known.addAll(parent.compiledBindings.keySet());
}
Preprocessor.check(known, bindings);
return new Injector(parent, compileBindingsTrie(parent != null ? parent.scopedInstances.length : 0, UNSCOPED, bindings, parent != null ? parent.compiledBindings : emptyMap()));
}
protected static Trie compileBindingsTrie(int scope, Scope[] path,
Trie, Binding>>> bindingsTrie,
Map, CompiledBinding>> compiledBindingsOfParent) {
DependencyGraph dependencyGraph = compileBindings(scope, path, bindingsTrie.get(), compiledBindingsOfParent);
Map> children = new HashMap<>();
bindingsTrie.getChildren().forEach((childScope, trie) -> {
Map, CompiledBinding>> compiledBindingsCopy = new HashMap<>(compiledBindingsOfParent);
compiledBindingsCopy.putAll(dependencyGraph.compiledBindings);
children.put(childScope,
compileBindingsTrie(scope + 1, next(path, childScope), bindingsTrie.get(childScope), compiledBindingsCopy));
});
return new Trie<>(dependencyGraph, children);
}
protected static DependencyGraph compileBindings(int scope, Scope[] path,
Map, Binding>> bindings,
Map, CompiledBinding>> compiledBindingsOfParent) {
boolean threadsafe = path.length == 0 || path[path.length - 1].isThreadsafe();
Map, CompiledBinding>> compiledBindings = new HashMap<>();
Map, Integer> compiledIndexes = new HashMap<>();
compiledBindings.put(Key.of(Injector.class),
scope == 0 ?
new CompiledBinding