org.jvault.beanloader.DefaultBeanLoader Maven / Gradle / Ivy
package org.jvault.beanloader;
import org.jvault.annotation.Inject;
import org.jvault.annotation.InternalBean;
import org.jvault.bean.Bean;
import org.jvault.bean.BeanBuilderFactory;
import org.jvault.bean.Type;
import org.jvault.exceptions.BeanCycledException;
import org.jvault.exceptions.DisallowedAccessException;
import org.jvault.exceptions.DuplicateBeanNameException;
import org.jvault.exceptions.NoDefinedInternalBeanException;
import org.jvault.factory.extensible.BeanLoader;
import org.jvault.metadata.InternalAPI;
import org.jvault.util.Reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
import java.util.*;
@InternalAPI
public final class DefaultBeanLoader implements BeanLoader {
private final Reflection REFLECTION;
private final BeanBuilderFactory BEAN_BUILDER_FACTORY;
private final Map BEANS;
private final Map BEAN_INSTANCES;
private final Map> SCANNED_BEANS;
private final Map SCC;
private final Map SCC_ENTER;
private int order = 1;
private int enter = 1;
{
REFLECTION = Accessors.UtilAccessor.getAccessor().getReflection();
BEAN_BUILDER_FACTORY = Accessors.BeanAccessor.getAccessor().getBeanBuilderFactory();
BEANS = new HashMap<>();
BEAN_INSTANCES = new HashMap<>();
SCANNED_BEANS = new HashMap<>();
SCC = new HashMap<>();
SCC_ENTER = new HashMap<>();
}
DefaultBeanLoader() {
}
@Override
public Map load(List> beanClasses) {
throwIfListContainNotInternalBean(beanClasses);
if (beanClasses.isEmpty()) return BEANS;
scanBeans(beanClasses);
for (Class> beanClass : beanClasses) {
if (BEANS.containsKey(getBeanName(beanClass))) continue;
loadBean(beanClass);
enter++;
}
return BEANS;
}
private void throwIfListContainNotInternalBean(List> beanClasses) {
for (Class> beanClass : beanClasses) throwIfIsNotInternalBean(beanClass);
}
private void throwIfIsNotInternalBean(Class> cls) {
if (cls.getDeclaredAnnotation(InternalBean.class) == null)
throw new NoDefinedInternalBeanException(cls.getSimpleName());
}
private void scanBeans(List> beanClasses) {
for (Class> beanClass : beanClasses) {
String beanName = getBeanName(beanClass);
throwIfDuplicateBeanDetected(beanName);
SCANNED_BEANS.put(beanName, beanClass);
}
}
private void throwIfDuplicateBeanDetected(String beanName) {
if (SCANNED_BEANS.containsKey(beanName))
throw new DuplicateBeanNameException(beanName);
}
private void loadBean(Class> beanClass) {
String beanName = getBeanName(beanClass);
if (SCC.containsKey(beanName)) {
throwIfBeanCycleOccurred(beanName);
return;
}
SCC.put(beanName, ++order);
SCC_ENTER.put(beanName, enter);
registerBean(beanClass);
}
private void throwIfBeanCycleOccurred(String beanName) {
if (SCC.get(beanName) <= order && Objects.equals(SCC_ENTER.get(beanName), enter))
throw new BeanCycledException();
}
private void registerBean(Class> beanClass) {
Constructor> constructor = REFLECTION.findConstructor(beanClass);
if (constructor != null) {
registerBeanFromConstructor(beanClass, constructor);
return;
}
List fields = REFLECTION.findFields(beanClass);
registerBeanFromField(beanClass, fields);
}
private void registerBeanFromConstructor(Class> beanClass, Constructor> constructor) {
List parameters = REFLECTION.getAnnotatedConstructorParameters(constructor);
List