-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5982257
commit 91d737a
Showing
14 changed files
with
745 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package newdicontainer; | ||
|
||
import java.util.function.Supplier; | ||
|
||
import dicontainer.DiException; | ||
import newdicontainer.annotation.Dependency; | ||
import newdicontainer.dictionary.ConstructionPolicy; | ||
import newdicontainer.dictionary.DiDictionary; | ||
import newdicontainer.resolver.DiResolver; | ||
|
||
public final class DiContainer | ||
{ | ||
private final DiDictionary diDictionary; | ||
private final DiResolver diResolver; | ||
|
||
public DiContainer() | ||
{ | ||
diDictionary = new DiDictionary(); | ||
diResolver = new DiResolver(diDictionary); | ||
} | ||
|
||
/** | ||
* Register concrete type for construction in the container. | ||
* @param type type class | ||
* @return {@code this} for method chaining | ||
*/ | ||
public <T> DiContainer registerConstruction(Class<T> type) | ||
{ | ||
diDictionary.addType(type, ConstructionPolicy.CONSTRUCT, null); | ||
return this; | ||
} | ||
|
||
/** | ||
* Register concrete type for construction with builder in the container. | ||
* @param type type class | ||
* @param builder builder function of instance | ||
* @return {@code this} for method chaining | ||
*/ | ||
public <T> DiContainer registerConstruction(Class<T> type, Supplier<T> builder) | ||
{ | ||
diDictionary.addType(type, ConstructionPolicy.CONSTRUCT, builder); | ||
return this; | ||
} | ||
|
||
/** | ||
* Register supertype for construction of its subtype in the container. | ||
* @param supertype supertype class | ||
* @param subtype subtype class | ||
* @return {@code this} for method chaining | ||
*/ | ||
public <T> DiContainer registerConstruction(Class<T> supertype, Class<? extends T> subtype) | ||
{ | ||
diDictionary.addType(supertype, subtype, ConstructionPolicy.CONSTRUCT); | ||
return this; | ||
} | ||
|
||
/** | ||
* Register concrete type as singleton in the container. | ||
* @param type type class | ||
* @return {@code this} for method chaining | ||
*/ | ||
public <T> DiContainer registerSingleton(Class<T> type) | ||
{ | ||
diDictionary.addType(type, ConstructionPolicy.SINGLETON, null); | ||
return this; | ||
} | ||
|
||
/** | ||
* Register concrete type as singleton in the container. | ||
* @param type type class | ||
* @return {@code this} for method chaining | ||
*/ | ||
public <T> DiContainer registerSingleton(Class<T> type, Supplier<T> builder) | ||
{ | ||
diDictionary.addType(type, ConstructionPolicy.SINGLETON, builder); | ||
return this; | ||
} | ||
|
||
/** | ||
* Register supertype as singleton of its subtype in the container. | ||
* @param supertype supertype class | ||
* @param subtype subtype class | ||
* @return {@code this} for method chaining | ||
*/ | ||
public <T> DiContainer registerSingleton( | ||
Class<T> supertype, Class<? extends T> subtype) | ||
{ | ||
diDictionary.addType(supertype, subtype, ConstructionPolicy.SINGLETON); | ||
return this; | ||
} | ||
|
||
/** | ||
* Register concrete instance as singleton of its type in the container. | ||
* @param type type class | ||
* @param instance concrete instance | ||
* @return {@code this} for method chaining | ||
*/ | ||
public <T> DiContainer registerInstance(Class<T> type, T instance) | ||
{ | ||
diDictionary.addInstance(type, instance); | ||
return this; | ||
} | ||
|
||
/** | ||
* Resolve all dependencies and construct a new instance of given type using {@link Dependency}. | ||
* @param type type class | ||
* @return new instance | ||
* @throws DiException if type cannot be resolved | ||
*/ | ||
public <T> T resolve(Class<T> type) | ||
{ | ||
return diResolver.construct(type); | ||
} | ||
|
||
/** | ||
* Resolve all dependencies and construct a new instance of given type using {@link Dependency}. | ||
* @param type type class | ||
* @return new instance, or {@code null} if type cannot be resolved. | ||
*/ | ||
public <T> T resolveOrNull(Class<T> type) | ||
{ | ||
try | ||
{ | ||
return resolve(type); | ||
} | ||
catch(DiException ex) | ||
{ | ||
return null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package newdicontainer.annotation; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Documented | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD}) | ||
public @interface Dependency | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package newdicontainer.annotation; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
import newdicontainer.dictionary.ConstructionPolicy; | ||
|
||
@Documented | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.TYPE) | ||
public @interface Register | ||
{ | ||
Class<?> value(); | ||
|
||
ConstructionPolicy policy() default ConstructionPolicy.CONSTRUCT; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package newdicontainer.annotation; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
import newdicontainer.dictionary.ConstructionPolicy; | ||
|
||
@Documented | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.TYPE) | ||
public @interface SelfRegister | ||
{ | ||
ConstructionPolicy policy() default ConstructionPolicy.CONSTRUCT; | ||
} |
6 changes: 6 additions & 0 deletions
6
src/main/java/newdicontainer/dictionary/ConstructionPolicy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package newdicontainer.dictionary; | ||
|
||
public enum ConstructionPolicy | ||
{ | ||
CONSTRUCT, SINGLETON | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package newdicontainer.dictionary; | ||
|
||
import java.util.function.Supplier; | ||
|
||
import dicontainer.dictionary.exception.RegistrationException; | ||
import dicontainer.dictionary.valuetypes.Instance; | ||
import newdicontainer.dictionary.valuetypes.Subtype; | ||
|
||
public class DiDictionary | ||
{ | ||
private final TypesDictionary typesDictionary = new TypesDictionary(); | ||
private final InstancesDictionary instancesDictionary = new InstancesDictionary(); | ||
|
||
public <T> void addType(Class<T> type, ConstructionPolicy policy, Supplier<T> builder) | ||
{ | ||
validateRegisteredType(type); | ||
typesDictionary.insert(type, policy, builder); | ||
} | ||
|
||
public <T> void addType(Class<T> type, Class<? extends T> subtype, ConstructionPolicy policy) | ||
{ | ||
validateRegisteredType(type); | ||
typesDictionary.insert(type, subtype, policy); | ||
} | ||
|
||
public <T> void addInstance(Class<T> type, T instance) | ||
{ | ||
validateRegisteredInstance(type); | ||
typesDictionary.insert(type, ConstructionPolicy.SINGLETON, null); | ||
instancesDictionary.insert(type, instance); | ||
} | ||
|
||
public <T> void addSingletonInstance(Class<T> type, T instance) | ||
{ | ||
instancesDictionary.insert(type, instance); | ||
} | ||
|
||
public <T> Subtype<? extends T> findType(Class<T> type) | ||
{ | ||
return typesDictionary.find(type); | ||
} | ||
|
||
public <T> Instance<T> findInstance(Class<T> type) | ||
{ | ||
return instancesDictionary.get(type); | ||
} | ||
|
||
public boolean contains(Class<?> type) | ||
{ | ||
return typesDictionary.contains(type); | ||
} | ||
|
||
private <T> void validateRegisteredType(Class<T> type) | ||
{ | ||
if(type.isPrimitive()) | ||
throw new RegistrationException("Cannot register a primitive type"); | ||
|
||
if(instancesDictionary.contains(type)) | ||
throw new RegistrationException( | ||
String.format("Type %s was registered with an instance", type.getName())); | ||
} | ||
|
||
private <T> void validateRegisteredInstance(Class<T> type) | ||
{ | ||
if(TypesUtils.isAnnotatedType(type)) | ||
throw new RegistrationException( | ||
String.format("Cannot register instance for annotated type %s", | ||
type.getName())); | ||
|
||
if(typesDictionary.contains(type)) | ||
throw new RegistrationException( | ||
String.format("Type %s was registered with another type", type.getName())); | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
src/main/java/newdicontainer/dictionary/InstancesDictionary.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package newdicontainer.dictionary; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import dicontainer.dictionary.valuetypes.Instance; | ||
|
||
class InstancesDictionary | ||
{ | ||
private final Map<Class<?>, Instance<?>> instances = new HashMap<>(); | ||
|
||
<T> void insert(Class<T> type, T instance) | ||
{ | ||
TypesUtils.requireNonNull(instance); | ||
instances.put(type, Instance.of(instance)); | ||
} | ||
|
||
boolean contains(Class<?> type) | ||
{ | ||
return instances.containsKey(type); | ||
} | ||
|
||
<T> Instance<T> get(Class<T> type) | ||
{ | ||
return Instance.cast(instances.get(type)); | ||
} | ||
} |
Oops, something went wrong.