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.
DataKernel has an extremely lightweight DI with ground-breaking design principles.
It supports nested scopes, singletons, object factories, modules and plugins which
allow to transform graph of dependencies at startup time without any reflection.
* 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 {
private static final class ScopeLocalData {
final Scope[] scope;
final Map, BindingInfo> bindingInfo;
final Map, CompiledBinding>> compiledBindings;
final Map, Integer> slotMapping;
final int slots;
final CompiledBinding>[] eagerSingletons;
private ScopeLocalData(
Scope[] scope,
Map, BindingInfo> bindingInfo,
Map, CompiledBinding>> compiledBindings,
Map, Integer> slotMapping,
int slots,
CompiledBinding>[] eagerSingletons
) {
this.scope = scope;
this.bindingInfo = bindingInfo;
this.compiledBindings = compiledBindings;
this.slotMapping = slotMapping;
this.slots = slots;
this.eagerSingletons = eagerSingletons;
}
}
@Nullable
final Injector parent;
final Trie scopeDataTree;
final Map, Integer> localSlotMapping;
final Map, CompiledBinding>> localCompiledBindings;
final AtomicReferenceArray[] scopeCaches;
@SuppressWarnings("unchecked")
private Injector(@Nullable Injector parent, Trie scopeDataTree) {
this.parent = parent;
this.scopeDataTree = scopeDataTree;
ScopeLocalData data = scopeDataTree.get();
this.localSlotMapping = data.slotMapping;
this.localCompiledBindings = data.compiledBindings;
AtomicReferenceArray[] scopeCaches = parent == null ?
new AtomicReferenceArray[1] :
Arrays.copyOf(parent.scopeCaches, parent.scopeCaches.length + 1);
AtomicReferenceArray localCache = new AtomicReferenceArray(data.slots);
localCache.set(0, this);
scopeCaches[scopeCaches.length - 1] = localCache;
this.scopeCaches = scopeCaches;
}
/**
* 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(map -> map.entrySet().stream().collect(toMap(Entry::getKey, entry -> new BindingSet<>(singleton(entry.getValue()), COMMON)))),
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, BindingSet>>> bindingsMultimap,
@NotNull Multibinder> multibinder,
@NotNull BindingTransformer> transformer,
@NotNull BindingGenerator> generator) {
Trie, MarkedBinding>>> 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.localCompiledBindings.keySet());
}
Trie, Binding>>> justBindings = bindings.map(m -> m.entrySet().stream().collect(toMap(Entry::getKey, e -> e.getValue().getBinding())));
Preprocessor.check(known, justBindings);
Trie scopeDataTree = compileBindingsTrie(
parent != null ? parent.scopeCaches.length : 0,
UNSCOPED,
bindings,
parent != null ? parent.localCompiledBindings : emptyMap()
);
return new Injector(parent, scopeDataTree);
}
protected static Trie compileBindingsTrie(int scope, Scope[] path,
Trie, MarkedBinding>>> bindings,
Map, CompiledBinding>> compiledBindingsOfParent) {
ScopeLocalData scopeLocalData = compileBindings(scope, path, bindings.get(), compiledBindingsOfParent);
Map> children = new HashMap<>();
bindings.getChildren().forEach((childScope, trie) -> {
Map, CompiledBinding>> compiledBindingsCopy = new HashMap<>(compiledBindingsOfParent);
compiledBindingsCopy.putAll(scopeLocalData.compiledBindings);
children.put(childScope, compileBindingsTrie(scope + 1, next(path, childScope), bindings.get(childScope), compiledBindingsCopy));
});
return new Trie<>(scopeLocalData, children);
}
@SuppressWarnings("Convert2Lambda")
protected static ScopeLocalData compileBindings(int scope, Scope[] path,
Map, MarkedBinding>> bindings,
Map, CompiledBinding>> compiledBindingsOfParent
) {
boolean threadsafe = path.length == 0 || path[path.length - 1].isThreadsafe();
Map, CompiledBinding>> compiledBindings = new HashMap<>();
compiledBindings.put(Key.of(Injector.class),
scope == 0 ?
new CompiledBinding