Skip to content

Commit

Permalink
#48 Merge all handler subtypes into the Handler interface
Browse files Browse the repository at this point in the history
  • Loading branch information
ljacqu committed Jun 13, 2017
1 parent dc43052 commit dc87285
Show file tree
Hide file tree
Showing 31 changed files with 195 additions and 431 deletions.
72 changes: 5 additions & 67 deletions injector/src/main/java/ch/jalu/injector/InjectorBuilder.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
package ch.jalu.injector;

import ch.jalu.injector.exceptions.InjectorException;
import ch.jalu.injector.handlers.Handler;
import ch.jalu.injector.handlers.annotationvalues.AnnotationValueHandler;
import ch.jalu.injector.handlers.dependency.DependencyHandler;
import ch.jalu.injector.handlers.dependency.FactoryDependencyHandler;
import ch.jalu.injector.handlers.dependency.SavedAnnotationsHandler;
import ch.jalu.injector.handlers.dependency.SingletonStoreDependencyHandler;
import ch.jalu.injector.handlers.instantiation.DefaultInjectionProvider;
import ch.jalu.injector.handlers.instantiation.InstantiationProvider;
import ch.jalu.injector.handlers.postconstruct.PostConstructHandler;
import ch.jalu.injector.handlers.postconstruct.PostConstructMethodInvoker;
import ch.jalu.injector.handlers.preconstruct.PreConstructHandler;
import ch.jalu.injector.handlers.preconstruct.PreConstructPackageValidator;
import ch.jalu.injector.handlers.provider.ProviderHandler;
import ch.jalu.injector.handlers.provider.ProviderHandlerImpl;
import ch.jalu.injector.utils.InjectorUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
* Configures and creates an {@link Injector}.
Expand Down Expand Up @@ -66,15 +57,15 @@ public static List<Handler> createDefaultHandlers(String rootPackage) {
}

/**
* Creates all default handlers of type {@link InstantiationProvider}. Useful if you want to create your own
* Creates all default handlers implementing {@link Handler#get}. Useful if you want to create your own
* preconstruct (etc.) handlers but want to use the default instantiation providers.
* <p>
* Use {@link #createDefaultHandlers(String)} or {@link #addDefaultHandlers(String)} otherwise.
*
* @return default instantiation providers
* @since 0.1
*/
public static List<InstantiationProvider> createInstantiationProviders() {
public static List<Handler> createInstantiationProviders() {
return new ArrayList<>(Arrays.asList(
new ProviderHandlerImpl(),
new DefaultInjectionProvider()));
Expand Down Expand Up @@ -115,15 +106,8 @@ public InjectorBuilder addHandlers(Handler... handlers) {
* @return the builder
* @since 0.1
*/
public InjectorBuilder addHandlers(Iterable<? extends Handler> handlers) {
new HandlerCollector()
.registerType(AnnotationValueHandler.class, config::addAnnotationValueHandlers)
.registerType(ProviderHandler.class, config::addProviderHandlers)
.registerType(PreConstructHandler.class, config::addPreConstructHandlers)
.registerType(InstantiationProvider.class, config::addInstantiationProviders)
.registerType(DependencyHandler.class, config::addDependencyHandlers)
.registerType(PostConstructHandler.class, config::addPostConstructHandlers)
.process(handlers);
public InjectorBuilder addHandlers(Collection<? extends Handler> handlers) {
config.addHandlers(handlers);
return this;
}

Expand All @@ -136,50 +120,4 @@ public InjectorBuilder addHandlers(Iterable<? extends Handler> handlers) {
public Injector create() {
return new InjectorImpl(config);
}

@SuppressWarnings("unchecked")
private static final class HandlerCollector {

private final Map<Class, List> handlersByType = new HashMap<>();
private final Map<Class, Consumer<List>> handlerListSetters = new HashMap<>();

<T extends Handler> HandlerCollector registerType(Class<T> subType, Consumer<List<T>> handlerListSetter) {
if (handlersByType.containsKey(subType)) {
throw new IllegalStateException("Already provided " + subType);
}
handlersByType.put(subType, new ArrayList<>());
handlerListSetters.put(subType, (Consumer) handlerListSetter);
return this;
}

void process(Iterable<? extends Handler> handlers) {
for (Handler handler : handlers) {
process(handler);
}
for (Map.Entry<Class, Consumer<List>> listSetter : handlerListSetters.entrySet()) {
listSetter.getValue().accept(
handlersByType.get(listSetter.getKey()));
}
}

private void process(Handler handler) {
boolean foundSubtype = false;
for (Class subtype : handlersByType.keySet()) {
foundSubtype |= addHandler(subtype, handler);
}
if (!foundSubtype) {
throw new InjectorException(String.format("Class '%s' must extend a known Handler subtype",
handler.getClass().getName()));
}
}

private boolean addHandler(Class clazz, Handler handler) {
if (clazz.isInstance(handler)) {
handlersByType.get(clazz).add(handler);
return true;
}
return false;
}
}

}
101 changes: 8 additions & 93 deletions injector/src/main/java/ch/jalu/injector/InjectorConfig.java
Original file line number Diff line number Diff line change
@@ -1,116 +1,31 @@
package ch.jalu.injector;

import ch.jalu.injector.handlers.annotationvalues.AnnotationValueHandler;
import ch.jalu.injector.handlers.dependency.DependencyHandler;
import ch.jalu.injector.handlers.instantiation.InstantiationProvider;
import ch.jalu.injector.handlers.postconstruct.PostConstructHandler;
import ch.jalu.injector.handlers.preconstruct.PreConstructHandler;
import ch.jalu.injector.handlers.provider.ProviderHandler;
import ch.jalu.injector.handlers.Handler;
import ch.jalu.injector.utils.InjectorUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* Injector configuration.
*/
public class InjectorConfig {

// Handlers
private List<AnnotationValueHandler> annotationValueHandlers = new ArrayList<>();
private List<ProviderHandler> providerHandlers = new ArrayList<>();
private List<PreConstructHandler> preConstructHandlers = new ArrayList<>();
private List<InstantiationProvider> instantiationProviders = new ArrayList<>();
private List<DependencyHandler> dependencyHandlers = new ArrayList<>();
private List<PostConstructHandler> postConstructHandlers = new ArrayList<>();
private List<Handler> handlers = new ArrayList<>();

/**
* Use the {@link InjectorBuilder} instead of instantiating this.
*/
protected InjectorConfig() {
}

/**
* Returns all registered {@link AnnotationValueHandler} instances.
*
* @return pre construct handlers
*/
public List<AnnotationValueHandler> getAnnotationValueHandlers() {
return annotationValueHandlers;
}

/**
* Returns all registered {@link ProviderHandler} instances.
*
* @return pre construct handlers
*/
public List<ProviderHandler> getProviderHandlers() {
return providerHandlers;
}

/**
* Returns all registered {@link PreConstructHandler} instances.
*
* @return pre construct handlers
*/
public List<PreConstructHandler> getPreConstructHandlers() {
return preConstructHandlers;
}

/**
* Returns all registered {@link InstantiationProvider} instances.
*
* @return instantiation providers
*/
public List<InstantiationProvider> getInstantiationProviders() {
return instantiationProviders;
}

/**
* Returns all registered {@link DependencyHandler} instances.
*
* @return dependency handlers
*/
public List<DependencyHandler> getDependencyHandlers() {
return dependencyHandlers;
}

/**
* Returns all registered {@link PostConstructHandler} instances.
*
* @return post construct handlers
*/
public List<PostConstructHandler> getPostConstructHandlers() {
return postConstructHandlers;
}

public void addAnnotationValueHandlers(List<? extends AnnotationValueHandler> annotationValueHandlers) {
InjectorUtils.checkNotNull(annotationValueHandlers, null);
this.annotationValueHandlers.addAll(annotationValueHandlers);
}

public void addProviderHandlers(List<? extends ProviderHandler> providerHandlers) {
InjectorUtils.checkNotNull(providerHandlers, null);
this.providerHandlers.addAll(providerHandlers);
}

public void addPreConstructHandlers(List<? extends PreConstructHandler> preConstructHandlers) {
InjectorUtils.checkNotNull(preConstructHandlers, null);
this.preConstructHandlers.addAll(preConstructHandlers);
}

public void addInstantiationProviders(List<? extends InstantiationProvider> instantiationProviders) {
InjectorUtils.checkNotNull(instantiationProviders, null);
this.instantiationProviders.addAll(instantiationProviders);
}

public void addDependencyHandlers(List<? extends DependencyHandler> dependencyHandlers) {
InjectorUtils.checkNotNull(dependencyHandlers, null);
this.dependencyHandlers.addAll(dependencyHandlers);
public void addHandlers(Collection<? extends Handler> handlers) {
InjectorUtils.checkNotNull(handlers, null);
this.handlers.addAll(handlers);
}

public void addPostConstructHandlers(List<? extends PostConstructHandler> postConstructHandlers) {
InjectorUtils.checkNotNull(postConstructHandlers, null);
this.postConstructHandlers.addAll(postConstructHandlers);
public List<Handler> getHandlers() {
return handlers;
}
}
39 changes: 18 additions & 21 deletions injector/src/main/java/ch/jalu/injector/InjectorImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@
import ch.jalu.injector.context.ResolvedInstantiationContext;
import ch.jalu.injector.context.UnresolvedInstantiationContext;
import ch.jalu.injector.exceptions.InjectorException;
import ch.jalu.injector.handlers.annotationvalues.AnnotationValueHandler;
import ch.jalu.injector.handlers.dependency.DependencyHandler;
import ch.jalu.injector.handlers.Handler;
import ch.jalu.injector.handlers.instantiation.DependencyDescription;
import ch.jalu.injector.handlers.instantiation.Instantiation;
import ch.jalu.injector.handlers.instantiation.InstantiationProvider;
import ch.jalu.injector.handlers.postconstruct.PostConstructHandler;
import ch.jalu.injector.handlers.preconstruct.PreConstructHandler;
import ch.jalu.injector.handlers.provider.ProviderHandler;
import ch.jalu.injector.utils.InjectorUtils;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -68,9 +63,9 @@ public <T> void register(Class<? super T> clazz, T object) {
@Override
public void provide(Class<? extends Annotation> clazz, Object object) {
checkNotNull(clazz, "Provided annotation may not be null");
for (AnnotationValueHandler annotationValueHandler : config.getAnnotationValueHandlers()) {
for (Handler handler : config.getHandlers()) {
try {
annotationValueHandler.processProvided(clazz, object);
handler.processProvided(clazz, object);
} catch (Exception e) {
rethrowException(e);
}
Expand Down Expand Up @@ -111,7 +106,7 @@ public <T> Collection<T> retrieveAllOfType(Class<T> clazz) {
public <T> void registerProvider(Class<T> clazz, Provider<? extends T> provider) {
checkNotNull(clazz, "Class may not be null");
checkNotNull(provider, "Provider may not be null");
for (ProviderHandler handler : config.getProviderHandlers()) {
for (Handler handler : config.getHandlers()) {
try {
handler.onProvider(clazz, provider);
} catch (Exception e) {
Expand All @@ -124,7 +119,7 @@ public <T> void registerProvider(Class<T> clazz, Provider<? extends T> provider)
public <T, P extends Provider<? extends T>> void registerProvider(Class<T> clazz, Class<P> providerClass) {
checkNotNull(clazz, "Class may not be null");
checkNotNull(providerClass, "Provider class may not be null");
for (ProviderHandler handler : config.getProviderHandlers()) {
for (Handler handler : config.getHandlers()) {
try {
handler.onProviderClass(clazz, providerClass);
} catch (Exception e) {
Expand Down Expand Up @@ -213,17 +208,19 @@ private Object[] resolveDependencies(ResolvedInstantiationContext<?> resolvedCon
}

private <T> Instantiation<? extends T> getInstantiation(UnresolvedInstantiationContext<T> context) {
for (InstantiationProvider provider : config.getInstantiationProviders()) {
Instantiation<? extends T> instantiation = provider.get(context);
for (Handler handler : config.getHandlers()) {
Instantiation<? extends T> instantiation = handler.get(context);
if (instantiation != null) {
return instantiation;
}
}

// No instantiation method was found, handle error with most appropriate message
if (config.getInstantiationProviders().isEmpty()) {
throw new InjectorException("You did not register any instantiation methods!");
} else if (!InjectorUtils.canInstantiate(context.getMappedClass())) {
// TODO #48: Need to be able to check this with the new layout
// if (config.getInstantiationProviders().isEmpty()) {
// throw new InjectorException("You did not register any instantiation methods!");
// } else
if (!InjectorUtils.canInstantiate(context.getMappedClass())) {
throw new InjectorException("Did not find instantiation method for '" + context.getMappedClass()
+ "'. This class cannot be instantiated directly, please check the class or your handlers.");
}
Expand All @@ -234,14 +231,14 @@ private <T> Instantiation<? extends T> getInstantiation(UnresolvedInstantiationC
}

/**
* Runs the given instantiation context through all registered {@link PreConstructHandler}s.
* Runs the given instantiation context through all registered handlers.
*
* @param unresolvedContext the instantiation context
*/
private void processPreConstructorHandlers(UnresolvedInstantiationContext<?> unresolvedContext) {
for (PreConstructHandler preConstructHandler : config.getPreConstructHandlers()) {
for (Handler handler : config.getHandlers()) {
try {
preConstructHandler.accept(unresolvedContext);
handler.accept(unresolvedContext);
} catch (Exception e) {
rethrowException(e);
}
Expand All @@ -250,9 +247,9 @@ private void processPreConstructorHandlers(UnresolvedInstantiationContext<?> unr

private <T> T runPostConstructHandlers(T instance, ResolvedInstantiationContext<T> resolvedContext) {
T object = instance;
for (PostConstructHandler postConstructHandler : config.getPostConstructHandlers()) {
for (Handler handler : config.getHandlers()) {
try {
object = firstNotNull(postConstructHandler.process(object, resolvedContext), object);
object = firstNotNull(handler.process(object, resolvedContext), object);
} catch (Exception e) {
rethrowException(e);
}
Expand All @@ -264,7 +261,7 @@ private <T> T runPostConstructHandlers(T instance, ResolvedInstantiationContext<
private Object resolveDependency(ResolvedInstantiationContext<?> resolvedContext,
DependencyDescription dependencyDescription) {
Object o;
for (DependencyHandler handler : config.getDependencyHandlers()) {
for (Handler handler : config.getHandlers()) {
try {
if ((o = handler.resolveValue(resolvedContext, dependencyDescription)) != null) {
return o;
Expand Down
Loading

0 comments on commit dc87285

Please sign in to comment.