Skip to content

Commit

Permalink
iss. 32 refactor to allow method arguments on Provides methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ljacqu committed Nov 5, 2016
1 parent 7766c28 commit 3187372
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 95 deletions.
17 changes: 14 additions & 3 deletions core/src/main/java/ch/jalu/injector/Injector.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.jalu.injector;

import ch.jalu.injector.config.InjectorConfiguration;
import ch.jalu.injector.handlers.instantiation.DependencyDescription;

import javax.annotation.Nullable;
import javax.inject.Provider;
Expand Down Expand Up @@ -43,10 +44,9 @@ public interface Injector {
* @param clazz the class to register the provider for
* @param providerClass the class of the provider
* @param <T> the class' type
* @param <P> the provider's type
* @since 0.3
* @since 0.4
*/
<T, P extends Provider<? extends T>> void registerProvider(Class<T> clazz, Class<P> providerClass);
<T> void registerProvider(Class<T> clazz, Class<? extends Provider<? extends T>> providerClass);

/**
* Processes an annotation with an associated object. The actual behavior of this method depends on the
Expand All @@ -62,6 +62,7 @@ public interface Injector {
* Processes the given configuration class.
*
* @param configuration the configuration
* @since 0.4
*/
void addConfiguration(InjectorConfiguration configuration);

Expand Down Expand Up @@ -112,6 +113,16 @@ public interface Injector {
@Nullable
<T> T createIfHasDependencies(Class<T> clazz);

/**
* Resolves the given dependency description object. This method is intended for hooking into the injector
* mechanism. Other methods such as {@link #getSingleton(Class)} should be preferred whenever possible.
*
* @param dependency the dependency to resolve
* @return the resolved object, or {@code null} if no dependency handler processed the request
*/
@Nullable
Object resolveDependency(DependencyDescription dependency);

/**
* Returns all known singletons of the given type. Typically used
* with interfaces in order to perform an action without knowing its concrete implementors.
Expand Down
38 changes: 25 additions & 13 deletions core/src/main/java/ch/jalu/injector/InjectorImpl.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package ch.jalu.injector;

import ch.jalu.injector.config.InjectorConfiguration;
import ch.jalu.injector.config.ProviderByMethod;
import ch.jalu.injector.config.ProviderMethodsUtil;
import ch.jalu.injector.config.UninitializedProviderByMethod;
import ch.jalu.injector.exceptions.InjectorException;
import ch.jalu.injector.handlers.annotationvalues.AnnotationValueHandler;
import ch.jalu.injector.handlers.dependency.DependencyHandler;
Expand All @@ -12,9 +12,9 @@
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.provider.UninitializedProviderByClass;
import ch.jalu.injector.utils.InjectorUtils;

import javax.annotation.Nullable;
import javax.inject.Provider;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -118,7 +118,7 @@ public void addConfiguration(InjectorConfiguration configuration) {
for (Method method : configuration.getClass().getDeclaredMethods()) {
if (ProviderMethodsUtil.isProviderMethod(method)) {
Class providerType = ProviderMethodsUtil.getProviderMethodType(method);
registerProvider(providerType, new ProviderByMethod<>(method, configuration));
registerProviderInstantiation(providerType, new UninitializedProviderByMethod<>(method, configuration));
}
}
}
Expand All @@ -137,12 +137,17 @@ public <T> void registerProvider(Class<T> clazz, Provider<? extends T> provider)
}

@Override
public <T, P extends Provider<? extends T>> void registerProvider(Class<T> clazz, Class<P> providerClass) {
public <T> void registerProvider(Class<T> clazz, Class<? extends Provider<? extends T>> providerClass) {
checkNotNull(clazz, "Class may not be null");
checkNotNull(providerClass, "Provider class may not be null");
registerProviderInstantiation(clazz, new UninitializedProviderByClass<>(providerClass));
}

private <T> void registerProviderInstantiation(Class<T> clazz,
Instantiation<? extends Provider<? extends T>> providerInstantiation) {
for (ProviderHandler handler : config.getProviderHandlers()) {
try {
handler.onProviderClass(clazz, providerClass);
handler.onProvider(clazz, providerInstantiation);
} catch (Exception e) {
InjectorUtils.rethrowException(e);
}
Expand Down Expand Up @@ -232,12 +237,7 @@ private Object[] resolveDependencies(Instantiation<?> instantiation, Set<Class<?
List<? extends DependencyDescription> dependencies = instantiation.getDependencies();
Object[] values = new Object[dependencies.size()];
for (int i = 0; i < dependencies.size(); ++i) {
DependencyDescription dependency = dependencies.get(i);
Object object = resolveDependency(dependency);

values[i] = (object == null)
? get(dependency.getType(), traversedClasses)
: object;
values[i] = resolveDependency(dependencies.get(i), traversedClasses);
}
return values;
}
Expand Down Expand Up @@ -275,8 +275,20 @@ private <T> T runPostConstructHandlers(T instance) {
return object;
}

@Nullable
private Object resolveDependency(DependencyDescription dependencyDescription) {
@Override
public Object resolveDependency(DependencyDescription dependency) {
return resolveDependency(dependency, new HashSet<Class<?>>());
}

private Object resolveDependency(DependencyDescription dependency, Set<Class<?>> traversedClasses) {
Object object = getDependencyFromHandlers(dependency);

return (object == null)
? get(dependency.getType(), traversedClasses)
: object;
}

private Object getDependencyFromHandlers(DependencyDescription dependencyDescription) {
Object o;
for (DependencyHandler handler : config.getDependencyHandlers()) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@ public class ProviderByMethod<T> implements Provider<T> {

private final Method method;
private final Object instance;
private final Object[] values;

public ProviderByMethod(Method method, Object instance) {
public ProviderByMethod(Method method, Object instance, Object... values) {
InjectorUtils.checkArgument(method.getParameterTypes().length == 0,
"Provider method may not take any arguments");
this.method = method;
this.instance = instance;
this.values = values;
}

@Override
public T get() {
return (T) ReflectionUtils.invokeMethod(method, instance);
return (T) ReflectionUtils.invokeMethod(method, instance, values);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ch.jalu.injector.config;

import ch.jalu.injector.handlers.instantiation.DependencyDescription;
import ch.jalu.injector.handlers.instantiation.Instantiation;

import javax.inject.Provider;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;


public class UninitializedProviderByMethod<T> implements Instantiation<Provider<T>> {

private final Method method;
private final Object instance;

public UninitializedProviderByMethod(Method method, Object instance) {
this.method = method;
this.instance = instance;
}

@Override
public List<DependencyDescription> getDependencies() {
Class<?>[] parameters = method.getParameterTypes();
Type[] genericTypes = method.getGenericParameterTypes();
Annotation[][] annotations = method.getParameterAnnotations();

List<DependencyDescription> dependencies = new ArrayList<>(parameters.length);
for (int i = 0; i < parameters.length; ++i) {
dependencies.add(new DependencyDescription(parameters[i], genericTypes[i], annotations[i]));
}
return dependencies;
}

@Override
public Provider<T> instantiateWith(Object... values) {
return new ProviderByMethod<>(method, instance, values);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.jalu.injector.handlers.provider;

import ch.jalu.injector.handlers.Handler;
import ch.jalu.injector.handlers.instantiation.Instantiation;

import javax.inject.Provider;

Expand All @@ -20,14 +21,14 @@ public interface ProviderHandler extends Handler {
<T> void onProvider(Class<T> clazz, Provider<? extends T> provider) throws Exception;

/**
* Processes the given provider class.
* Processes the given instantiation of a provider for the given class.
*
* @param clazz the class to associate the provider class with
* @param providerClass the provider class
* @param clazz the class to associate the future provider with
* @param providerInstantiation the instantiation method of the provider
* @param <T> the class' type
* @param <P> the provider class' type
* @throws Exception for unsuccessful validation, etc.
* @throws Exception upon unsuccessful operation, etc.
*/
<T, P extends Provider<? extends T>> void onProviderClass(Class<T> clazz, Class<P> providerClass) throws Exception;
<T> void onProvider(Class<T> clazz, Instantiation<? extends Provider<? extends T>> providerInstantiation)
throws Exception;

}
Loading

0 comments on commit 3187372

Please sign in to comment.