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

io.datakernel.di.module.DefaultModule Maven / Gradle / Ivy

package io.datakernel.di.module;

import io.datakernel.di.annotation.Inject;
import io.datakernel.di.core.*;
import io.datakernel.di.impl.AbstractCompiledBinding;
import io.datakernel.di.impl.BindingInitializer;
import io.datakernel.di.impl.CompiledBinding;
import io.datakernel.di.impl.CompiledBindingInitializer;
import io.datakernel.di.util.ReflectionUtils;
import io.datakernel.di.util.Trie;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReferenceArray;

import static io.datakernel.di.util.ReflectionUtils.generateInjectingInitializer;
import static java.util.Collections.*;

/**
 * This module provides a set of default generators.
 * 

* The first one tries to generate a binding for any missing key by searching for {@link Inject} constructors. *

* The second one generates any Key<SomeType> instance for SomeType. * Its purpose is to get reified types from generics in templated providers. *

* The last three generate appropriate instances for {@link InstanceProvider}, {@link InstanceFactory} and {@link InstanceInjector} requests. */ public final class DefaultModule implements Module { private static final Trie, Set>>> emptyTrie = Trie.leaf(new HashMap<>()); private static final Map, Set>> generators = new HashMap<>(); static { // generating bindings for classes that have @Inject constructors/factory methods generators.put(Object.class, singleton((bindings, scope, key) -> ReflectionUtils.generateImplicitBinding(key))); // generating dummy bindings for reified type requests (can be used in templated providers to get a Key instance) generators.put(Key.class, singleton((bindings, scope, key) -> Binding.toInstance(key.getTypeParameter(0)))); // generating bindings for provider requests generators.put(InstanceProvider.class, singleton( (bindings, scope, key) -> { Key instanceKey = key.getTypeParameter(0).named(key.getName()); Binding instanceBinding = bindings.get(instanceKey); if (instanceBinding == null) { return null; } return new Binding<>( emptySet(), (compiledBindings, threadsafe, synchronizedScope, index) -> new AbstractCompiledBinding(synchronizedScope, index) { @Override public InstanceProvider doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) { return new InstanceProvider() { final CompiledBinding compiledBinding = compiledBindings.get(instanceKey); @Override public Key key() { return instanceKey; } @Override public Object get() { return compiledBinding.getInstance(scopedInstances, synchronizedScope); } @Override public String toString() { return "factory of " + instanceKey.toString(); } }; } }); } )); // generating bindings for factory requests generators.put(InstanceFactory.class, singleton( (bindings, scope, key) -> { Key instanceKey = key.getTypeParameter(0).named(key.getName()); Binding instanceBinding = bindings.get(instanceKey); if (instanceBinding == null) { return (Binding) null; } return new Binding<>( emptySet(), (compiledBindings, threadsafe, synchronizedScope, index) -> new AbstractCompiledBinding(synchronizedScope, index) { @Override protected InstanceFactory doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) { return new InstanceFactory() { final CompiledBinding compiledBinding = compiledBindings.get(instanceKey); @Override public Key key() { return instanceKey; } @Override public Object create() { return compiledBinding.createInstance(scopedInstances, synchronizedScope); } @Override public String toString() { return "factory of " + instanceKey.toString(); } }; } }); } )); // generating bindings for injector requests generators.put(InstanceInjector.class, singleton( (bindings, scope, key) -> { Key instanceKey = key.getTypeParameter(0).named(key.getName()); BindingInitializer bindingInitializer = generateInjectingInitializer(instanceKey); return new Binding<>( bindingInitializer.getDependencies(), (compiledBindings, threadsafe, synchronizedScope, index) -> new AbstractCompiledBinding(synchronizedScope, index) { @Override public Object doCreateInstance(AtomicReferenceArray[] scopedInstances, int synchronizedScope) { return new InstanceInjector() { final CompiledBindingInitializer compiledBindingInitializer = bindingInitializer.getCompiler().compile(compiledBindings); @Override public Key key() { return instanceKey; } @Override public void injectInto(Object existingInstance) { compiledBindingInitializer.initInstance(existingInstance, scopedInstances, synchronizedScope); } @Override public String toString() { return "injector for " + instanceKey.toString(); } }; } } ); } )); } @Override public Trie, Set>>> getBindings() { return emptyTrie; } @Override public Map>> getBindingTransformers() { return emptyMap(); } @Override public Map, Set>> getBindingGenerators() { return generators; } @Override public Map, Multibinder> getMultibinders() { return emptyMap(); } }