io.datakernel.di.core.Binding Maven / Gradle / Ivy
Show all versions of datakernel-di Show documentation
package io.datakernel.di.core;
import io.datakernel.di.impl.*;
import io.datakernel.di.util.Constructors.*;
import io.datakernel.di.util.LocationInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.function.*;
import java.util.stream.Stream;
import static io.datakernel.di.util.Utils.union;
import static java.util.Arrays.asList;
import static java.util.Collections.*;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toSet;
/**
* A binding is one of the main components of DataKernel DI.
* It boils down to "introspectable function", since it only describes
* a {@link BindingCompiler function} to create an instance of T from an array of objects and
* an array of its {@link Dependency dependencies} in known terms.
*
* Also it contains a set of {@link io.datakernel.di.module.AbstractModule binding-DSL-like} static factory methods
* as well as some functional transformations for the ease of creating immutable binding modifications.
*/
@SuppressWarnings({"unused", "WeakerAccess", "ArraysAsListWithZeroOrOneArgument", "Convert2Lambda"})
public final class Binding {
private final Set dependencies;
private final BindingCompiler compiler;
@Nullable
private LocationInfo location;
public Binding(@NotNull Set dependencies, @NotNull BindingCompiler compiler) {
this(dependencies, compiler, null);
}
private Binding(@NotNull Set dependencies, @NotNull BindingCompiler compiler, @Nullable LocationInfo location) {
this.dependencies = dependencies;
this.compiler = compiler;
this.location = location;
}
public static Binding toInstance(@NotNull T instance) {
return new Binding<>(emptySet(),
(compiledBindings, threadsafe, scope, slot) ->
slot != null ?
new CompiledBinding() {
@SuppressWarnings("unchecked")
@Override
public T getInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
scopedInstances[scope].lazySet(slot, instance);
return instance;
}
} :
new CompiledBinding() {
@Override
public T getInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return instance;
}
});
}
public static Binding toSupplier(@NotNull Key extends Supplier extends T>> supplierKey) {
return Binding.to(Supplier::get, supplierKey);
}
public static Binding toSupplier(@NotNull Class extends Supplier extends T>> supplierType) {
return Binding.to(Supplier::get, supplierType);
}
// region Various Binding.to(...) overloads
public static Binding to(Class extends T> key) {
return Binding.to(Key.of(key));
}
public static Binding to(Key extends T> key) {
return new Binding<>(singleton(Dependency.toKey(key)), new PlainCompiler<>(key));
}
public static Binding to(@NotNull ConstructorN constructor, @NotNull Class>[] types) {
return Binding.to(constructor, Stream.of(types).map(Key::of).map(Dependency::toKey).toArray(Dependency[]::new));
}
public static Binding to(@NotNull ConstructorN constructor, @NotNull Key>[] keys) {
return Binding.to(constructor, Stream.of(keys).map(Dependency::toKey).toArray(Dependency[]::new));
}
@SuppressWarnings("Duplicates")
public static Binding to(@NotNull ConstructorN constructor, @NotNull Dependency[] dependencies) {
if (dependencies.length == 0) {
return to(constructor::create);
}
return new Binding<>(new HashSet<>(asList(dependencies)),
(compiledBindings, threadsafe, scope, slot) -> {
final CompiledBinding>[] bindings = Arrays.stream(dependencies)
.map(dependency -> compiledBindings.get(dependency.getKey()))
.toArray(CompiledBinding[]::new);
return slot != null ? threadsafe ? scope == 0 ?
new AbstractRootCompiledBinding(slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
Object[] args = new Object[bindings.length];
for (int i = 0; i < bindings.length; i++) {
args[i] = bindings[i].getInstance(scopedInstances, synchronizedScope);
}
return constructor.create(args);
}
} :
new AbstractCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
Object[] args = new Object[bindings.length];
for (int i = 0; i < bindings.length; i++) {
args[i] = bindings[i].getInstance(scopedInstances, synchronizedScope);
}
return constructor.create(args);
}
} :
new AbstractUnsyncCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
Object[] args = new Object[bindings.length];
for (int i = 0; i < bindings.length; i++) {
args[i] = bindings[i].getInstance(scopedInstances, synchronizedScope);
}
return constructor.create(args);
}
} :
new CompiledBinding() {
@Override
public R getInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
Object[] args = new Object[bindings.length];
for (int i = 0; i < bindings.length; i++) {
args[i] = bindings[i].getInstance(scopedInstances, synchronizedScope);
}
return constructor.create(args);
}
};
});
}
public static Binding to(@NotNull Constructor1 constructor,
@NotNull Class dependency1) {
return Binding.to(constructor, Key.of(dependency1));
}
public static Binding to(@NotNull Constructor2 constructor,
@NotNull Class dependency1, @NotNull Class dependency2) {
return Binding.to(constructor, Key.of(dependency1), Key.of(dependency2));
}
public static Binding to(@NotNull Constructor3 constructor,
@NotNull Class dependency1, @NotNull Class dependency2, @NotNull Class dependency3) {
return Binding.to(constructor, Key.of(dependency1), Key.of(dependency2), Key.of(dependency3));
}
public static Binding to(@NotNull Constructor4 constructor,
@NotNull Class dependency1, @NotNull Class dependency2, @NotNull Class dependency3, @NotNull Class dependency4) {
return Binding.to(constructor, Key.of(dependency1), Key.of(dependency2), Key.of(dependency3), Key.of(dependency4));
}
public static Binding to(@NotNull Constructor5 constructor,
@NotNull Class dependency1, @NotNull Class dependency2, @NotNull Class dependency3, @NotNull Class dependency4, @NotNull Class dependency5) {
return Binding.to(constructor, Key.of(dependency1), Key.of(dependency2), Key.of(dependency3), Key.of(dependency4), Key.of(dependency5));
}
public static Binding to(@NotNull Constructor6 constructor,
@NotNull Class dependency1, @NotNull Class dependency2, @NotNull Class dependency3, @NotNull Class dependency4, @NotNull Class dependency5, @NotNull Class dependency6) {
return Binding.to(constructor, Key.of(dependency1), Key.of(dependency2), Key.of(dependency3), Key.of(dependency4), Key.of(dependency5), Key.of(dependency6));
}
public static Binding to(@NotNull Constructor0 constructor) {
return new Binding<>(emptySet(),
(compiledBindings, threadsafe, scope, slot) ->
slot != null ? threadsafe ? scope == 0 ?
new AbstractRootCompiledBinding(slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create();
}
} :
new AbstractCompiledBinding(scope, slot) {
@Nullable
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create();
}
} :
new AbstractUnsyncCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create();
}
} :
new CompiledBinding() {
@Override
public R getInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create();
}
});
}
public static Binding to(@NotNull Constructor1 constructor,
@NotNull Key dependency1) {
return new Binding<>(new HashSet<>(asList(Dependency.toKey(dependency1))),
(compiledBindings, threadsafe, scope, slot) -> {
final CompiledBinding binding1 = compiledBindings.get(dependency1);
return slot != null ? threadsafe ? scope == 0 ?
new AbstractRootCompiledBinding(slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractUnsyncCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope));
}
} :
new CompiledBinding() {
@Override
public R getInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope));
}
};
});
}
@SuppressWarnings("Duplicates")
public static Binding to(@NotNull Constructor2 constructor,
@NotNull Key dependency1, @NotNull Key dependency2) {
return new Binding<>(new HashSet<>(asList(Dependency.toKey(dependency1), Dependency.toKey(dependency2))),
(compiledBindings, threadsafe, scope, slot) -> {
final CompiledBinding binding1 = compiledBindings.get(dependency1);
final CompiledBinding binding2 = compiledBindings.get(dependency2);
return slot != null ? threadsafe ? scope == 0 ?
new AbstractRootCompiledBinding(slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractUnsyncCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope));
}
} :
new CompiledBinding() {
@Override
public R getInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope));
}
};
});
}
@SuppressWarnings("Duplicates")
public static Binding to(@NotNull Constructor3 constructor,
@NotNull Key dependency1, @NotNull Key dependency2, @NotNull Key dependency3) {
return new Binding<>(new HashSet<>(asList(Dependency.toKey(dependency1), Dependency.toKey(dependency2), Dependency.toKey(dependency3))),
(compiledBindings, threadsafe, scope, slot) -> {
final CompiledBinding binding1 = compiledBindings.get(dependency1);
final CompiledBinding binding2 = compiledBindings.get(dependency2);
final CompiledBinding binding3 = compiledBindings.get(dependency3);
return slot != null ? threadsafe ? scope == 0 ?
new AbstractRootCompiledBinding(slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractUnsyncCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope));
}
} :
new CompiledBinding() {
@Override
public R getInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope));
}
};
});
}
@SuppressWarnings("Duplicates")
public static Binding to(@NotNull Constructor4 constructor,
@NotNull Key dependency1, @NotNull Key dependency2, @NotNull Key dependency3, @NotNull Key dependency4) {
return new Binding<>(new HashSet<>(asList(Dependency.toKey(dependency1), Dependency.toKey(dependency2), Dependency.toKey(dependency3), Dependency.toKey(dependency4))),
(compiledBindings, threadsafe, scope, slot) -> {
final CompiledBinding binding1 = compiledBindings.get(dependency1);
final CompiledBinding binding2 = compiledBindings.get(dependency2);
final CompiledBinding binding3 = compiledBindings.get(dependency3);
final CompiledBinding binding4 = compiledBindings.get(dependency4);
return slot != null ? threadsafe ? scope == 0 ?
new AbstractRootCompiledBinding(slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractUnsyncCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope));
}
} :
new CompiledBinding() {
@Override
public R getInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope));
}
};
});
}
@SuppressWarnings("Duplicates")
public static Binding to(@NotNull Constructor5 constructor,
@NotNull Key dependency1, @NotNull Key dependency2, @NotNull Key dependency3, @NotNull Key dependency4, @NotNull Key dependency5) {
return new Binding<>(new HashSet<>(asList(Dependency.toKey(dependency1), Dependency.toKey(dependency2), Dependency.toKey(dependency3), Dependency.toKey(dependency4), Dependency.toKey(dependency5))),
(compiledBindings, threadsafe, scope, slot) -> {
final CompiledBinding binding1 = compiledBindings.get(dependency1);
final CompiledBinding binding2 = compiledBindings.get(dependency2);
final CompiledBinding binding3 = compiledBindings.get(dependency3);
final CompiledBinding binding4 = compiledBindings.get(dependency4);
final CompiledBinding binding5 = compiledBindings.get(dependency5);
return slot != null ? threadsafe ? scope == 0 ?
new AbstractRootCompiledBinding(slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope),
binding5.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope),
binding5.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractUnsyncCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope),
binding5.getInstance(scopedInstances, synchronizedScope));
}
} :
new CompiledBinding() {
@Override
public R getInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope),
binding5.getInstance(scopedInstances, synchronizedScope));
}
};
});
}
@SuppressWarnings("Duplicates")
public static Binding to(@NotNull Constructor6 constructor,
@NotNull Key dependency1, @NotNull Key dependency2, @NotNull Key dependency3, @NotNull Key dependency4, @NotNull Key dependency5, @NotNull Key dependency6) {
return new Binding<>(new HashSet<>(asList(Dependency.toKey(dependency1), Dependency.toKey(dependency2), Dependency.toKey(dependency3), Dependency.toKey(dependency4), Dependency.toKey(dependency5), Dependency.toKey(dependency6))),
(compiledBindings, threadsafe, scope, slot) -> {
final CompiledBinding binding1 = compiledBindings.get(dependency1);
final CompiledBinding binding2 = compiledBindings.get(dependency2);
final CompiledBinding binding3 = compiledBindings.get(dependency3);
final CompiledBinding binding4 = compiledBindings.get(dependency4);
final CompiledBinding binding5 = compiledBindings.get(dependency5);
final CompiledBinding binding6 = compiledBindings.get(dependency6);
return slot != null ? threadsafe ? scope == 0 ?
new AbstractRootCompiledBinding(slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope),
binding5.getInstance(scopedInstances, synchronizedScope),
binding6.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope),
binding5.getInstance(scopedInstances, synchronizedScope),
binding6.getInstance(scopedInstances, synchronizedScope));
}
} :
new AbstractUnsyncCompiledBinding(scope, slot) {
@Override
protected R doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope),
binding5.getInstance(scopedInstances, synchronizedScope),
binding6.getInstance(scopedInstances, synchronizedScope));
}
} :
new CompiledBinding() {
@Override
public R getInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) {
return constructor.create(
binding1.getInstance(scopedInstances, synchronizedScope),
binding2.getInstance(scopedInstances, synchronizedScope),
binding3.getInstance(scopedInstances, synchronizedScope),
binding4.getInstance(scopedInstances, synchronizedScope),
binding5.getInstance(scopedInstances, synchronizedScope),
binding6.getInstance(scopedInstances, synchronizedScope));
}
};
});
}
// endregion
public Binding at(@Nullable LocationInfo location) {
this.location = location;
return this;
}
public Binding onInstance(@NotNull Consumer super T> consumer) {
return mapInstance(null, (args, instance) -> {
consumer.accept(instance);
return instance;
});
}
public Binding mapInstance(@NotNull Function super T, ? extends R> fn) {
return mapInstance(null, (args, instance) -> fn.apply(instance));
}
@SuppressWarnings("Duplicates")
public Binding mapInstance(@Nullable List> dependencies, @NotNull BiFunction