com.coditory.quark.context.ContextBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of quark-context Show documentation
Show all versions of quark-context Show documentation
Coditory Quark Configuration Library
package com.coditory.quark.context;
import com.coditory.quark.context.annotations.Bean;
import com.coditory.quark.context.annotations.Configuration;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.StreamSupport;
import static com.coditory.quark.context.Args.checkNonNull;
import static com.coditory.quark.context.BeanDescriptor.descriptor;
import static com.coditory.quark.context.BeanHolder.holder;
import static com.coditory.quark.context.ConstructorBasedBeanCreator.fromConstructor;
public final class ContextBuilder {
private final Set> beanHolders = new LinkedHashSet<>();
private final Map properties = new LinkedHashMap<>();
public ContextBuilder scanPackage(Class> type) {
checkNonNull(type, "type");
return scanPackage(type.getPackageName(), name -> true);
}
public ContextBuilder scanPackage(Class> type, Predicate canonicalNameFilter) {
checkNonNull(type, "type");
checkNonNull(canonicalNameFilter, "canonicalNameFilter");
return scanPackage(type.getPackageName(), canonicalNameFilter);
}
public ContextBuilder scanPackage(String packageName) {
checkNonNull(packageName, "packageName");
return scanPackage(packageName, name -> true);
}
public ContextBuilder scanPackage(String packageName, Predicate canonicalNameFilter) {
checkNonNull(packageName, "packageName");
checkNonNull(canonicalNameFilter, "canonicalNameFilter");
Iterable> iterable = () -> ClasspathScanner.scanPackageAndSubPackages(packageName, canonicalNameFilter);
StreamSupport.stream(iterable.spliterator(), false)
.forEach(this::scanClass);
return this;
}
public ContextBuilder scanClass(Class type) {
checkNonNull(type, "type");
Configuration configuration = type.getAnnotation(Configuration.class);
if (configuration != null) {
if (type.isAnnotationPresent(Bean.class)) {
throw new ContextException("Detected incompatible annotations on class: " + type.getCanonicalName()
+ ". Class should have one annotation: @Configuration or @Bean.");
}
addBeansFromConfiguration(configuration, type);
} else if (type.isAnnotationPresent(Bean.class)) {
addAnnotatedBeanClass(type);
}
return this;
}
private void addAnnotatedBeanClass(Class type) {
Bean annotation = type.getAnnotation(Bean.class);
BeanCreator creator = fromConstructor(type);
addAnnotatedCreator(annotation, type, creator);
}
private void addBeansFromConfiguration(Configuration configuration, Class type) {
String name = configuration.name().isBlank()
? configuration.value()
: configuration.name();
BeanHolder holder = holder(descriptor(type, name), fromConstructor(type), configuration.eager());
addBeanHolder(holder);
for (Method method : type.getDeclaredMethods()) {
if (method.isAnnotationPresent(Bean.class)) {
method.setAccessible(true);
addFromAnnotatedConfiguration(holder, method, method.getReturnType());
}
}
}
private void addFromAnnotatedConfiguration(BeanHolder> holder, Method method, Class returnType) {
BeanCreator creator = new MethodBasedBeanCreator<>(holder, method);
Bean annotation = method.getAnnotation(Bean.class);
addAnnotatedCreator(annotation, returnType, creator);
}
private void addAnnotatedCreator(Bean annotation, Class type, BeanCreator creator) {
String name = annotation.name().isBlank()
? annotation.value()
: annotation.name();
BeanHolder holder = holder(descriptor(type, name), creator, annotation.eager());
addBeanHolder(holder);
}
public ContextBuilder setProperty(String name, Object value) {
checkNonNull(name, "name");
checkNonNull(value, "value");
properties.put(name, value);
return this;
}
public ContextBuilder setProperties(Map properties) {
checkNonNull(properties, "properties");
this.properties.putAll(properties);
return this;
}
@SuppressWarnings("unchecked")
public ContextBuilder add(T bean) {
checkNonNull(bean, "bean");
BeanDescriptor descriptor = descriptor((Class) bean.getClass());
BeanHolder holder = holder(descriptor, (ctx) -> bean, true);
addBeanHolder(holder);
return this;
}
@SuppressWarnings("unchecked")
public ContextBuilder add(T bean, String name) {
checkNonNull(bean, "bean");
checkNonNull(name, "name");
BeanDescriptor descriptor = descriptor((Class) bean.getClass(), name);
BeanHolder holder = holder(descriptor, (ctx) -> bean, true);
addBeanHolder(holder);
return this;
}
public ContextBuilder add(Class type, Predicate condition, BeanCreator beanCreator) {
checkNonNull(condition, "condition");
checkNonNull(type, "type");
checkNonNull(beanCreator, "beanCreator");
return add(type, wrapBeanCreator(condition, beanCreator));
}
public ContextBuilder add(Class type, String name, Predicate condition, BeanCreator beanCreator) {
checkNonNull(condition, "condition");
checkNonNull(type, "type");
checkNonNull(name, "name");
checkNonNull(beanCreator, "beanCreator");
return add(type, name, wrapBeanCreator(condition, beanCreator));
}
private BeanCreator wrapBeanCreator(Predicate condition, BeanCreator beanCreator) {
return new BeanCreator() {
@Override
public T create(ResolutionContext context) {
return beanCreator.create(context);
}
@Override
public boolean isActive(ConditionContext context) {
return beanCreator.isActive(context) && condition.test(context);
}
};
}
public ContextBuilder add(Class type, BeanCreator beanCreator) {
checkNonNull(beanCreator, "beanCreator");
addBeanHolder(holder(descriptor(type), beanCreator));
return this;
}
public ContextBuilder add(Class type, String name, BeanCreator beanCreator) {
checkNonNull(name, "name");
checkNonNull(beanCreator, "beanCreator");
addBeanHolder(holder(descriptor(type, name), beanCreator));
return this;
}
private void addBeanHolder(BeanHolder> holder) {
beanHolders.add(holder);
}
public Context buildEager() {
Map, List>> holders = resolveConditionalBeans();
Context context = Context.create(holders, properties);
holders.forEach((descriptor, creator) -> {
if (descriptor.getName() != null) {
context.get(descriptor.getType(), descriptor.getName());
} else {
context.get(descriptor.getType());
}
});
return context;
}
public Context build() {
return Context.create(resolveConditionalBeans(), properties);
}
private Map, List>> resolveConditionalBeans() {
return ContextResolver.resolve(beanHolders, properties);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy