Lightweight dependency injection framework for Java 8 and above that eliminates factories and the use of 'new' through @Inject annotation
—
Type-safe dependency identification system supporting generic types and binding annotations for distinguishing multiple bindings of the same type.
Identifies a dependency that can be resolved by the Injector, combining type information with optional binding annotations.
/**
* Identifies a dependency that can be resolved by the Injector.
* A key is composed of a type and optional binding annotation.
* @param <T> Type of the dependency
*/
public class Key<T> {
/**
* Creates a key for the given type.
* @param type Class type
* @return Key for the type
*/
public static <T> Key<T> get(Class<T> type);
/**
* Creates a key for the given type with annotation type.
* @param type Class type
* @param annotationType Binding annotation type
* @return Key for the type with annotation
*/
public static <T> Key<T> get(Class<T> type, Class<? extends Annotation> annotationType);
/**
* Creates a key for the given type with annotation instance.
* @param type Class type
* @param annotation Binding annotation instance
* @return Key for the type with annotation
*/
public static <T> Key<T> get(Class<T> type, Annotation annotation);
/**
* Creates a key for the given type.
* @param type Type instance
* @return Key for the type
*/
public static Key<?> get(Type type);
/**
* Creates a key for the given type with annotation type.
* @param type Type instance
* @param annotationType Binding annotation type
* @return Key for the type with annotation
*/
public static Key<?> get(Type type, Class<? extends Annotation> annotationType);
/**
* Creates a key for the given type with annotation instance.
* @param type Type instance
* @param annotation Binding annotation instance
* @return Key for the type with annotation
*/
public static Key<?> get(Type type, Annotation annotation);
/**
* Creates a key for the given type literal.
* @param typeLiteral Type literal
* @return Key for the type literal
*/
public static <T> Key<T> get(TypeLiteral<T> typeLiteral);
/**
* Creates a key for the given type literal with annotation type.
* @param typeLiteral Type literal
* @param annotationType Binding annotation type
* @return Key for the type literal with annotation
*/
public static <T> Key<T> get(TypeLiteral<T> typeLiteral, Class<? extends Annotation> annotationType);
/**
* Creates a key for the given type literal with annotation instance.
* @param typeLiteral Type literal
* @param annotation Binding annotation instance
* @return Key for the type literal with annotation
*/
public static <T> Key<T> get(TypeLiteral<T> typeLiteral, Annotation annotation);
/**
* Returns the type literal for this key.
* @return TypeLiteral representing the type
*/
public TypeLiteral<T> getTypeLiteral();
/**
* Returns the binding annotation type, or null if none.
* @return Annotation type or null
*/
public Class<? extends Annotation> getAnnotationType();
/**
* Returns the binding annotation instance, or null if none.
* @return Annotation instance or null
*/
public Annotation getAnnotation();
/**
* Creates a new key with the same annotation but different type.
* @param type New type
* @return Key with new type
*/
public <U> Key<U> ofType(Class<U> type);
/**
* Creates a new key with the same annotation but different type.
* @param type New type
* @return Key with new type
* @since 3.0
*/
public Key<?> ofType(Type type);
/**
* Creates a new key with the same annotation but different type literal.
* @param typeLiteral New type literal
* @return Key with new type literal
* @since 3.0
*/
public <U> Key<U> ofType(TypeLiteral<U> typeLiteral);
/**
* Returns a new key of the same type with the specified annotation.
* @param annotationType Annotation type to use
* @return Key with specified annotation
* @since 5.0
*/
public Key<T> withAnnotation(Class<? extends Annotation> annotationType);
/**
* Returns a new key of the same type with the specified annotation.
* @param annotation Annotation instance to use
* @return Key with specified annotation
* @since 5.0
*/
public Key<T> withAnnotation(Annotation annotation);
/**
* Returns true if this key has binding annotation attributes.
* @return true if annotated
*/
public boolean hasAttributes();
/**
* Returns a key without annotation attributes.
* @return Key without attributes
*/
public Key<T> withoutAttributes();
}Usage Examples:
import com.google.inject.*;
import com.google.inject.name.*;
// Simple type keys
Key<String> stringKey = Key.get(String.class);
Key<DatabaseService> dbKey = Key.get(DatabaseService.class);
// Generic type keys
Key<List<String>> listKey = Key.get(new TypeLiteral<List<String>>() {});
Key<Map<String, Object>> mapKey = Key.get(new TypeLiteral<Map<String, Object>>() {});
// Keys with annotations
Key<String> namedKey = Key.get(String.class, Names.named("database.url"));
Key<Cache> primaryCache = Key.get(Cache.class, Names.named("primary"));
// Custom annotation keys
Key<Logger> loggerKey = Key.get(Logger.class, LoggerFor.class);
// Using keys with injector
DatabaseService db = injector.getInstance(Key.get(DatabaseService.class));
String dbUrl = injector.getInstance(Key.get(String.class, Names.named("database.url")));
List<String> items = injector.getInstance(Key.get(new TypeLiteral<List<String>>() {}));Represents generic types at runtime, overcoming Java's type erasure limitations.
/**
* Represents a generic type T. Java doesn't yet provide a way to represent
* generic types, so this class does. Forces clients to create a subclass
* which enables retrieval of the type information even at runtime.
* @param <T> Generic type
*/
public class TypeLiteral<T> {
/**
* Creates a type literal for the given class.
* @param type Class type
* @return TypeLiteral for the class
*/
public static <T> TypeLiteral<T> get(Class<T> type);
/**
* Creates a type literal for the given type.
* @param type Type instance
* @return TypeLiteral for the type
*/
public static TypeLiteral<?> get(Type type);
/**
* Returns the raw (non-generic) type for this type.
* @return Raw type
*/
public Class<? super T> getRawType();
/**
* Returns the underlying Type instance.
* @return Type instance
*/
public Type getType();
/**
* Returns the generic form of supertype. For example, if this is
* ArrayList<String>, this returns Iterable<String> given the input Iterable.class.
* @param supertype a superclass of, or interface implemented by, this
* @return TypeLiteral for the supertype
* @since 2.0
*/
public TypeLiteral<?> getSupertype(Class<?> supertype);
/**
* Returns the resolved generic type of field.
* @param field a field defined by this or any superclass
* @return TypeLiteral for the field type
* @since 2.0
*/
public TypeLiteral<?> getFieldType(Field field);
/**
* Returns the resolved generic parameter types of methodOrConstructor.
* @param methodOrConstructor a method or constructor defined by this or any supertype
* @return List of TypeLiterals for parameter types
* @since 2.0
*/
public List<TypeLiteral<?>> getParameterTypes(Member methodOrConstructor);
/**
* Returns the resolved generic exception types thrown by methodOrConstructor.
* @param methodOrConstructor a method or constructor defined by this or any supertype
* @return List of TypeLiterals for exception types
* @since 2.0
*/
public List<TypeLiteral<?>> getExceptionTypes(Member methodOrConstructor);
/**
* Returns the resolved generic return type of method.
* @param method a method defined by this or any supertype
* @return TypeLiteral for the return type
* @since 2.0
*/
public TypeLiteral<?> getReturnType(Method method);
}Usage Examples:
import com.google.inject.*;
import java.util.*;
// Create type literals for generic types
TypeLiteral<List<String>> stringListType = new TypeLiteral<List<String>>() {};
TypeLiteral<Map<String, Integer>> mapType = new TypeLiteral<Map<String, Integer>>() {};
TypeLiteral<Set<User>> userSetType = new TypeLiteral<Set<User>>() {};
// Use with binding
public class CollectionModule extends AbstractModule {
@Override
protected void configure() {
bind(new TypeLiteral<List<String>>() {})
.toInstance(Arrays.asList("item1", "item2", "item3"));
bind(new TypeLiteral<Map<String, Integer>>() {})
.toProvider(ConfigMapProvider.class);
}
}
// Get instances using type literals
List<String> strings = injector.getInstance(Key.get(new TypeLiteral<List<String>>() {}));
Map<String, Integer> config = injector.getInstance(Key.get(new TypeLiteral<Map<String, Integer>>() {}));
// Provider methods with type literals
@Provides
List<DatabaseConnection> provideConnections() {
return Arrays.asList(
createConnection("primary"),
createConnection("secondary")
);
}// Binding collections
public class CollectionModule extends AbstractModule {
@Override
protected void configure() {
// Bind specific collection types
bind(new TypeLiteral<List<String>>() {})
.annotatedWith(Names.named("urls"))
.toInstance(Arrays.asList("http://api1.com", "http://api2.com"));
bind(new TypeLiteral<Map<String, DatabaseConfig>>() {})
.toProvider(DatabaseConfigProvider.class)
.in(Singleton.class);
}
}
// Injecting collections
public class ApiClient {
private final List<String> apiUrls;
private final Map<String, DatabaseConfig> dbConfigs;
@Inject
public ApiClient(
@Named("urls") List<String> apiUrls,
Map<String, DatabaseConfig> dbConfigs
) {
this.apiUrls = apiUrls;
this.dbConfigs = dbConfigs;
}
}// Wildcard type literals
TypeLiteral<List<? extends Animal>> animalList = new TypeLiteral<List<? extends Animal>>() {};
TypeLiteral<Map<String, ? super Number>> numberMap = new TypeLiteral<Map<String, ? super Number>>() {};
// Bounded type parameters
public class GenericService<T extends Serializable> {
// Implementation
}
// Binding generic services
bind(new TypeLiteral<GenericService<User>>() {})
.to(new TypeLiteral<UserGenericService>() {});// From TypeLiteral to Key
TypeLiteral<List<String>> typeLiteral = new TypeLiteral<List<String>>() {};
Key<List<String>> key = Key.get(typeLiteral);
// From Key to TypeLiteral
Key<Map<String, Object>> mapKey = Key.get(new TypeLiteral<Map<String, Object>>() {});
TypeLiteral<Map<String, Object>> extracted = mapKey.getTypeLiteral();
// Working with generic type information
Type type = typeLiteral.getType();
Class<?> rawType = typeLiteral.getRawType(); // Returns List.class
// Type equality
TypeLiteral<List<String>> type1 = new TypeLiteral<List<String>>() {};
TypeLiteral<List<String>> type2 = new TypeLiteral<List<String>>() {};
boolean equal = type1.equals(type2); // trueInstall with Tessl CLI
npx tessl i tessl/maven-com-google-inject--guice