Skip to content

Commit

Permalink
stage 4
Browse files Browse the repository at this point in the history
(cherry picked from commit 90270df)
  • Loading branch information
shin-mallang committed Sep 29, 2023
1 parent ddd8167 commit ac839f9
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 5 deletions.
21 changes: 20 additions & 1 deletion study/src/test/java/di/stage4/annotations/ClassPathScanner.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
package di.stage4.annotations;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Set;
import java.util.stream.Collectors;

public class ClassPathScanner {

public static Set<Class<?>> getAllClassesInPackage(final String packageName) {
return null;
InputStream stream = ClassLoader.getSystemClassLoader()
.getResourceAsStream(packageName.replaceAll("[.]", "/"));
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
return reader.lines()
.filter(line -> line.endsWith(".class"))
.map(line -> getClass(line, packageName))
.collect(Collectors.toSet());
}

private static Class<?> getClass(String className, String packageName) {
try {
return Class.forName(packageName + "."
+ className.substring(0, className.lastIndexOf('.')));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
115 changes: 111 additions & 4 deletions study/src/test/java/di/stage4/annotations/DIContainer.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,131 @@
package di.stage4.annotations;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.reflections.Reflections;

/**
* 스프링의 BeanFactory, ApplicationContext에 해당되는 클래스
*/
class DIContainer {

private final Set<Object> beans;

private final Set<Object> beans = new HashSet<>();
private final Map<Class<?>, Object> beanBySuperTypeMap = new HashMap<>();

public DIContainer(final Set<Class<?>> classes) {
this.beans = Set.of();
for (Class<?> aClass : classes) {
createBean(aClass);
}
for (Object bean : beans) {
injectBean(bean);
}
}

public static DIContainer createContainerForPackage(final String rootPackageName) {
return null;
Set<Class<?>> allClassesInPackage = ClassPathScanner.getAllClassesInPackage(rootPackageName);
Set<Class<?>> beanCandidate = findBeanCandidate(allClassesInPackage);
return new DIContainer(beanCandidate);
}

private static Set<Class<?>> findBeanCandidate(Set<Class<?>> allClassesInPackage) {
return allClassesInPackage.stream()
.filter(it -> it.isAnnotationPresent(Repository.class)
|| it.isAnnotationPresent(Service.class))
.collect(Collectors.toSet());
}

private void createBean(Class<?> aClass) {
if (beanBySuperTypeMap.containsKey(aClass)) {
return;
}
if (aClass.isInterface()) {
createInterfaceBean(aClass);
return;
}
Constructor<?> declaredConstructor = aClass.getDeclaredConstructors()[0];
declaredConstructor.setAccessible(true);
if (isDefaultConstructor(declaredConstructor)) {
createBeanWithDefaultCtor(declaredConstructor);
} else {
createBeanWithCtorParameters(declaredConstructor);
}
}

private void createInterfaceBean(Class<?> aClass) {
Set<Class<?>> subTypes = findAllSubTypes(aClass);
for (Class<?> subType : subTypes) {
createBean(subType);
return;
}
}

private Set<Class<?>> findAllSubTypes(Class<?> aClass) {
return (Set<Class<?>>)
new Reflections(aClass.getPackage().getName()).getSubTypesOf(aClass);
}

private boolean isDefaultConstructor(Constructor<?> declaredConstructor) {
Parameter[] parameters = declaredConstructor.getParameters();
return parameters.length == 0;
}

private void createBeanWithDefaultCtor(Constructor<?> declaredConstructor) {
try {
Object o = declaredConstructor.newInstance();
storeBean(o);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private void storeBean(Object o) {
beanBySuperTypeMap.put(o.getClass(), o);
if (o.getClass().getInterfaces().length != 0) {
beanBySuperTypeMap.put(o.getClass().getInterfaces()[0], o);
}
beans.add(o);
}

private void createBeanWithCtorParameters(Constructor<?> declaredConstructor) {
Parameter[] parameters = declaredConstructor.getParameters();
Object[] parameterBeans = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Class<?> type = parameters[i].getType();
createBean(type);
parameterBeans[i] = getBean(type);
}
try {
Object o = declaredConstructor.newInstance(parameterBeans);
storeBean(o);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private void injectBean(Object bean) {
for (Field field : bean.getClass().getDeclaredFields()) {
field.setAccessible(true);
if (!field.isAnnotationPresent(Inject.class)) {
continue;
}
try {
field.set(bean, getBean(field.getType()));
} catch (IllegalAccessException e) {
System.out.println("Inject 오류!");
throw new RuntimeException(e);
}
}
}

@SuppressWarnings("unchecked")
public <T> T getBean(final Class<T> aClass) {
return null;
return (T) beanBySuperTypeMap.get(aClass);
}
}

0 comments on commit ac839f9

Please sign in to comment.