All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.datakernel.di.core.BindingGenerator Maven / Gradle / Ivy

Go to download

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.

The newest version!
package io.datakernel.di.core;

import io.datakernel.di.impl.BindingLocator;
import io.datakernel.di.util.Types;
import org.jetbrains.annotations.Nullable;

import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static java.util.stream.Collectors.toSet;

/**
 * This is a function that can try to generate a missing dependency binding when
 * {@link Injector} compiles the final binding graph trie.
 * 

* An example of such function could be {@link io.datakernel.di.util.ReflectionUtils#generateImplicitBinding the injection DSL}. * * @see Injector#compile */ @FunctionalInterface public interface BindingGenerator { BindingGenerator REFUSING = (bindings, scope, key) -> null; @Nullable Binding generate(BindingLocator bindings, Scope[] scope, Key key); /** * Default generator that never generates anything. */ @SuppressWarnings("unchecked") static BindingGenerator refusing() { return (BindingGenerator) REFUSING; } /** * Modules export a multimap of binding generators with raw class keys. *

* This generator aggregates such map into one big generator to be used by {@link Injector#compile} method. * For each requested key, a set of generators is fetched based on its raw class. * All generators from this set are then called and if one and only one of them generated a binding then this * binding is returned. * When nobody generated a binding then combined generator didn't as well, and it is considered an error when more than one did. *

* When raw class of the requested key is an interface, it is matched by equality, and when it is some class then generator of its closest superclass * will be called. *

* Be aware of that when creating generators for some concrete classes: usually they are made for interfaces or for final classes. * * @throws DIException when more than one generator provides a binding for given key */ @SuppressWarnings("unchecked") static BindingGenerator combinedGenerator(Map, Set>> generators) { return (bindings, scope, key) -> { Class rawType = key.getRawType(); Class generatorKey = rawType.isInterface() ? rawType : Types.findClosestAncestor(rawType, generators.keySet()); if (generatorKey == null) { return null; } Set> found = generators.get(generatorKey); if (found == null) { return null; } Set> generatedBindings = found.stream() .map(generator -> ((BindingGenerator) generator).generate(bindings, scope, key)) .filter(Objects::nonNull) .collect(toSet()); switch (generatedBindings.size()) { case 0: return null; case 1: return generatedBindings.iterator().next(); default: throw new DIException("More than one generator provided a binding for key " + key.getDisplayString()); } }; } }