Skip to content

Commit

Permalink
Prepare classes for new container
Browse files Browse the repository at this point in the history
  • Loading branch information
ref-humbold committed Jul 27, 2024
1 parent 5982257 commit 91d737a
Show file tree
Hide file tree
Showing 14 changed files with 745 additions and 0 deletions.
131 changes: 131 additions & 0 deletions src/main/java/newdicontainer/DiContainer.java
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;
}
}
}
14 changes: 14 additions & 0 deletions src/main/java/newdicontainer/annotation/Dependency.java
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
{
}
19 changes: 19 additions & 0 deletions src/main/java/newdicontainer/annotation/Register.java
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;
}
17 changes: 17 additions & 0 deletions src/main/java/newdicontainer/annotation/SelfRegister.java
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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package newdicontainer.dictionary;

public enum ConstructionPolicy
{
CONSTRUCT, SINGLETON
}
74 changes: 74 additions & 0 deletions src/main/java/newdicontainer/dictionary/DiDictionary.java
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 src/main/java/newdicontainer/dictionary/InstancesDictionary.java
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));
}
}
Loading

0 comments on commit 91d737a

Please sign in to comment.