Skip to content

Commit

Permalink
Merge pull request #3 from treblereel/generators_refactoring
Browse files Browse the repository at this point in the history
Generators refactoring
  • Loading branch information
treblereel authored Aug 17, 2023
2 parents 711e522 + b5cb3cb commit 3a88fac
Show file tree
Hide file tree
Showing 48 changed files with 1,316 additions and 488 deletions.
271 changes: 150 additions & 121 deletions core/src/main/java/io/crysknife/client/internal/AbstractBeanManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,56 +19,90 @@
import jakarta.enterprise.inject.Typed;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

import static io.crysknife.client.internal.QualifierUtil.ANY_ANNOTATION;
import static io.crysknife.client.internal.QualifierUtil.DEFAULT_ANNOTATION;
import static io.crysknife.client.internal.QualifierUtil.DEFAULT_QUALIFIERS;
import static io.crysknife.client.internal.QualifierUtil.SPECIALIZES_ANNOTATION;
import static io.crysknife.client.internal.QualifierUtil.matches;

/**
* @author Dmitrii Tikhomirov Created by treblereel 3/28/19
*/
@SuppressWarnings("unchecked")
public abstract class AbstractBeanManager implements BeanManager {

private final Map<Class, BeanDefinitionHolder> beans = new HashMap<>();

private final Map<Object, BeanFactory> pool = new IdentityHashMap<>();
private final Map<Object, BeanFactory> pool = new HashMap<>();
private final Map<String, Class> beansByBeanName = new HashMap<>();

protected AbstractBeanManager() {
private final Predicate<SyncBeanDefImpl> isTyped =
syncBeanDef -> syncBeanDef.getTyped().isPresent();
private final Predicate<SyncBeanDefImpl> isNotTyped =
syncBeanDef -> syncBeanDef.getTyped().isEmpty();

}
private final Predicate<SyncBeanDefImpl> hasFactory =
syncBeanDef -> syncBeanDef.getFactory().isPresent();

public void register(SyncBeanDefImpl beanDefinition) {
BeanDefinitionHolder holder = get(beanDefinition.getType());
holder.beanDefinition = beanDefinition;
beanDefinition.getAssignableTypes().forEach(superType -> {
get((Class<?>) superType).subTypes.add(holder);
beansByBeanName.put(((Class<?>) superType).getCanonicalName(), (Class<?>) superType);
private final Predicate<SyncBeanDefImpl> hasDefaultQualifiers =
bean -> bean.matches(setOf(DEFAULT_ANNOTATION));

protected AbstractBeanManager() {

});
beansByBeanName.put(beanDefinition.getName(), beanDefinition.getType());
}

private BeanDefinitionHolder get(Class<?> type) {
if (!beans.containsKey(type)) {
BeanDefinitionHolder holder = new BeanDefinitionHolder();
beans.put(type, holder);
public void register(final SyncBeanDefImpl beanDefinition) {
BeanDefinitionHolder holder =
beans.computeIfAbsent(beanDefinition.getType(), k -> new BeanDefinitionHolder());
for (Class<?> superType : (Collection<Class<?>>) beanDefinition.getAssignableTypes()) {
beans.computeIfAbsent(superType, k -> new BeanDefinitionHolder()).subTypes.add(holder);
beansByBeanName.put(superType.getCanonicalName(), superType);
}
return beans.get(type);
Set<Annotation> temp = new HashSet<Annotation>(beanDefinition.getActualQualifiers());
holder.qualifiers.put(temp, beanDefinition);
beansByBeanName.put(beanDefinition.getName(), beanDefinition.getType());
}

@Override
public Collection<SyncBeanDef> lookupBeans(String name) {
if (beansByBeanName.containsKey(name)) {
return lookupBeans(beansByBeanName.get(name));
}
return Collections.EMPTY_SET;
}

public <T> Collection<SyncBeanDef<T>> lookupBeans(final Class<T> type) {
Set<SyncBeanDef<T>> result = new HashSet<>();
if (!beans.containsKey(type)) {
return result;
}
of(beans.get(type)).map(f -> (SyncBeanDef<T>) f).forEach(result::add);
return result;
}

return Collections.EMPTY_SET;
private Stream<SyncBeanDefImpl> of(BeanDefinitionHolder holder,
Predicate<SyncBeanDefImpl>... filters) {
Stream<SyncBeanDefImpl> stream =
Stream.of(holder.subTypes.stream().flatMap(f -> f.qualifiers.values().stream()),
holder.qualifiers.values().stream()).flatMap(Function.identity());
for (Predicate<SyncBeanDefImpl> filter : filters) {
stream = stream.filter(filter);
}

return stream;
}

public <T> Collection<SyncBeanDef<T>> lookupBeans(final Class<T> type, Annotation... qualifiers) {
Expand All @@ -78,33 +112,25 @@ public <T> Collection<SyncBeanDef<T>> lookupBeans(final Class<T> type, Annotatio
}

if (qualifiers.length == 0) {
if (beans.get(type).beanDefinition != null) {
result.add(beans.get(type).beanDefinition);
}
beans.get(type).subTypes.stream().filter(f -> f.beanDefinition != null)
.forEach(bean -> result.add(bean.beanDefinition));
return result;
return lookupBeans(type);
}

if (beans.get(type).beanDefinition != null) {
if (compareAnnotations(beans.get(type).beanDefinition.getActualQualifiers(), qualifiers)) {
result.add(beans.get(type).beanDefinition);
}
}
beans.get(type).subTypes.stream().filter(f -> f.beanDefinition != null)
.filter(f -> compareAnnotations(f.beanDefinition.getActualQualifiers(), qualifiers))
.forEach(bean -> result.add(bean.beanDefinition));
of(beans.get(type)).filter(bean -> bean.matches(setOf(qualifiers))).map(f -> (SyncBeanDef<T>) f)
.forEach(result::add);

return result;
}

private boolean compareAnnotations(Collection<Annotation> all, Annotation... in) {
Annotation[] _all = all.toArray(new Annotation[all.size()]);
return QualifierUtil.matches(in, _all);
}

public <T> SyncBeanDef<T> lookupBean(final Class<T> type) {
return lookupBean(type, QualifierUtil.DEFAULT_ANNOTATION);
Collection<IOCBeanDef<T>> candidates = doLookupBean(type, QualifierUtil.DEFAULT_ANNOTATION);

if (candidates.size() > 1) {
throw BeanManagerUtil.ambiguousResolutionException(type, candidates, DEFAULT_ANNOTATION);
} else if (candidates.isEmpty()) {
throw BeanManagerUtil.unsatisfiedResolutionException(type, DEFAULT_ANNOTATION);
} else {
return (SyncBeanDef<T>) candidates.iterator().next();
}
}

public <T> SyncBeanDef<T> lookupBean(final Class<T> type, Annotation... qualifiers) {
Expand All @@ -126,110 +152,113 @@ public void destroyBean(Object ref) {
}
}

<T> T addBeanInstanceToPool(Object instance, BeanFactory factory) {
pool.put(instance, factory);
return (T) instance;
}
private <T> Collection<IOCBeanDef<T>> doLookupBean(final Class<T> type,
final Annotation... qualifiers) {
if (!beans.containsKey(type)) {
return Collections.EMPTY_SET;
}

<T> Collection<IOCBeanDef<T>> doLookupBean(final Class<T> type, Annotation... qualifiers) {
Collection<IOCBeanDef<T>> candidates = new HashSet<>();
if (beans.containsKey(type)) {
BeanDefinitionHolder holder = beans.get(type);

if (qualifiers == null || qualifiers.length == 0) {
qualifiers = new Annotation[] {QualifierUtil.DEFAULT_ANNOTATION};
}
Optional<IOCBeanDef<T>> maybeTyped = of(holder, isTyped)
.filter(bean -> Arrays.asList(((Typed) bean.getTyped().get()).value()).contains(type))
.map(bean -> (IOCBeanDef<T>) bean).findFirst();

if (beans.get(type).beanDefinition != null) {
if (beans.get(type).beanDefinition.getTyped().isPresent()) {
if (Arrays.stream(((Typed) beans.get(type).beanDefinition.getTyped().get()).value())
.anyMatch(any -> any.equals(type))) {
Set<IOCBeanDef<T>> result = new HashSet<>();
result.add(beans.get(type).beanDefinition);
return result;
}
}
if (maybeTyped.isPresent()) {
return setOf(maybeTyped.get());
}

if (compareAnnotations(beans.get(type).beanDefinition.getQualifiers(), qualifiers)) {
if (beans.get(type).beanDefinition.getFactory().isPresent()) {
candidates.add(beans.get(type).beanDefinition);
}
}
of(holder, hasFactory, isNotTyped).filter(bean -> {
Set<Annotation> temp = new HashSet<>(bean.getActualQualifiers());
Collections.addAll(temp, DEFAULT_QUALIFIERS);
return compareAnnotations(temp, qualifiers);
}).forEach(bean -> candidates.add((IOCBeanDef<T>) bean));

if (qualifiers.length == 1 && isDefault(qualifiers)) {
Optional<IOCBeanDef<T>> maybeSpecialized =
of(holder, isNotTyped).filter(bean -> bean.matches(setOf(SPECIALIZES_ANNOTATION)))
.map(bean -> (IOCBeanDef<T>) bean).findFirst();

// TODO this is not correct, specialized bean totally overrides the parent bean, including
// qualifiers
if (maybeSpecialized.isPresent()) {
return setOf(maybeSpecialized.get());
}

if (qualifiers.length == 1 && !beans.get(type).subTypes.isEmpty() && isDefault(qualifiers)) {
for (BeanDefinitionHolder subType : beans.get(type).subTypes) {
if (subType.beanDefinition != null) {
if (!subType.beanDefinition.getActualQualifiers().isEmpty()
&& compareAnnotations(subType.beanDefinition.getActualQualifiers(),
QualifierUtil.SPECIALIZES_ANNOTATION)) {
Collection<IOCBeanDef<T>> result = new HashSet<>();
result.add(subType.beanDefinition);
return result;
}
}
}
for (BeanDefinitionHolder subType : beans.get(type).subTypes) {
if (subType.beanDefinition != null) {
if (!subType.beanDefinition.getActualQualifiers().isEmpty() && compareAnnotations(
subType.beanDefinition.getActualQualifiers(), QualifierUtil.DEFAULT_ANNOTATION)) {
Collection<IOCBeanDef<T>> result = new HashSet<>();
result.add(subType.beanDefinition);
return result;
}
}
}
for (BeanDefinitionHolder subType : beans.get(type).subTypes) {
Set<Annotation> annotations = new HashSet<>();
annotations.add(QualifierUtil.DEFAULT_ANNOTATION);
if (compareAnnotations(subType.beanDefinition.getActualQualifiers(), qualifiers)) {
if (subType.beanDefinition.getTyped().isPresent()) {
continue;
} else if (subType.beanDefinition.getFactory().isPresent())
candidates.add(subType.beanDefinition);
}
}
} else {
Set<Annotation> _qual = new HashSet<>();
Collections.addAll(_qual, qualifiers);
Collections.addAll(_qual, QualifierUtil.DEFAULT_QUALIFIERS);
_qual.toArray(new Annotation[_qual.size()]);

for (BeanDefinitionHolder subType : beans.get(type).subTypes) {
if (compareAnnotations(subType.beanDefinition.getQualifiers(),
_qual.toArray(new Annotation[_qual.size()]))) {
if (subType.beanDefinition.getTyped().isPresent()
&& !isDefault(subType.beanDefinition.getActualQualifiers())) {
continue;
} else if (subType.beanDefinition.getFactory().isPresent())
candidates.add(subType.beanDefinition);
}
}
Optional<IOCBeanDef<T>> maybeDefault = of(holder, isNotTyped, hasDefaultQualifiers)
.map(bean -> (IOCBeanDef<T>) bean).findFirst();

if (maybeDefault.isPresent()) {
return setOf(maybeDefault.get());
}

of(holder, isNotTyped, hasFactory, hasDefaultQualifiers).map(bean -> (IOCBeanDef<T>) bean)
.forEach(candidates::add);
} else if (qualifiers.length == 1 && isAny(qualifiers)) {

of(holder, hasFactory)
// .filter(bean -> bean.getTyped().isEmpty()) //TODO not sure about this, may I have to
// filter out @typed beans
.map(bean -> (IOCBeanDef<T>) bean).forEach(candidates::add);
} else {
of(holder, isNotTyped, hasFactory).filter(bean -> bean.matches(setOf(qualifiers)))
.map(bean -> (IOCBeanDef<T>) bean).forEach(candidates::add);
}
return candidates;
}

private boolean isDefault(Collection<Annotation> qualifiers) {
if (qualifiers.isEmpty()) {
return false;
}
return isDefault(qualifiers.toArray(new Annotation[qualifiers.size()]));
private boolean compareAnnotations(Collection<Annotation> all, Annotation... in) {
Annotation[] _all = all.toArray(new Annotation[all.size()]);
return matches(in, _all);
}

private boolean isDefault(Annotation[] qualifiers) {
Annotation[] a1 = new Annotation[] {qualifiers[0]};
Annotation[] a2 = new Annotation[] {QualifierUtil.DEFAULT_ANNOTATION};
return QualifierUtil.matches(a1, a2);
Annotation[] a2 = new Annotation[] {DEFAULT_ANNOTATION};
return matches(a1, a2);
}

private boolean isAny(Annotation[] qualifiers) {
Annotation[] a1 = new Annotation[] {qualifiers[0]};
Annotation[] a2 = new Annotation[] {ANY_ANNOTATION};
return matches(a1, a2);
}

private <T> Collection<IOCBeanDef<T>> doLookupBean(final Class<T> type) {
Collection<IOCBeanDef<T>> candidates = new ArrayList<>();
if (beans.containsKey(type)) {
if (!beans.get(type).qualifiers.isEmpty()) {
beans.get(type).qualifiers.values().forEach(candidates::add);
} else {
of(beans.get(type), isNotTyped, hasFactory).filter(syncBeanDef -> {
if (syncBeanDef.getActualQualifiers().isEmpty()) {
return true;
} else {
return syncBeanDef.matches(setOf(DEFAULT_ANNOTATION));
}
}).map(bean -> (IOCBeanDef<T>) bean).forEach(candidates::add);
}
}
return candidates;
}

private boolean compareAnnotations(Annotation[] all, Annotation[] in) {
return QualifierUtil.matches(in, all);
// replace it with setOf right after we move to Java 11 emulated by J2CL
public static <T> Set<T> setOf(T... values) {
Set<T> set = new HashSet<>();
Collections.addAll(set, values);
return Collections.unmodifiableSet(set);
}

<T> T addBeanInstanceToPool(Object instance, BeanFactory<T> factory) {
pool.put(instance, factory);
return (T) instance;
}

private static class BeanDefinitionHolder {

SyncBeanDefImpl beanDefinition;
Set<BeanDefinitionHolder> subTypes = new HashSet<>();
private final Set<BeanDefinitionHolder> subTypes = new HashSet<>();
private final Map<Set<Annotation>, SyncBeanDefImpl> qualifiers = new HashMap<>();

}
}

14 changes: 7 additions & 7 deletions core/src/main/java/io/crysknife/client/internal/BeanFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ protected void setIncompleteInstance(final T instance) {
incompleteInstance = instance;
}

public abstract <T> T getInstance();
public abstract T getInstance();

public void initInstance(T instance) {
if (beanDef.getScope().equals(Dependent.class) || !initialized) {
Expand All @@ -58,19 +58,19 @@ protected void doInitInstance(T instance) {

}

public <T> T createNewInstance() {
public T createNewInstance() {
if (instance != null) {
createInstance();
}
return (T) instance;
return instance;
}

protected <T> T createInstance() {
protected T createInstance() {
throw new UnsupportedOperationException(
"The factory, " + getClass().getSimpleName() + ", only supports contextual instances.");
}

protected <T> T createInstanceInternal() {
protected T createInstanceInternal() {
T instance = createInstance();
return addBeanInstanceToPool(instance, this);
}
Expand All @@ -90,8 +90,8 @@ void onDestroyInternal(T instance) {
initialized = false;
}

protected <T> T addBeanInstanceToPool(Object instance, BeanFactory factory) {
return (T) beanManager.addBeanInstanceToPool(instance, factory);
T addBeanInstanceToPool(T instance, BeanFactory<T> factory) {
return beanManager.addBeanInstanceToPool(instance, factory);
}

}
Loading

0 comments on commit 3a88fac

Please sign in to comment.