You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tasks/astrid/common-src/com/todoroo/andlib/service/DependencyInjectionService....

153 lines
4.9 KiB
Java

package com.todoroo.andlib.service;
import java.lang.reflect.Field;
import java.util.Arrays;
import android.util.Log;
import com.todoroo.astrid.utility.Constants;
/**
* Simple Dependency Injection Service for Android.
* <p>
* Add dependency injectors to the injector chain, then invoke this method
* against classes you wish to perform dependency injection for.
* <p>
* All errors encountered are handled as warnings, so if dependency injection
* seems to be failing, check the logs for more information.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class DependencyInjectionService {
private static final String QUALIFIED_PACKAGE = "com.t"; //$NON-NLS-1$
/**
* Dependency injectors. Use getters and setters to modify this list
*/
private AbstractDependencyInjector[] injectors = {};
/**
* Perform dependency injection in the caller object
*
* @param caller
* object to perform DI on
*/
@SuppressWarnings("nls")
public void inject(Object caller) {
if(Constants.DEBUG) {
Log.d("INJECTOR", "Invoked Injector on " + caller, new Throwable());
}
// Traverse through class and all parent classes, looking for
// fields declared with the @Autowired annotation and using
// dependency injection to set them as appropriate
Class<?> cls = caller.getClass();
while(cls != null) {
String packageName = cls.getPackage().getName();
if(!packageName.startsWith(QUALIFIED_PACKAGE))
break;
for(Field field : cls.getDeclaredFields()) {
if(field.getAnnotation(Autowired.class) != null) {
field.setAccessible(true);
try {
handleField(caller, field);
} catch (IllegalStateException e) {
throw new RuntimeException(String.format("Unable to set field '%s' of type '%s'",
field.getName(), field.getType()), e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(String.format("Unable to set field '%s' of type '%s'",
field.getName(), field.getType()), e);
} catch (IllegalAccessException e) {
throw new RuntimeException(String.format("Unable to set field '%s' of type '%s'",
field.getName(), field.getType()), e);
}
}
}
cls = cls.getSuperclass();
}
}
/**
* This method returns the appropriate dependency object based on the type
* that this autowired field accepts
*
* @param caller
* calling object
* @param field
* field to inject
*/
@SuppressWarnings("nls")
private void handleField(Object caller, Field field)
throws IllegalStateException, IllegalArgumentException,
IllegalAccessException {
if(field.getType().isPrimitive())
throw new IllegalStateException(String.format(
"Tried to dependency-inject primative field '%s' of type '%s'",
field.getName(), field.getType()));
// field has already been processed, ignore
if (field.get(caller) != null) {
return;
}
for (AbstractDependencyInjector injector : injectors) {
Object injection = injector.getInjection(caller, field);
if (injection != null) {
if(Constants.DEBUG)
Log.e("INJECTOR", injector + ":" + caller + "." + field.getName() + " => " + injection);
field.set(caller, injection);
return;
}
}
throw new IllegalStateException(
String.format("No dependency injector found for autowired " +
"field '%s' in class '%s'. Injectors: %s",
field.getName(), caller.getClass().getName(),
Arrays.asList(getInjectors())));
}
// --- static methods
private static DependencyInjectionService instance = null;
DependencyInjectionService() {
// prevent instantiation
}
/**
* Gets the singleton instance of the dependency injection service.
* @return
*/
public synchronized static DependencyInjectionService getInstance() {
if(instance == null)
instance = new DependencyInjectionService();
return instance;
}
/**
* Gets the array of installed injectors
* @return
*/
public synchronized AbstractDependencyInjector[] getInjectors() {
return injectors;
}
/**
* Sets the array of installed injectors
* @param injectors
*/
public synchronized void setInjectors(AbstractDependencyInjector[] injectors) {
this.injectors = injectors;
}
}