package mireka.startup; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import javax.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * DependencyInjection maintains a collection of injectable default objects, and * is able to inject those objects into uninitialized properties of other * configuration objects. */ public class DependencyInjection { private static final Logger logger = LoggerFactory .getLogger(DependencyInjection.class); private static InjectableObjectContainer injectableObjects = new InjectableObjectContainer(); /** * Registers the object as an object which can be injected later into * uninitialized properties. * * @param object * The object which can be injected */ public static void addInjectable(Object object) { logger.debug("Injectable object registered: " + object); injectableObjects.add(object); } /** * Initializes the properties that has not got a value explicitly and are * annotated with @Inject annotation with default objects selected from the * set of injectable objects. * * @param object * The object that may have uninitialized properties * @param initializedProperties * The list of properties which were explicitly initialized. */ public static void injectDependencies(Object object, List<String> initializedProperties) { for (Method method : object.getClass().getMethods()) { if (!method.isAnnotationPresent(Inject.class)) continue; if (isExplicitlyInitialized(method, initializedProperties)) continue; injectIntoMethod(object, method); } } private static boolean isExplicitlyInitialized(Method method, List<String> initializedProperties) { String property = calculatePropertyName(method); return initializedProperties.contains(property); } private static String calculatePropertyName(Method method) { String methodName = method.getName(); if (methodName.length() < 4 || !methodName.startsWith("set") || !Character.isUpperCase(methodName.charAt(3))) throw new RuntimeException( "Method name does not conform to the JavaBean setter " + "naming convention (setX): " + method.toString()); return Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4); } private static void injectIntoMethod(Object object, Method method) { Class<?> type = method.getParameterTypes()[0]; Object dependency = injectableObjects.get(type); try { method.invoke(object, dependency); } catch (IllegalAccessException e) { // impossible throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException( "Dependency injection failed, because the setter has thrown " + "an exception. Object: " + object + ". Method: " + method + ".", e.getCause()); } logger.debug("Dependency " + dependency + " has been injected into the " + calculatePropertyName(method) + " property of " + object); } }