/** * Copyright 2011 Marin Solutions */ package dependency_injection_with_annotations; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import dependency_injection_with_annotations.loaders.FileLoader; import dependency_injection_with_annotations.loaders.FileSystemClassLoader; import dependency_injection_with_annotations.loaders.JarLoader; /** * This is a very limited factory class that performs dependency injection using * annotations. * * @author Roger * */ public class DependencyInjectionBeanFactory implements MyBeanFactory { public final String packageName; public final Map<Class<?>, Object> injectionGraph; /** * Default Ctor - start looking in the root location */ public DependencyInjectionBeanFactory() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { this(""); } public DependencyInjectionBeanFactory(String packageName) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { this.packageName = packageName; injectionGraph = loadAll(); } /* * Given a starting point on the classpath, load all the annotated classes, * returning them in a map where the key is either an id value or a class * name */ private Map<Class<?>, Object> loadAll() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { List<File> directories = getDirectories(); List<Class<?>> classes = loadClasses(directories); return glueClassesTogether(classes); } private List<File> getDirectories() throws IOException { FileLoader loader = FileLoader.getInstance(packageName); return loader.getFileList(); } private List<Class<?>> loadClasses(List<File> directories) throws ClassNotFoundException, IOException { List<Class<?>> classes = new ArrayList<Class<?>>(); for (File directory : directories) { if (isJarFile(directory)) { classes.addAll(loadFromJarFile(directory)); } else { classes.addAll(loadFromFileSystem(directory)); } } return classes; } private boolean isJarFile(File directory) { return directory.getParent().endsWith(".jar"); } private List<Class<?>> loadFromJarFile(File directory) throws ClassNotFoundException, IOException { return JarLoader.getInstance(directory, packageName).getClasses(); } private List<Class<?>> loadFromFileSystem(File directory) throws ClassNotFoundException, IOException { return FileSystemClassLoader.getInstance(directory, packageName).getClasses(); } private Map<Class<?>, Object> glueClassesTogether(List<Class<?>> classes) throws InstantiationException, IllegalAccessException { Map<Class<?>, Object> components = getComponents(classes); glueComponents(components); return components; } private Map<Class<?>, Object> getComponents(List<Class<?>> classes) throws InstantiationException, IllegalAccessException { Map<Class<?>, Object> result = new HashMap<Class<?>, Object>(); for (Class<?> clazz : classes) { AnnotationChecker checker = new AnnotationChecker(clazz); if (checker.isMyComponent()) { Object obj = clazz.newInstance(); result.put(clazz, obj); } } return result; } private void glueComponents(Map<Class<?>, Object> components) throws IllegalArgumentException, IllegalAccessException { Set<Class<?>> keys = components.keySet(); for (Class<?> key : keys) { injectFields(key, components); } } private void injectFields(Class<?> clazz, Map<Class<?>, Object> components) throws IllegalArgumentException, IllegalAccessException { AnnotationChecker checker = new AnnotationChecker(clazz); Object target = components.get(clazz); List<Field> fields = checker.getAutoWireFields(); for (Field field : fields) { injectInToField(target, field, components); } } private void injectInToField(Object target, Field field, Map<Class<?>, Object> components) throws IllegalArgumentException, IllegalAccessException { field.setAccessible(true); // If a field is private, then gain access to // it. Object injectedClass = getObjectToInject(components, field); field.set(target, injectedClass); } private Object getObjectToInject(Map<Class<?>, Object> components, Field field) { Class<?> classField = field.getType(); return components.get(classField); } @SuppressWarnings("unchecked") public <T> T getBean(Class<T> clazz) { return (T) injectionGraph.get(clazz); } }