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

io.datakernel.di.core.Key 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.util.ReflectionUtils;
import io.datakernel.di.util.Types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;

import static io.datakernel.di.util.Types.ensureEquality;

/**
 * The key defines an identity of a binding. In any DI, a key is usually a type of the object along
 * with some optional tag to distinguish between bindings which make objects of the same type.
 * 

* In DataKernel DI, a key is also a type token - special abstract class that can store type information * with shortest syntax possible in Java. *

* For example, to create a key of type Map<String, List<Integer>>, you can just use * this syntax: new Key<Map<String, List<Integer>>>(){}. *

* If your types are not known at compile time, you can use {@link Types#parameterized} to make a * parameterized type and give it to a {@link #ofType Key.ofType} constructor. */ public abstract class Key { @NotNull private final Type type; @Nullable private final Name name; public Key() { this.type = ensureEquality(getTypeParameter()); this.name = null; } public Key(@Nullable Name name) { this.type = ensureEquality(getTypeParameter()); this.name = name; } public Key(@NotNull String name) { this.type = ensureEquality(getTypeParameter()); this.name = Name.of(name); } public Key(@NotNull Class annotationType) { this.type = ensureEquality(getTypeParameter()); this.name = Name.of(annotationType); } public Key(@NotNull Annotation annotation) { this.type = ensureEquality(getTypeParameter()); this.name = Name.of(annotation); } Key(@NotNull Type type, @Nullable Name name) { this.type = ensureEquality(type); this.name = name; } /** * A default subclass to be used by {@link #of Key.of*} and {@link #ofType Key.ofType*} constructors */ private static final class KeyImpl extends Key { private KeyImpl(Type type, Name name) { super(type, name); } } @NotNull public static Key of(@NotNull Class type) { return new KeyImpl<>(type, null); } @NotNull public static Key of(@NotNull Class type, @Nullable Name name) { return new KeyImpl<>(type, name); } @NotNull public static Key of(@NotNull Class type, @NotNull String name) { return new KeyImpl<>(type, Name.of(name)); } @NotNull public static Key of(@NotNull Class type, @NotNull Class annotationType) { return new KeyImpl<>(type, Name.of(annotationType)); } @NotNull public static Key of(@NotNull Class type, @NotNull Annotation annotation) { return new KeyImpl<>(type, Name.of(annotation)); } @NotNull public static Key ofType(@NotNull Type type) { return new KeyImpl<>(type, null); } @NotNull public static Key ofType(@NotNull Type type, @Nullable Name name) { return new KeyImpl<>(type, name); } @NotNull public static Key ofType(@NotNull Type type, @NotNull String name) { return new KeyImpl<>(type, Name.of(name)); } @NotNull public static Key ofType(@NotNull Type type, @NotNull Class annotationType) { return new KeyImpl<>(type, Name.of(annotationType)); } @NotNull public static Key ofType(@NotNull Type type, @NotNull Annotation annotation) { return new KeyImpl<>(type, Name.of(annotation)); } /** * Returns a new key with same type but the name replaced with a given one */ public Key named(Name name) { return new KeyImpl<>(type, name); } /** * @see #named(Name) */ public Key named(String name) { return new KeyImpl<>(type, Name.of(name)); } /** * @see #named(Name) */ public Key named(@NotNull Class annotationType) { return new KeyImpl<>(type, Name.of(annotationType)); } /** * @see #named(Name) */ public Key named(@NotNull Annotation annotation) { return new KeyImpl<>(type, Name.of(annotation)); } @NotNull private Type getTypeParameter() { // this cannot possibly fail so not even a check here return ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } @NotNull public Type getType() { return type; } /** * A shortcut for {@link Types#getRawType}(key.getType()). * Also casts the result to a properly parameterized class. */ @SuppressWarnings("unchecked") @NotNull public Class getRawType() { return (Class) Types.getRawType(type); } /** * Returns a type parameter of the underlying type wrapped as a key with no name. * * @throws IllegalStateException when underlying type is not a parameterized one. */ public Key getTypeParameter(int index) { if (type instanceof ParameterizedType) { return new KeyImpl<>(((ParameterizedType) type).getActualTypeArguments()[index], null); } throw new IllegalStateException("Expected type from key " + getDisplayString() + " to be parameterized"); } /** * Null-checked shortcut for key.getName()?.getAnnotationType(). */ @Nullable public Class getAnnotationType() { return name != null ? name.getAnnotationType() : null; } /** * Null-checked shortcut for key.getName()?.getAnnotation(). */ @Nullable public Annotation getAnnotation() { return name != null ? name.getAnnotation() : null; } @Nullable public Name getName() { return name; } /** * Returns an underlying type with display string formatting (package names stripped) * and prepended name display string if this key has a name. */ public String getDisplayString() { return (name != null ? name.getDisplayString() + " " : "") + ReflectionUtils.getDisplayName(type); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Key)) { return false; } Key that = (Key) o; return type.equals(that.type) && Objects.equals(name, that.name); } @Override public int hashCode() { return 31 * type.hashCode() + (name == null ? 0 : name.hashCode()); } @Override public String toString() { return (name != null ? name.toString() + " " : "") + type.getTypeName(); } }