From 9a854d3f3dcd780eee8eee09a62a20e9e8698921 Mon Sep 17 00:00:00 2001 From: Dmitrii Tikhomirov Date: Mon, 7 Aug 2023 19:20:29 -0700 Subject: [PATCH 1/5] logging has become more verboue --- .../java/io/crysknife/logger/PrintWriterTreeLogger.java | 5 ++--- .../src/main/java/io/crysknife/logger/TreeLogger.java | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/processor/src/main/java/io/crysknife/logger/PrintWriterTreeLogger.java b/processor/src/main/java/io/crysknife/logger/PrintWriterTreeLogger.java index bda10e18..feb6e76f 100644 --- a/processor/src/main/java/io/crysknife/logger/PrintWriterTreeLogger.java +++ b/processor/src/main/java/io/crysknife/logger/PrintWriterTreeLogger.java @@ -64,14 +64,13 @@ protected void doCommitBranch(AbstractTreeLogger childBeingCommitted, Type type, @Override protected void doLog(int indexOfLogEntryWithinParentLogger, Type type, String msg, Throwable caught, HelpInfo helpInfo) { - synchronized (mutex) { // ensure thread interleaving... - out.print(indent); + synchronized (mutex) { if (type.needsAttention()) { out.print("["); out.print(type.getLabel()); out.print("] "); } - + out.print(indent); out.println(msg); if (helpInfo != null) { URL url = helpInfo.getURL(); diff --git a/processor/src/main/java/io/crysknife/logger/TreeLogger.java b/processor/src/main/java/io/crysknife/logger/TreeLogger.java index 89be9383..a632cf5d 100644 --- a/processor/src/main/java/io/crysknife/logger/TreeLogger.java +++ b/processor/src/main/java/io/crysknife/logger/TreeLogger.java @@ -52,13 +52,13 @@ public enum Type { WARN(true), /** Logs information. */ - INFO(false), + INFO(true), /** Logs information related to lower-level operation. */ TRACE(false), /** Logs detailed information that could be useful during debugging. */ - DEBUG(false), + DEBUG(true), /** * Logs extremely verbose and detailed information that is typically useful only to product @@ -98,7 +98,7 @@ public String getLabel() { * Determines whether this log type is of lower priority than some other log type. * * @param other the other log type - * + * * @return true if this log type is lower priority */ public boolean isLowerPriorityThan(Type other) { @@ -204,7 +204,7 @@ public final TreeLogger branch(TreeLogger.Type type, String msg, Throwable caugh * being logged * @param helpInfo extra information that might be used by the logger to provide extended * information to the user - * + * * @return an instance of {@link TreeLogger} representing the new branch of the log; may be the * same instance on which this method is called */ From d806817a501d446c109de96fa6c14ff24a2e08c5 Mon Sep 17 00:00:00 2001 From: Dmitrii Tikhomirov Date: Mon, 14 Aug 2023 02:04:07 -0700 Subject: [PATCH 2/5] @Produces must support @Named/Qualifiers --- .../client/internal/AbstractBeanManager.java | 271 +++++++++------- .../client/internal/BeanFactory.java | 14 +- .../client/internal/BeanManagerUtil.java | 13 +- .../client/internal/ManagedInstanceImpl.java | 13 +- .../io/crysknife/client/internal/Pair.java | 30 +- .../client/internal/ProducesBeanFactory.java | 4 + .../client/internal/QualifierUtil.java | 8 +- .../client/internal/SyncBeanDefImpl.java | 68 ++-- .../java/io/crysknife/client/internal/temp | 283 ++++++++++++++++ .../crysknife/definition/BeanDefinition.java | 20 +- .../definition/BeanDefinitionFactory.java | 8 +- .../definition/ProducesBeanDefinition.java | 29 +- .../generator/SingletonGenerator.java | 27 +- .../generator/context/oracle/BeanOracle.java | 10 +- .../generator/info/InterceptorGenerator.java | 24 +- .../processor/ProducesProcessor.java | 11 +- .../task/BeanManagerGeneratorTask.java | 306 +++++++++--------- .../io/crysknife/task/BeanProcessorTask.java | 5 +- ....java => QualifierBeanProducerHolder.java} | 0 .../generator/TemplateGenerator.java | 17 +- 20 files changed, 789 insertions(+), 372 deletions(-) create mode 100644 core/src/main/java/io/crysknife/client/internal/temp rename tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/{QualifierBeanProducerTest.java => QualifierBeanProducerHolder.java} (100%) diff --git a/core/src/main/java/io/crysknife/client/internal/AbstractBeanManager.java b/core/src/main/java/io/crysknife/client/internal/AbstractBeanManager.java index 1548f404..af475893 100644 --- a/core/src/main/java/io/crysknife/client/internal/AbstractBeanManager.java +++ b/core/src/main/java/io/crysknife/client/internal/AbstractBeanManager.java @@ -19,46 +19,61 @@ 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 beans = new HashMap<>(); - private final Map pool = new IdentityHashMap<>(); + private final Map pool = new HashMap<>(); private final Map beansByBeanName = new HashMap<>(); - protected AbstractBeanManager() { + private final Predicate isTyped = + syncBeanDef -> syncBeanDef.getTyped().isPresent(); + private final Predicate isNotTyped = + syncBeanDef -> syncBeanDef.getTyped().isEmpty(); - } + private final Predicate 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 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>) beanDefinition.getAssignableTypes()) { + beans.computeIfAbsent(superType, k -> new BeanDefinitionHolder()).subTypes.add(holder); + beansByBeanName.put(superType.getCanonicalName(), superType); } - return beans.get(type); + Set temp = new HashSet(beanDefinition.getActualQualifiers()); + holder.qualifiers.put(temp, beanDefinition); + beansByBeanName.put(beanDefinition.getName(), beanDefinition.getType()); } @Override @@ -66,9 +81,28 @@ public Collection lookupBeans(String name) { if (beansByBeanName.containsKey(name)) { return lookupBeans(beansByBeanName.get(name)); } + return Collections.EMPTY_SET; + } + public Collection> lookupBeans(final Class type) { + Set> result = new HashSet<>(); + if (!beans.containsKey(type)) { + return result; + } + of(beans.get(type)).map(f -> (SyncBeanDef) f).forEach(result::add); + return result; + } - return Collections.EMPTY_SET; + private Stream of(BeanDefinitionHolder holder, + Predicate... filters) { + Stream stream = + Stream.of(holder.subTypes.stream().flatMap(f -> f.qualifiers.values().stream()), + holder.qualifiers.values().stream()).flatMap(Function.identity()); + for (Predicate filter : filters) { + stream = stream.filter(filter); + } + + return stream; } public Collection> lookupBeans(final Class type, Annotation... qualifiers) { @@ -78,33 +112,25 @@ public Collection> lookupBeans(final Class 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) f) + .forEach(result::add); return result; } - private boolean compareAnnotations(Collection all, Annotation... in) { - Annotation[] _all = all.toArray(new Annotation[all.size()]); - return QualifierUtil.matches(in, _all); - } - public SyncBeanDef lookupBean(final Class type) { - return lookupBean(type, QualifierUtil.DEFAULT_ANNOTATION); + Collection> 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) candidates.iterator().next(); + } } public SyncBeanDef lookupBean(final Class type, Annotation... qualifiers) { @@ -126,110 +152,113 @@ public void destroyBean(Object ref) { } } - T addBeanInstanceToPool(Object instance, BeanFactory factory) { - pool.put(instance, factory); - return (T) instance; - } + private Collection> doLookupBean(final Class type, + final Annotation... qualifiers) { + if (!beans.containsKey(type)) { + return Collections.EMPTY_SET; + } - Collection> doLookupBean(final Class type, Annotation... qualifiers) { Collection> 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> maybeTyped = of(holder, isTyped) + .filter(bean -> Arrays.asList(((Typed) bean.getTyped().get()).value()).contains(type)) + .map(bean -> (IOCBeanDef) 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> 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 temp = new HashSet<>(bean.getActualQualifiers()); + Collections.addAll(temp, DEFAULT_QUALIFIERS); + return compareAnnotations(temp, qualifiers); + }).forEach(bean -> candidates.add((IOCBeanDef) bean)); + + if (qualifiers.length == 1 && isDefault(qualifiers)) { + Optional> maybeSpecialized = + of(holder, isNotTyped).filter(bean -> bean.matches(setOf(SPECIALIZES_ANNOTATION))) + .map(bean -> (IOCBeanDef) 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> 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> result = new HashSet<>(); - result.add(subType.beanDefinition); - return result; - } - } - } - for (BeanDefinitionHolder subType : beans.get(type).subTypes) { - Set 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 _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> maybeDefault = of(holder, isNotTyped, hasDefaultQualifiers) + .map(bean -> (IOCBeanDef) bean).findFirst(); + + if (maybeDefault.isPresent()) { + return setOf(maybeDefault.get()); } + + of(holder, isNotTyped, hasFactory, hasDefaultQualifiers).map(bean -> (IOCBeanDef) 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) bean).forEach(candidates::add); + } else { + of(holder, isNotTyped, hasFactory).filter(bean -> bean.matches(setOf(qualifiers))) + .map(bean -> (IOCBeanDef) bean).forEach(candidates::add); } return candidates; } - private boolean isDefault(Collection qualifiers) { - if (qualifiers.isEmpty()) { - return false; - } - return isDefault(qualifiers.toArray(new Annotation[qualifiers.size()])); + private boolean compareAnnotations(Collection 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 Collection> doLookupBean(final Class type) { + Collection> 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) 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 Set setOf(T... values) { + Set set = new HashSet<>(); + Collections.addAll(set, values); + return Collections.unmodifiableSet(set); + } + + T addBeanInstanceToPool(Object instance, BeanFactory factory) { + pool.put(instance, factory); + return (T) instance; } private static class BeanDefinitionHolder { - SyncBeanDefImpl beanDefinition; - Set subTypes = new HashSet<>(); + private final Set subTypes = new HashSet<>(); + private final Map, SyncBeanDefImpl> qualifiers = new HashMap<>(); + } } - diff --git a/core/src/main/java/io/crysknife/client/internal/BeanFactory.java b/core/src/main/java/io/crysknife/client/internal/BeanFactory.java index 59be7ba7..098af7b0 100644 --- a/core/src/main/java/io/crysknife/client/internal/BeanFactory.java +++ b/core/src/main/java/io/crysknife/client/internal/BeanFactory.java @@ -45,7 +45,7 @@ protected void setIncompleteInstance(final T instance) { incompleteInstance = instance; } - public abstract T getInstance(); + public abstract T getInstance(); public void initInstance(T instance) { if (beanDef.getScope().equals(Dependent.class) || !initialized) { @@ -58,19 +58,19 @@ protected void doInitInstance(T instance) { } - public T createNewInstance() { + public T createNewInstance() { if (instance != null) { createInstance(); } - return (T) instance; + return instance; } - protected T createInstance() { + protected T createInstance() { throw new UnsupportedOperationException( "The factory, " + getClass().getSimpleName() + ", only supports contextual instances."); } - protected T createInstanceInternal() { + protected T createInstanceInternal() { T instance = createInstance(); return addBeanInstanceToPool(instance, this); } @@ -90,8 +90,8 @@ void onDestroyInternal(T instance) { initialized = false; } - protected T addBeanInstanceToPool(Object instance, BeanFactory factory) { - return (T) beanManager.addBeanInstanceToPool(instance, factory); + T addBeanInstanceToPool(T instance, BeanFactory factory) { + return beanManager.addBeanInstanceToPool(instance, factory); } } diff --git a/core/src/main/java/io/crysknife/client/internal/BeanManagerUtil.java b/core/src/main/java/io/crysknife/client/internal/BeanManagerUtil.java index 1b6a06f5..f3144953 100644 --- a/core/src/main/java/io/crysknife/client/internal/BeanManagerUtil.java +++ b/core/src/main/java/io/crysknife/client/internal/BeanManagerUtil.java @@ -29,26 +29,25 @@ public class BeanManagerUtil { public static IOCResolutionException ambiguousResolutionException(Class type, final Collection> resolved, Annotation... qualifiers) { final StringBuilder builder = new StringBuilder(); - builder.append("Multiple beans matched " + type.getName() + " with qualifiers {" - + qualifiersToString(qualifiers) + "\n").append("Found:\n"); + builder.append("Multiple beans matched ").append(type.getName()).append(" with qualifiers ") + .append(qualifiersToString(qualifiers)).append("\n").append("Found:\n"); for (final IOCBeanDef beanDef : resolved) { builder.append(" ").append(beanDef.toString()).append("\n"); } builder.append("}"); - IOCResolutionException iocResolutionException = new IOCResolutionException(builder.toString()); - return iocResolutionException; + return new IOCResolutionException(builder.toString()); } public static IOCResolutionException unsatisfiedResolutionException(Class type, Annotation... qualifiers) { - return new IOCResolutionException("No beans matched " + type.getName() + " with qualifiers {" - + qualifiersToString(qualifiers) + "}"); + return new IOCResolutionException("No beans matched " + type.getName() + " with qualifiers " + + qualifiersToString(qualifiers)); } public static IOCResolutionException noFactoryResolutionException(Class type, Annotation... qualifiers) { return new IOCResolutionException("No factory registered for " + type.getName() - + " with qualifiers {" + qualifiersToString(qualifiers) + "}"); + + " with qualifiers " + qualifiersToString(qualifiers)); } public static String qualifiersToString(Collection qualifiers) { diff --git a/core/src/main/java/io/crysknife/client/internal/ManagedInstanceImpl.java b/core/src/main/java/io/crysknife/client/internal/ManagedInstanceImpl.java index ecfc3486..df1ebab9 100644 --- a/core/src/main/java/io/crysknife/client/internal/ManagedInstanceImpl.java +++ b/core/src/main/java/io/crysknife/client/internal/ManagedInstanceImpl.java @@ -15,14 +15,12 @@ package io.crysknife.client.internal; import io.crysknife.client.BeanManager; -import io.crysknife.client.IOCBeanDef; import io.crysknife.client.ManagedInstance; import io.crysknife.client.SyncBeanDef; import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Iterator; -import java.util.function.Consumer; /** * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 @@ -52,7 +50,7 @@ public ManagedInstance select(Annotation... annotations) { @Override public ManagedInstance select(Class subtype, Annotation... qualifiers) { - return new ManagedInstanceImpl(beanManager, subtype, qualifiers); + return new ManagedInstanceImpl<>(beanManager, subtype, qualifiers); } @Override @@ -61,14 +59,12 @@ public boolean isUnsatisfied() { qualifiers = new Annotation[] {QualifierUtil.DEFAULT_ANNOTATION}; } - Collection> result = - ((AbstractBeanManager) beanManager).doLookupBean(type, qualifiers); - return result.size() != 1; + return beanManager.lookupBeans(type, qualifiers).size() != 1; } @Override public boolean isAmbiguous() { - return beanManager.lookupBeans(type, qualifiers).stream().count() > 1; + return beanManager.lookupBeans(type, qualifiers).size() > 1; } @Override @@ -110,8 +106,7 @@ public boolean hasNext() { @Override public T next() { final SyncBeanDef bean = delegate.next(); - final T instance = bean.getInstance(); - return instance; + return bean.getInstance(); } } } diff --git a/core/src/main/java/io/crysknife/client/internal/Pair.java b/core/src/main/java/io/crysknife/client/internal/Pair.java index d9034986..39708948 100644 --- a/core/src/main/java/io/crysknife/client/internal/Pair.java +++ b/core/src/main/java/io/crysknife/client/internal/Pair.java @@ -14,16 +14,36 @@ package io.crysknife.client.internal; +import java.util.Objects; + /** * @author Dmitrii Tikhomirov Created by treblereel 10/4/21 */ public class Pair { - public final K a; - public final V b; + public final K key; + public final V value; + + private Pair(K key, V value) { + this.key = key; + this.value = value; + } - public Pair(K a, V b) { - this.a = a; - this.b = b; + public static Pair of(K a, V b) { + return new Pair<>(a, b); } + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Pair pair = (Pair) o; + return Objects.equals(key, pair.key) && Objects.equals(value, pair.value); + } + + @Override + public int hashCode() { + return Objects.hash(key, value); + } } diff --git a/core/src/main/java/io/crysknife/client/internal/ProducesBeanFactory.java b/core/src/main/java/io/crysknife/client/internal/ProducesBeanFactory.java index fe74c8f7..af794996 100644 --- a/core/src/main/java/io/crysknife/client/internal/ProducesBeanFactory.java +++ b/core/src/main/java/io/crysknife/client/internal/ProducesBeanFactory.java @@ -29,6 +29,10 @@ public class ProducesBeanFactory extends BeanFactory { public ProducesBeanFactory(BeanManager beanManager, Supplier producer) { super(beanManager); this.producer = producer; + + // beanManager.register(new SyncBeanDefImpl(beanManager, + // beanManager.getOrCreateBean(producer.get().getClass())))); + } @Override() diff --git a/core/src/main/java/io/crysknife/client/internal/QualifierUtil.java b/core/src/main/java/io/crysknife/client/internal/QualifierUtil.java index 268943a8..51a70b3d 100644 --- a/core/src/main/java/io/crysknife/client/internal/QualifierUtil.java +++ b/core/src/main/java/io/crysknife/client/internal/QualifierUtil.java @@ -100,9 +100,9 @@ public static boolean matches(final Annotation[] allOf, final Annotation[] in) { * collection is empty, then it represents the universal qualifier that satisfies all other * qualifiers. This is unambiguous since it is otherwise impossible to have no qualifiers * (everything has {@link Any}). - * @return If {@code in} is non-empty then this returns true iff every annotation in - * {@code allOff} contains an equal annotation in {@code in}. If {@code in} is empty, then - * this returns true. + * @return If {@code in} is non-empty then this returns true if every annotation in {@code allOff} + * contains an equal annotation in {@code in}. If {@code in} is empty, then this returns + * true. */ public static boolean matches(final Collection allOf, final Collection in) { @@ -116,7 +116,7 @@ public static boolean matches(final Collection allOf, public static boolean contains(final Collection allOf, final Collection in) { if (allOf.isEmpty()) - return true; + return false; final Map allOfMap = new HashMap<>(); final Map inMap = new HashMap<>(); diff --git a/core/src/main/java/io/crysknife/client/internal/SyncBeanDefImpl.java b/core/src/main/java/io/crysknife/client/internal/SyncBeanDefImpl.java index 056ac265..7770b765 100644 --- a/core/src/main/java/io/crysknife/client/internal/SyncBeanDefImpl.java +++ b/core/src/main/java/io/crysknife/client/internal/SyncBeanDefImpl.java @@ -28,6 +28,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; /** * @author Dmitrii Tikhomirov Created by treblereel 9/25/21 @@ -77,7 +78,7 @@ public Class getScope() { return scope; } - @Override + @Override // TODO: this is not correct public Collection getQualifiers() { Set temp = new HashSet<>(defaultQualifiers); if (qualifiers != null) @@ -94,14 +95,20 @@ public Collection getActualQualifiers() { } } - @Override - public Optional> getFactory() { - return factory; - } - @Override public boolean matches(Set annotations) { - return QualifierUtil.matches(annotations, getQualifiers()); + if (annotations.isEmpty()) { + return true; + } + if (getActualQualifiers().isEmpty()) { + return false; + } + + Collection actualQualifiers = getActualQualifiers().stream() + .map(BeanManagerUtil::qualifierToString).collect(Collectors.toCollection(HashSet::new)); + Collection qualifiers = annotations.stream().map(BeanManagerUtil::qualifierToString) + .collect(Collectors.toCollection(HashSet::new)); + return actualQualifiers.containsAll(qualifiers); } @Override @@ -114,22 +121,10 @@ public String getName() { return actualType.getCanonicalName(); } - @Override - public String toString() { - String qualifiers = ""; - if (this.qualifiers != null) { - qualifiers = BeanManagerUtil - .qualifiersToString(this.qualifiers.toArray(new Annotation[this.qualifiers.size()])); - } - - return "[type=" + actualType + ", scope=" + scope.getSimpleName() + ", qualifiers=" + qualifiers - + "]"; - } - @Override public T getInstance() { - if (!factory.isPresent()) { - BeanManagerUtil.noFactoryResolutionException(actualType, + if (factory.isEmpty()) { + throw BeanManagerUtil.noFactoryResolutionException(actualType, qualifiers.toArray(new Annotation[qualifiers.size()])); } return factory.get().getInstance(); @@ -137,17 +132,27 @@ public T getInstance() { @Override public T newInstance() { - if (!factory.isPresent()) { - BeanManagerUtil.noFactoryResolutionException(actualType, + if (factory.isEmpty()) { + throw BeanManagerUtil.noFactoryResolutionException(actualType, qualifiers.toArray(new Annotation[qualifiers.size()])); } return factory.get().createInstance(); } + @Override + public Optional> getFactory() { + return factory; + } + public Optional getTyped() { return typed; } + @Override + public int hashCode() { + return Objects.hash(actualType); + } + @Override public boolean equals(Object o) { if (this == o) @@ -159,8 +164,20 @@ public boolean equals(Object o) { } @Override - public int hashCode() { - return Objects.hash(actualType); + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SyncBeanDefImpl [actualType="); + builder.append(actualType).append(", scope="); + builder.append(scope).append(","); + if (this.qualifiers != null) { + String qualifiers = BeanManagerUtil + .qualifiersToString(this.qualifiers.toArray(new Annotation[this.qualifiers.size()])); + builder.append("qualifiers="); + builder.append(qualifiers).append(","); + } + builder.append("assignableTypes=").append(assignableTypes); + builder.append(", factory=").append(factory).append("]"); + return builder.toString(); } public static class Builder { @@ -197,6 +214,7 @@ public Builder withFactory(BeanFactory factory) { return this; } + @SuppressWarnings("unchecked") public SyncBeanDefImpl build() { SyncBeanDefImpl definition = new SyncBeanDefImpl(actualType, scope); if (qualifiers != null) { diff --git a/core/src/main/java/io/crysknife/client/internal/temp b/core/src/main/java/io/crysknife/client/internal/temp new file mode 100644 index 00000000..74cbfb0d --- /dev/null +++ b/core/src/main/java/io/crysknife/client/internal/temp @@ -0,0 +1,283 @@ +/* + * Copyright © 2020 Treblereel + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package io.crysknife.client.internal; + +import io.crysknife.client.BeanManager; +import io.crysknife.client.IOCBeanDef; +import io.crysknife.client.SyncBeanDef; +import jakarta.enterprise.inject.Typed; + +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +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 beans = new HashMap<>(); + + private final Map pool = new HashMap<>(); + private final Map beansByBeanName = new HashMap<>(); + + private final Predicate isTyped = + syncBeanDef -> syncBeanDef.getTyped().isPresent(); + private final Predicate isNotTyped = + syncBeanDef -> syncBeanDef.getTyped().isEmpty(); + + private final Predicate hasFactory = + syncBeanDef -> syncBeanDef.getFactory().isPresent(); + + + protected AbstractBeanManager() { + + } + + public void register(final SyncBeanDefImpl beanDefinition) { + BeanDefinitionHolder holder = + beans.computeIfAbsent(beanDefinition.getType(), k -> new BeanDefinitionHolder()); + for (Class superType : (Collection>) beanDefinition.getAssignableTypes()) { + beans.computeIfAbsent(superType, k -> new BeanDefinitionHolder()).subTypes.add(holder); + beansByBeanName.put(superType.getCanonicalName(), superType); + } + Set temp = new HashSet(beanDefinition.getActualQualifiers()); + holder.qualifiers.put(temp, beanDefinition); + beansByBeanName.put(beanDefinition.getName(), beanDefinition.getType()); + } + + @Override + public Collection lookupBeans(String name) { + if (beansByBeanName.containsKey(name)) { + return lookupBeans(beansByBeanName.get(name)); + } + return Collections.EMPTY_SET; + } + + public Collection> lookupBeans(final Class type) { + Set> result = new HashSet<>(); + if (!beans.containsKey(type)) { + return result; + } + if (beans.get(type) != null) { + beans.get(type).qualifiers.values().stream().map(f -> (SyncBeanDef) f) + .forEach(result::add); + beans.get(type).subTypes.stream().flatMap(f -> f.qualifiers.values().stream()) + .map(f -> (SyncBeanDef) f).forEach(result::add); + } + return result; + } + + public Collection> lookupBeans(final Class type, Annotation... qualifiers) { + Set> result = new HashSet<>(); + if (!beans.containsKey(type)) { + return result; + } + + if (qualifiers.length == 0) { + return lookupBeans(type); + } + + of(beans.get(type)).filter(bean -> bean.matches(Set.of(qualifiers))) + .map(f -> (SyncBeanDef) f).forEach(result::add); + + return result; + } + + public SyncBeanDef lookupBean(final Class type) { + Collection> candidates = doLookupBean(type); + + if (candidates.size() > 1) { + throw BeanManagerUtil.ambiguousResolutionException(type, candidates, DEFAULT_ANNOTATION); + } else if (candidates.isEmpty()) { + throw BeanManagerUtil.unsatisfiedResolutionException(type, DEFAULT_ANNOTATION); + } else { + return (SyncBeanDef) candidates.iterator().next(); + } + } + + public SyncBeanDef lookupBean(final Class type, Annotation... qualifiers) { + Collection> candidates = doLookupBean(type, qualifiers); + + if (candidates.size() > 1) { + throw BeanManagerUtil.ambiguousResolutionException(type, candidates, qualifiers); + } else if (candidates.isEmpty()) { + throw BeanManagerUtil.unsatisfiedResolutionException(type, qualifiers); + } else { + return (SyncBeanDef) candidates.iterator().next(); + } + } + + public void destroyBean(Object ref) { + if (pool.containsKey(ref)) { + pool.get(ref).onDestroyInternal(ref); + pool.remove(ref); + } + } + + private Collection> doLookupBean(final Class type, + final Annotation... qualifiers) { + if (!beans.containsKey(type)) { + return Collections.EMPTY_SET; + } + + Collection> candidates = new HashSet<>(); + BeanDefinitionHolder holder = beans.get(type); + + Optional> maybeTyped = of(holder, isTyped) + .filter(bean -> Arrays.asList(((Typed) bean.getTyped().get()).value()).contains(type)) + .map(bean -> (IOCBeanDef) bean).findFirst(); + + if (maybeTyped.isPresent()) { + return Set.of(maybeTyped.get()); + } + + of(holder).filter(bean -> { + Set temp = new HashSet<>(bean.getActualQualifiers()); + Collections.addAll(temp, DEFAULT_QUALIFIERS); + return compareAnnotations(temp, qualifiers); + }).filter(hasFactory).forEach(bean -> candidates.add((IOCBeanDef) bean)); + + if (qualifiers.length == 1 && isDefault(qualifiers)) { + Optional> maybeSpecialized = + of(holder).filter(bean -> bean.matches(Set.of(SPECIALIZES_ANNOTATION))) + .map(bean -> (IOCBeanDef) bean).findFirst(); + + // TODO this is not correct, specialized bean totally overrides the parent bean, including + // qualifiers + if (maybeSpecialized.isPresent()) { + return Set.of(maybeSpecialized.get()); + } + + Optional> maybeDefault = Stream + .of(holder.subTypes.stream().flatMap(f -> f.qualifiers.values().stream()), + holder.qualifiers.values().stream()) + .flatMap(Function.identity()).filter(bean -> bean.getTyped().isEmpty()) + .filter(bean -> bean.matches(Set.of(DEFAULT_ANNOTATION))) + .map(bean -> (IOCBeanDef) bean).findFirst(); + + if (maybeDefault.isPresent()) { + return Set.of(maybeDefault.get()); + } + + Stream + .of(holder.subTypes.stream().flatMap(f -> f.qualifiers.values().stream()), + holder.qualifiers.values().stream()) + .flatMap(Function.identity()).filter(bean -> bean.getTyped().isEmpty()) + .filter(bean -> bean.matches(Set.of(DEFAULT_ANNOTATION))) + .filter(bean -> bean.getFactory().isPresent()).map(bean -> (IOCBeanDef) bean) + .forEach(candidates::add); + } else if (qualifiers.length == 1 && isAny(qualifiers)) { + + Stream + .of(holder.subTypes.stream().flatMap(f -> f.qualifiers.values().stream()), + holder.qualifiers.values().stream()) + .flatMap(Function.identity()) + // .filter(bean -> bean.getTyped().isEmpty()) //TODO not sure about this, may I have to + // filter out @typed beans + .filter(bean -> bean.getFactory().isPresent()).map(bean -> (IOCBeanDef) bean) + .forEach(candidates::add); + } else { + + Stream + .of(holder.subTypes.stream().flatMap(f -> f.qualifiers.values().stream()), + holder.qualifiers.values().stream()) + .flatMap(Function.identity()).filter(bean -> bean.getTyped().isEmpty()) + .filter(bean -> bean.matches(Set.of(qualifiers))) + .filter(bean -> bean.getFactory().isPresent()).map(bean -> (IOCBeanDef) bean) + .forEach(candidates::add); + } + return candidates; + } + + private Stream of(BeanDefinitionHolder holder, + Predicate... filters) { + Stream stream = + Stream.of(holder.subTypes.stream().flatMap(f -> f.qualifiers.values().stream()), + holder.qualifiers.values().stream()).flatMap(Function.identity()); + for (Predicate filter : filters) { + stream = stream.filter(filter); + } + + return stream; + } + + private boolean compareAnnotations(Collection 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[] {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 Collection> doLookupBean(final Class type) { + Collection> candidates = new HashSet<>(); + if (beans.containsKey(type)) { + if (!beans.get(type).qualifiers.isEmpty()) { + beans.get(type).qualifiers.values().forEach(candidates::add); + } else { + Stream + .of(beans.get(type).subTypes.stream().flatMap(f -> f.qualifiers.values().stream()), + beans.get(type).qualifiers.values().stream()) + .flatMap(Function.identity()).filter(bean -> bean.getTyped().isEmpty()) + .filter(syncBeanDef -> { + if (syncBeanDef.getActualQualifiers().isEmpty()) { + return true; + } else { + return syncBeanDef.matches(Set.of(DEFAULT_ANNOTATION)); + } + }).filter(bean -> bean.getFactory().isPresent()).map(bean -> (IOCBeanDef) bean) + .forEach(candidates::add); + } + } + return candidates; + } + + T addBeanInstanceToPool(Object instance, BeanFactory factory) { + pool.put(instance, factory); + return (T) instance; + } + + private static class BeanDefinitionHolder { + + private final Set subTypes = new HashSet<>(); + private final Map, SyncBeanDefImpl> qualifiers = new HashMap<>(); + + } +} diff --git a/processor/src/main/java/io/crysknife/definition/BeanDefinition.java b/processor/src/main/java/io/crysknife/definition/BeanDefinition.java index 1a30428c..794bdb2e 100644 --- a/processor/src/main/java/io/crysknife/definition/BeanDefinition.java +++ b/processor/src/main/java/io/crysknife/definition/BeanDefinition.java @@ -37,18 +37,17 @@ public class BeanDefinition implements Definition { private final TypeMirror type; - private final Set fields = new LinkedHashSet<>(); private final Set constructorParams = new LinkedHashSet<>(); private final Set methods = new LinkedHashSet<>(); private final Set dependencies = new LinkedHashSet<>(); private final Set> decorators = new LinkedHashSet<>(); private Optional> iocGenerator = Optional.empty(); + private final Set subclasses = new LinkedHashSet<>(); private boolean hasFactory = true; private boolean factoryGenerationFinished = false; - private final Set subclasses = new LinkedHashSet<>(); public BeanDefinition(TypeMirror type) { this.type = type; @@ -140,6 +139,15 @@ public void setHasFactory(boolean hasFactory) { this.hasFactory = hasFactory; } + + public boolean isFactoryGenerationFinished() { + return factoryGenerationFinished; + } + + public void setFactoryGenerationFinished(boolean factoryGenerationFinished) { + this.factoryGenerationFinished = factoryGenerationFinished; + } + @Override public int hashCode() { return Objects.hash(MoreTypes.asTypeElement(type).getQualifiedName().toString()); @@ -155,12 +163,4 @@ public boolean equals(Object o) { return MoreTypes.asTypeElement(type).getQualifiedName().toString() .equals(MoreTypes.asTypeElement(that.type).getQualifiedName().toString()); } - - public boolean isFactoryGenerationFinished() { - return factoryGenerationFinished; - } - - public void setFactoryGenerationFinished(boolean factoryGenerationFinished) { - this.factoryGenerationFinished = factoryGenerationFinished; - } } diff --git a/processor/src/main/java/io/crysknife/definition/BeanDefinitionFactory.java b/processor/src/main/java/io/crysknife/definition/BeanDefinitionFactory.java index 583b6995..5142f3fd 100644 --- a/processor/src/main/java/io/crysknife/definition/BeanDefinitionFactory.java +++ b/processor/src/main/java/io/crysknife/definition/BeanDefinitionFactory.java @@ -19,9 +19,12 @@ import io.crysknife.logger.TreeLogger; import io.crysknife.processor.ConstructorInjectionPointProcessor; import io.crysknife.processor.FieldProcessor; +import io.crysknife.util.TypeUtils; +import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.ExecutableElement; import javax.lang.model.type.TypeMirror; +import java.util.List; /** * @author Dmitrii Tikhomirov Created by treblereel 9/3/21 @@ -50,8 +53,9 @@ public BeanDefinition of(TypeMirror type) throws UnableToCompleteException { } public ProducesBeanDefinition of(ExecutableElement produces) throws UnableToCompleteException { - ProducesBeanDefinition bean = new ProducesBeanDefinition(produces); - return bean; + List qualifiers = + TypeUtils.getAllElementQualifierAnnotations(context, produces); + return new ProducesBeanDefinition(produces, qualifiers); } private void validateBean(TypeMirror type) { diff --git a/processor/src/main/java/io/crysknife/definition/ProducesBeanDefinition.java b/processor/src/main/java/io/crysknife/definition/ProducesBeanDefinition.java index 074d0ca6..fcf03643 100644 --- a/processor/src/main/java/io/crysknife/definition/ProducesBeanDefinition.java +++ b/processor/src/main/java/io/crysknife/definition/ProducesBeanDefinition.java @@ -15,13 +15,17 @@ package io.crysknife.definition; import com.google.auto.common.MoreElements; - import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.Dependent; import jakarta.inject.Singleton; + +import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import java.lang.annotation.Annotation; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * @author Dmitrii Tikhomirov Created by treblereel 9/6/21 @@ -30,16 +34,34 @@ public class ProducesBeanDefinition extends BeanDefinition { private ExecutableElement method; - public ProducesBeanDefinition(ExecutableElement method) { + private List qualifiers; + + private Set subtypes = new HashSet<>(); + + + public ProducesBeanDefinition(ExecutableElement method, List qualifiers) { super(method.getReturnType()); + super.setHasFactory(false); this.method = method; - setHasFactory(false); + this.qualifiers = qualifiers; + } + + public void addSubtype(ProducesBeanDefinition subtype) { + subtypes.add(subtype); + } + + public Set getSubtypes() { + return new HashSet<>(subtypes); } public ExecutableElement getMethod() { return method; } + public List getQualifier() { + return qualifiers; + } + public TypeElement getProducer() { return MoreElements.asType(method.getEnclosingElement()); } @@ -67,4 +89,5 @@ public Class annotationType() { } }; } + } diff --git a/processor/src/main/java/io/crysknife/generator/SingletonGenerator.java b/processor/src/main/java/io/crysknife/generator/SingletonGenerator.java index 8233c0de..19792ead 100644 --- a/processor/src/main/java/io/crysknife/generator/SingletonGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/SingletonGenerator.java @@ -18,6 +18,7 @@ import com.github.javaparser.ast.expr.FieldAccessExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.ast.expr.StringLiteralExpr; import com.github.javaparser.ast.type.ClassOrInterfaceType; import freemarker.template.Configuration; import freemarker.template.Template; @@ -36,6 +37,7 @@ import io.crysknife.util.TypeUtils; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.Dependent; +import jakarta.inject.Named; import jakarta.inject.Singleton; import io.crysknife.generator.api.Generator; @@ -44,6 +46,7 @@ import io.crysknife.logger.TreeLogger; import javax.annotation.processing.FilerException; +import javax.lang.model.element.AnnotationMirror; import javax.tools.JavaFileObject; import java.io.IOException; import java.io.OutputStreamWriter; @@ -233,9 +236,6 @@ protected String generateFactoryFieldDeclaration(InjectableVariableDefinition fi } else { beanCall = generateBeanLookupCall(fieldPoint); } - - // Expression beanCall = fieldPoint.generate(iocContext); - if (beanCall == null) { throw new GenerationException("No bean call for " + fieldPoint.getVariableElement().asType()); } @@ -245,8 +245,25 @@ protected String generateFactoryFieldDeclaration(InjectableVariableDefinition fi public String generateBeanLookupCall(InjectableVariableDefinition fieldPoint) { String typeQualifiedName = generationUtils.getActualQualifiedBeanName(fieldPoint); - return new MethodCallExpr(new NameExpr("beanManager"), "lookupBean") - .addArgument(new FieldAccessExpr(new NameExpr(typeQualifiedName), "class")).toString(); + + MethodCallExpr call = new MethodCallExpr(new NameExpr("beanManager"), "lookupBean") + .addArgument(new FieldAccessExpr(new NameExpr(typeQualifiedName), "class")); + + if (fieldPoint.getImplementation().isEmpty()) { + List qualifiers = new ArrayList<>( + TypeUtils.getAllElementQualifierAnnotations(iocContext, fieldPoint.getVariableElement())); + for (AnnotationMirror qualifier : qualifiers) { + call.addArgument(generationUtils.createQualifierExpression(qualifier)); + } + Named named = fieldPoint.getVariableElement().getAnnotation(Named.class); + if (named != null) { + call.addArgument(new MethodCallExpr( + new NameExpr("io.crysknife.client.internal.QualifierUtil"), "createNamed") + .addArgument(new StringLiteralExpr( + fieldPoint.getVariableElement().getAnnotation(Named.class).value()))); + } + } + return call.toString(); } public static class Dep { diff --git a/processor/src/main/java/io/crysknife/generator/context/oracle/BeanOracle.java b/processor/src/main/java/io/crysknife/generator/context/oracle/BeanOracle.java index 582f45c2..7f6f0dec 100644 --- a/processor/src/main/java/io/crysknife/generator/context/oracle/BeanOracle.java +++ b/processor/src/main/java/io/crysknife/generator/context/oracle/BeanOracle.java @@ -155,10 +155,6 @@ private boolean isUnscopedBean(TypeMirror beanTypeMirror) { return false; } - public Optional guessDefaultImpl(TypeMirror point) { - return asInterfaceOrAbstractClass(point); - } - private Optional asInterfaceOrAbstractClass(TypeMirror point) { Set subclasses = getSubClasses(point); @@ -189,14 +185,16 @@ private Optional asInterfaceOrAbstractClass(TypeMirror point) { .collect(Collectors.toSet()); if (!maybeTyped.isEmpty()) { TypeMirror mirror = context.getGenerationContext().getTypes().erasure(point); - for (BeanDefinition typed : maybeTyped) { + return Optional.of(context.getBean(mirror)); + + /* for (BeanDefinition typed : maybeTyped) { Optional> annotations = getTypedAnnotationValues(typed.getType()); if (annotations.isPresent()) { if (annotations.get().contains(mirror)) { return Optional.of(typed); } } - } + }*/ } } return Optional.empty(); diff --git a/processor/src/main/java/io/crysknife/generator/info/InterceptorGenerator.java b/processor/src/main/java/io/crysknife/generator/info/InterceptorGenerator.java index 82e0add6..e420a857 100644 --- a/processor/src/main/java/io/crysknife/generator/info/InterceptorGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/info/InterceptorGenerator.java @@ -17,6 +17,7 @@ import com.github.javaparser.ast.expr.FieldAccessExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.ast.expr.StringLiteralExpr; import com.google.auto.common.MoreTypes; import freemarker.template.Configuration; import freemarker.template.Template; @@ -24,12 +25,16 @@ import freemarker.template.TemplateExceptionHandler; import io.crysknife.definition.BeanDefinition; import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.definition.ProducesBeanDefinition; import io.crysknife.exception.GenerationException; import io.crysknife.generator.context.IOCContext; import io.crysknife.util.StringOutputStream; import io.crysknife.util.GenerationUtils; +import io.crysknife.util.TypeUtils; +import jakarta.inject.Named; import javax.annotation.processing.FilerException; +import javax.lang.model.element.AnnotationMirror; import javax.tools.JavaFileObject; import java.io.IOException; import java.io.OutputStreamWriter; @@ -126,8 +131,23 @@ private String getCall(InjectableVariableDefinition fieldPoint) { _beanCall = fieldPoint.getGenerator().get().generateBeanLookupCall(fieldPoint); } else { String name = generationUtils.getActualQualifiedBeanName(fieldPoint); - _beanCall = new MethodCallExpr(new NameExpr("beanManager"), "lookupBean") - .addArgument(new FieldAccessExpr(new NameExpr(name), "class")).toString(); + MethodCallExpr call = new MethodCallExpr(new NameExpr("beanManager"), "lookupBean") + .addArgument(new FieldAccessExpr(new NameExpr(name), "class")); + if (fieldPoint.getImplementation().isEmpty()) { + List qualifiers = new ArrayList<>(TypeUtils + .getAllElementQualifierAnnotations(iocContext, fieldPoint.getVariableElement())); + for (AnnotationMirror qualifier : qualifiers) { + call.addArgument(generationUtils.createQualifierExpression(qualifier)); + } + Named named = fieldPoint.getVariableElement().getAnnotation(Named.class); + if (named != null) { + call.addArgument(new MethodCallExpr( + new NameExpr("io.crysknife.client.internal.QualifierUtil"), "createNamed") + .addArgument(new StringLiteralExpr( + fieldPoint.getVariableElement().getAnnotation(Named.class).value()))); + } + } + _beanCall = call.toString(); } return _beanCall; } diff --git a/processor/src/main/java/io/crysknife/processor/ProducesProcessor.java b/processor/src/main/java/io/crysknife/processor/ProducesProcessor.java index 70605c17..dd6b5a91 100644 --- a/processor/src/main/java/io/crysknife/processor/ProducesProcessor.java +++ b/processor/src/main/java/io/crysknife/processor/ProducesProcessor.java @@ -76,10 +76,17 @@ public void process(Element produce) throws UnableToCompleteException { if (generator.isPresent()) { ProducesBeanDefinition beanDefinition = beanDefinitionFactory.of(method); - beanDefinition.setIocGenerator(generator.get()); + generator.ifPresent(beanDefinition::setIocGenerator); TypeMirror beanTypeMirror = iocContext.getGenerationContext().getTypes().erasure(method.getReturnType()); - iocContext.getBeans().put(beanTypeMirror, beanDefinition); + // TODO this must be refactored + if (iocContext.getBeans().containsKey(beanTypeMirror) + && iocContext.getBeans().get(beanTypeMirror) instanceof ProducesBeanDefinition) { + ((ProducesBeanDefinition) iocContext.getBeans().get(beanTypeMirror)) + .addSubtype(beanDefinition); + } else { + iocContext.getBeans().put(beanTypeMirror, beanDefinition); + } } } diff --git a/processor/src/main/java/io/crysknife/task/BeanManagerGeneratorTask.java b/processor/src/main/java/io/crysknife/task/BeanManagerGeneratorTask.java index 863bcd58..66708668 100644 --- a/processor/src/main/java/io/crysknife/task/BeanManagerGeneratorTask.java +++ b/processor/src/main/java/io/crysknife/task/BeanManagerGeneratorTask.java @@ -54,18 +54,18 @@ import io.crysknife.exception.GenerationException; import io.crysknife.exception.UnableToCompleteException; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.context.oracle.BeanOracle; import io.crysknife.logger.TreeLogger; import io.crysknife.util.GenerationUtils; import io.crysknife.util.TypeUtils; - import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.Instance; import jakarta.enterprise.inject.Specializes; import jakarta.enterprise.inject.Typed; import jakarta.inject.Named; import jakarta.inject.Provider; + import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.MirroredTypesException; import javax.lang.model.type.TypeMirror; @@ -86,14 +86,13 @@ /** * @author Dmitrii Tikhomirov Created by treblereel 3/28/19 */ +// TODO this class must be refactored public class BeanManagerGeneratorTask implements Task { private final IOCContext iocContext; private final GenerationUtils generationUtils; - private final BeanOracle oracle; - private final TypeMirror OBJECT; private TreeLogger logger; @@ -101,7 +100,6 @@ public class BeanManagerGeneratorTask implements Task { public BeanManagerGeneratorTask(IOCContext iocContext, TreeLogger logger) { this.iocContext = iocContext; this.logger = logger; - this.oracle = new BeanOracle(iocContext, logger); this.generationUtils = new GenerationUtils(iocContext); OBJECT = iocContext.getGenerationContext().getElements() .getTypeElement(Object.class.getCanonicalName()).asType(); @@ -181,13 +179,6 @@ private void addFields() { addBeanInstance(); } - private void addBeanInstance() { - ClassOrInterfaceType type = new ClassOrInterfaceType(); - type.setName(BeanManager.class.getSimpleName() + "Impl"); - classDeclaration.addField(type, "instance", Modifier.Keyword.STATIC, - Modifier.Keyword.PRIVATE); - } - private void initInitMethod() { init = classDeclaration.addMethod("init", Modifier.Keyword.PRIVATE); addBeanManager(init); @@ -222,74 +213,16 @@ private void initInitMethod() { } }); - - List qualifiers = new ArrayList<>(TypeUtils - .getAllElementQualifierAnnotations(iocContext, MoreTypes.asElement(erased))); - Set qualifiersExpression = new HashSet<>(); - - qualifiers.forEach(type -> qualifiersExpression - .add(generationUtils.createQualifierExpression(type))); - Named named = MoreTypes.asTypeElement(erased).getAnnotation(Named.class); - if (named != null) { - qualifiersExpression - .add(new MethodCallExpr(new NameExpr("QualifierUtil"), "createNamed") - .addArgument(new StringLiteralExpr( - MoreTypes.asTypeElement(bean).getAnnotation(Named.class).value()))); - } - - if (MoreTypes.asTypeElement(bean).getAnnotation(Default.class) != null) { - qualifiersExpression.add(new NameExpr("DEFAULT_ANNOTATION")); - } - - if (MoreTypes.asTypeElement(bean).getAnnotation(Specializes.class) != null) { - qualifiersExpression.add(new NameExpr("SPECIALIZES_ANNOTATION")); - } - - - ArrayInitializerExpr withAssignableTypesValues = new ArrayInitializerExpr(); - assignableTypes.forEach(type -> withAssignableTypesValues.getValues() - .add(new NameExpr(type + ".class"))); - - ArrayCreationExpr withAssignableTypes = new ArrayCreationExpr(); - withAssignableTypes.setElementType("Class[]"); - withAssignableTypes.setInitializer(withAssignableTypesValues); - - ArrayInitializerExpr withQualifiersValues = new ArrayInitializerExpr(); - qualifiersExpression.forEach(type -> withQualifiersValues.getValues().add(type)); - ArrayCreationExpr withQualifiers = new ArrayCreationExpr(); - withQualifiers.setElementType("Annotation[]"); - withQualifiers.setInitializer(withQualifiersValues); - - MethodCallExpr registerCallExpr = new MethodCallExpr("register"); Expression builderCallExpr = new ObjectCreationExpr().setType("Builder").addArgument(erased + ".class") .addArgument(scope.annotationType().getCanonicalName() + ".class"); - builderCallExpr = new MethodCallExpr(builderCallExpr, "withAssignableTypes") - .addArgument(withAssignableTypes); - - if (!qualifiersExpression.isEmpty()) { - builderCallExpr = new MethodCallExpr(builderCallExpr, "withQualifiers") - .addArgument(withQualifiers); - } - - if (MoreTypes.asTypeElement(bean).getAnnotation(Typed.class) != null) { - Typed typed = MoreTypes.asTypeElement(bean).getAnnotation(Typed.class); - MethodCallExpr createTyped = - new MethodCallExpr(new NameExpr("QualifierUtil"), "createTyped"); - try { - typed.value(); - } catch (MirroredTypesException types) { - List mirrors = (List) types.getTypeMirrors(); - mirrors - .forEach(mirror -> createTyped.addArgument(mirror.toString() + ".class")); - - builderCallExpr = - new MethodCallExpr(builderCallExpr, "withTyped").addArgument(createTyped); - } - } + builderCallExpr = addAssignableTypes(assignableTypes, builderCallExpr); + builderCallExpr = + maybeAddQualifierExpression(MoreTypes.asElement(erased), builderCallExpr); + builderCallExpr = maybeAddTypedExpression(bean, builderCallExpr); builderCallExpr = new MethodCallExpr(builderCallExpr, "withFactory").addArgument( new ObjectCreationExpr().setType(TypeUtils.getQualifiedFactoryName(erased)) @@ -297,21 +230,97 @@ private void initInitMethod() { builderCallExpr = new MethodCallExpr(builderCallExpr, "build"); registerCallExpr.addArgument(builderCallExpr); - init.getBody().get().addAndGetStatement(registerCallExpr); + init.getBody().ifPresent(body -> body.addAndGetStatement(registerCallExpr)); } } } }); } - private boolean isSuitableBeanDefinition(BeanDefinition beanDefinition) { - return MoreTypes.asTypeElement(beanDefinition.getType()).getKind().isClass() - && !MoreTypes.asTypeElement(beanDefinition.getType()).getModifiers().contains(ABSTRACT) - && beanDefinition.getIocGenerator().isPresent() && beanDefinition.hasFactory(); + private Expression maybeAddTypedExpression(TypeMirror bean, Expression builderCallExpr) { + if (MoreTypes.asTypeElement(bean).getAnnotation(Typed.class) != null) { + Typed typed = MoreTypes.asTypeElement(bean).getAnnotation(Typed.class); + MethodCallExpr createTyped = + new MethodCallExpr(new NameExpr("QualifierUtil"), "createTyped"); + try { + typed.value(); + } catch (MirroredTypesException types) { + List mirrors = (List) types.getTypeMirrors(); + mirrors.forEach(mirror -> createTyped.addArgument(mirror.toString() + ".class")); + + builderCallExpr = + new MethodCallExpr(builderCallExpr, "withTyped").addArgument(createTyped); + } + } + return builderCallExpr; + } + + private Expression addAssignableTypes(List assignableTypes, + Expression builderCallExpr) { + ArrayInitializerExpr withAssignableTypesValues = new ArrayInitializerExpr(); + assignableTypes.forEach( + type -> withAssignableTypesValues.getValues().add(new NameExpr(type + ".class"))); + + ArrayCreationExpr withAssignableTypes = new ArrayCreationExpr(); + withAssignableTypes.setElementType("Class[]"); + withAssignableTypes.setInitializer(withAssignableTypesValues); + + builderCallExpr = new MethodCallExpr(builderCallExpr, "withAssignableTypes") + .addArgument(withAssignableTypes); + return builderCallExpr; + } + + private void addGetInstanceMethod() { + getMethodDeclaration = + classDeclaration.addMethod("get", Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC); + getMethodDeclaration.setType(BeanManager.class.getSimpleName()); + addGetBody(); + } + + private void addBeanInstance() { + ClassOrInterfaceType type = new ClassOrInterfaceType(); + type.setName(BeanManager.class.getSimpleName() + "Impl"); + classDeclaration.addField(type, "instance", Modifier.Keyword.STATIC, + Modifier.Keyword.PRIVATE); + } + + private void addBeanManager(MethodDeclaration init) { + ArrayInitializerExpr withAssignableTypesValues = new ArrayInitializerExpr(); + withAssignableTypesValues.getValues().add(new NameExpr("BeanManager.class")); + + ArrayCreationExpr withAssignableTypes = new ArrayCreationExpr(); + withAssignableTypes.setElementType("Class[]"); + withAssignableTypes.setInitializer(withAssignableTypesValues); + + + MethodCallExpr registerCallExpr = new MethodCallExpr("register"); + + Expression builderCallExpr = + new ObjectCreationExpr().setType("Builder").addArgument("BeanManager.class") + .addArgument("jakarta.enterprise.context.ApplicationScoped.class"); + + builderCallExpr = new MethodCallExpr(builderCallExpr, "withAssignableTypes") + .addArgument(withAssignableTypes); + + builderCallExpr = new MethodCallExpr(builderCallExpr, "withQualifiers") + .addArgument(new NameExpr("new Annotation[] { DEFAULT_ANNOTATION }")); + + + builderCallExpr = new MethodCallExpr(builderCallExpr, "withFactory").addArgument(new NameExpr( + "new BeanFactory(this){\n" + "\n" + " @Override\n" + + " public BeanManager getInstance() {\n" + + " return BeanManagerImpl.this;\n" + " }\n" + + " }")); + + builderCallExpr = new MethodCallExpr(builderCallExpr, "build"); + registerCallExpr.addArgument(builderCallExpr); + + + init.getBody().ifPresent(body -> body.addAndGetStatement(registerCallExpr)); } - private void addProducesBeanDefinition(ProducesBeanDefinition beanDefinition) { - ProducesBeanDefinition producesBeanDefinition = beanDefinition; + private void addProducesBeanDefinition(ProducesBeanDefinition producesBeanDefinition) { + producesBeanDefinition.getSubtypes().forEach(this::addProducesBeanDefinition); TypeMirror erased = iocContext.getGenerationContext().getTypes().erasure(producesBeanDefinition.getType()); @@ -332,19 +341,15 @@ private void addProducesBeanDefinition(ProducesBeanDefinition beanDefinition) { assignableTypes.forEach( type -> withAssignableTypesValues.getValues().add(new NameExpr(type + ".class"))); - ArrayCreationExpr withAssignableTypes = new ArrayCreationExpr(); - withAssignableTypes.setElementType("Class[]"); - withAssignableTypes.setInitializer(withAssignableTypesValues); - MethodCallExpr registerCallExpr = new MethodCallExpr("register"); Expression builderCallExpr = new ObjectCreationExpr().setType("Builder").addArgument(erased + ".class") .addArgument(scope.annotationType().getCanonicalName() + ".class"); - builderCallExpr = new MethodCallExpr(builderCallExpr, "withAssignableTypes") - .addArgument(withAssignableTypes); - + builderCallExpr = addAssignableTypes(assignableTypes, builderCallExpr); + builderCallExpr = + maybeAddQualifierExpression(producesBeanDefinition.getMethod(), builderCallExpr); ClassOrInterfaceType producerType = new ClassOrInterfaceType(); producerType.setName(ProducesBeanFactory.class.getCanonicalName()) @@ -364,33 +369,27 @@ private void addProducesBeanDefinition(ProducesBeanDefinition beanDefinition) { annotationType.setName("get"); annotationType.setType(new ClassOrInterfaceType().setName(erased.toString())); - annotationType.getBody().get().addAndGetStatement(new ReturnStmt(new MethodCallExpr( - new MethodCallExpr(new MethodCallExpr( - new FieldAccessExpr(new NameExpr("BeanManagerImpl"), "this"), "lookupBean") - .addArgument(producesBeanDefinition.getProducer().getQualifiedName().toString() - + ".class"), - "getInstance"), - producesBeanDefinition.getMethod().getSimpleName().toString()))); - supplierClassBody.add(annotationType); + annotationType.getBody() + .ifPresent(body -> body.addAndGetStatement(new ReturnStmt(new MethodCallExpr( + new MethodCallExpr( + new MethodCallExpr(new FieldAccessExpr(new NameExpr("BeanManagerImpl"), "this"), + "lookupBean").addArgument( + producesBeanDefinition.getProducer().getQualifiedName().toString() + + ".class"), + "getInstance"), + producesBeanDefinition.getMethod().getSimpleName().toString())))); + supplierClassBody.add(annotationType); supplier.setAnonymousClassBody(supplierClassBody); - ObjectCreationExpr factory = new ObjectCreationExpr().setType(producerType) .addArgument(new ThisExpr()).addArgument(supplier); - builderCallExpr = new MethodCallExpr(builderCallExpr, "withFactory").addArgument(factory); - builderCallExpr = new MethodCallExpr(builderCallExpr, "build"); - registerCallExpr.addArgument(builderCallExpr); - init.getBody().get().addAndGetStatement(registerCallExpr); - - - /* - **************************** - */ + registerCallExpr.addArgument(builderCallExpr); + init.getBody().ifPresent(body -> body.addAndGetStatement(registerCallExpr)); String qualifiedName = MoreTypes.asTypeElement( iocContext.getGenerationContext().getTypes().erasure(producesBeanDefinition.getType())) @@ -444,69 +443,70 @@ private void addProducesBeanDefinition(ProducesBeanDefinition beanDefinition) { new AssignExpr().setTarget(new NameExpr("holder")).setValue(getNewInstance)); ifStmt.setThenStmt(blockStmt); - get.getBody().get().addAndGetStatement(ifStmt); - + get.getBody().ifPresent(body -> body.addAndGetStatement(ifStmt)); VariableDeclarator holder = new VariableDeclarator(new ClassOrInterfaceType().setName(qualifiedName), "holder"); FieldDeclaration field = new FieldDeclaration(); field.getVariables().add(holder); anonymousClassBody.add(field); - - get.getBody().get().addAndGetStatement(new ReturnStmt(new NameExpr("holder"))); + get.getBody() + .ifPresent(body -> body.addAndGetStatement(new ReturnStmt(new NameExpr("holder")))); } else { - get.getBody().get().addAndGetStatement(new ReturnStmt(getNewInstance)); - + get.getBody().ifPresent(body -> body.addAndGetStatement(new ReturnStmt(getNewInstance))); } anonymousClassBody.add(get); provider.setAnonymousClassBody(anonymousClassBody); - MethodCallExpr call = new MethodCallExpr(new ThisExpr(), "register") - .addArgument(new FieldAccessExpr(new NameExpr(qualifiedName), "class")) - .addArgument(newInstance); - - // init.getBody().ifPresent(body -> body.addAndGetStatement(call)); } - private void addBeanManager(MethodDeclaration init) { - ArrayInitializerExpr withAssignableTypesValues = new ArrayInitializerExpr(); - withAssignableTypesValues.getValues().add(new NameExpr("BeanManager.class")); - - ArrayCreationExpr withAssignableTypes = new ArrayCreationExpr(); - withAssignableTypes.setElementType("Class[]"); - withAssignableTypes.setInitializer(withAssignableTypesValues); - - - MethodCallExpr registerCallExpr = new MethodCallExpr("register"); - - Expression builderCallExpr = - new ObjectCreationExpr().setType("Builder").addArgument("BeanManager.class") - .addArgument("jakarta.enterprise.context.ApplicationScoped.class"); - - builderCallExpr = new MethodCallExpr(builderCallExpr, "withAssignableTypes") - .addArgument(withAssignableTypes); - - builderCallExpr = new MethodCallExpr(builderCallExpr, "withQualifiers") - .addArgument(new NameExpr("new Annotation[] { DEFAULT_ANNOTATION }")); - - - builderCallExpr = new MethodCallExpr(builderCallExpr, "withFactory").addArgument(new NameExpr( - "new BeanFactory(this){\n" + "\n" + " @Override\n" - + " public BeanManager getInstance() {\n" - + " return BeanManagerImpl.this;\n" + " }\n" - + " }")); + private boolean isSuitableBeanDefinition(BeanDefinition beanDefinition) { + return MoreTypes.asTypeElement(beanDefinition.getType()).getKind().isClass() + && !MoreTypes.asTypeElement(beanDefinition.getType()).getModifiers().contains(ABSTRACT) + && beanDefinition.getIocGenerator().isPresent() && beanDefinition.hasFactory(); + } - builderCallExpr = new MethodCallExpr(builderCallExpr, "build"); - registerCallExpr.addArgument(builderCallExpr); + private Expression maybeAddQualifierExpression(Element bean, Expression builderCallExpr) { + List qualifiers = + new ArrayList<>(TypeUtils.getAllElementQualifierAnnotations(iocContext, bean)); + Set qualifiersExpression = new HashSet<>(); + + qualifiers.forEach( + type -> qualifiersExpression.add(generationUtils.createQualifierExpression(type))); + Named named = bean.getAnnotation(Named.class); + if (named != null) { + qualifiersExpression.add(new MethodCallExpr(new NameExpr("QualifierUtil"), "createNamed") + .addArgument(new StringLiteralExpr(bean.getAnnotation(Named.class).value()))); + } + if (bean.getAnnotation(Specializes.class) != null) { + qualifiersExpression.add(new NameExpr("SPECIALIZES_ANNOTATION")); + } - init.getBody().ifPresent(body -> body.addAndGetStatement(registerCallExpr)); - } + if (bean.getAnnotation(Default.class) != null) { + qualifiersExpression.add(new NameExpr("DEFAULT_ANNOTATION")); + } - private void addGetInstanceMethod() { - getMethodDeclaration = - classDeclaration.addMethod("get", Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC); - getMethodDeclaration.setType(BeanManager.class.getSimpleName()); - addGetBody(); + // ArrayInitializerExpr withAssignableTypesValues = new ArrayInitializerExpr(); + // assignableTypes.forEach( + // type -> withAssignableTypesValues.getValues().add(new NameExpr(type + ".class"))); + + // ArrayCreationExpr withAssignableTypes = new ArrayCreationExpr(); + // withAssignableTypes.setElementType("Class[]"); + // withAssignableTypes.setInitializer(withAssignableTypesValues); + + ArrayInitializerExpr withQualifiersValues = new ArrayInitializerExpr(); + qualifiersExpression.forEach(type -> withQualifiersValues.getValues().add(type)); + ArrayCreationExpr withQualifiers = new ArrayCreationExpr(); + withQualifiers.setElementType("Annotation[]"); + withQualifiers.setInitializer(withQualifiersValues); + // builderCallExpr = new MethodCallExpr(builderCallExpr, "withAssignableTypes") + // .addArgument(withAssignableTypes); + + if (!qualifiersExpression.isEmpty()) { + builderCallExpr = + new MethodCallExpr(builderCallExpr, "withQualifiers").addArgument(withQualifiers); + } + return builderCallExpr; } private void addGetBody() { diff --git a/processor/src/main/java/io/crysknife/task/BeanProcessorTask.java b/processor/src/main/java/io/crysknife/task/BeanProcessorTask.java index b111ace2..dfdf15a1 100644 --- a/processor/src/main/java/io/crysknife/task/BeanProcessorTask.java +++ b/processor/src/main/java/io/crysknife/task/BeanProcessorTask.java @@ -54,7 +54,6 @@ import java.util.Comparator; import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; @@ -312,10 +311,8 @@ private Optional processBean(TypeElement type) { } private void setBeanDefinitionGenerator(BeanDefinition bean) { - Set annotations = bean.getAnnotationMirrors().stream() + Set intersection = bean.getAnnotationMirrors().stream() .map(anno -> anno.getAnnotationType().toString()).collect(Collectors.toSet()); - - Set intersection = new HashSet<>(annotations); intersection.retainAll(scoped); if (!intersection.isEmpty()) { diff --git a/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerTest.java b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerHolder.java similarity index 100% rename from tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerTest.java rename to tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerHolder.java diff --git a/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateGenerator.java b/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateGenerator.java index 26b1cc1d..55287aa5 100644 --- a/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateGenerator.java +++ b/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateGenerator.java @@ -47,7 +47,6 @@ import io.crysknife.generator.api.Generator; import io.crysknife.generator.api.IOCGenerator; import io.crysknife.generator.api.WiringElementType; -import io.crysknife.generator.context.ExecutionEnv; import io.crysknife.generator.context.IOCContext; import io.crysknife.generator.helpers.MethodCallGenerator; import io.crysknife.logger.TreeLogger; @@ -151,8 +150,7 @@ public TemplateGenerator(TreeLogger treeLogger, IOCContext iocContext) { this.templatedGeneratorUtils = new TemplatedGeneratorUtils(iocContext); this.eventHandlerValidator = new EventHandlerValidator(iocContext); this.methodCallGenerator = new MethodCallGenerator(iocContext); - - isElement = iocContext.getGenerationContext().getProcessingEnvironment().getElementUtils() + this.isElement = iocContext.getGenerationContext().getProcessingEnvironment().getElementUtils() .getTypeElement(IsElement.class.getCanonicalName()); } @@ -172,6 +170,13 @@ public void generate(ClassMetaInfo classMetaInfo, BeanDefinition beanDefinition) TemplateDefinition templateDefinition = new TemplateDefinition(); + maybeHasNotGetMethod(beanDefinition, templateDefinition); + classMetaInfo.addToDoCreateInstance(() -> "setAndInitTemplate()"); + setAndInitTemplate(classMetaInfo, beanDefinition, templateDefinition); + } + + private void maybeHasNotGetMethod(BeanDefinition beanDefinition, + TemplateDefinition templateDefinition) { if (!hasGetElement(beanDefinition)) { Optional executableElement = ElementFilter .methodsIn(isElement.getEnclosedElements()).stream().map(MoreElements::asExecutable) @@ -180,13 +185,11 @@ public void generate(ClassMetaInfo classMetaInfo, BeanDefinition beanDefinition) if (executableElement.isPresent()) { templateDefinition.setInitRootElement(true); - String valueName = + String mangledName = j2CLUtils.createDeclarationMethodDescriptor(executableElement.get()).getMangledName(); - templateDefinition.setRootElementPropertyName(valueName); + templateDefinition.setRootElementPropertyName(mangledName); } } - classMetaInfo.addToDoCreateInstance(() -> "setAndInitTemplate()"); - setAndInitTemplate(classMetaInfo, beanDefinition, templateDefinition); } private void setAndInitTemplate(ClassMetaInfo classMetaInfo, BeanDefinition beanDefinition, From efe801fd8d40e7c3d0aa2b7a9f56b92c54781691 Mon Sep 17 00:00:00 2001 From: Dmitrii Tikhomirov Date: Mon, 14 Aug 2023 02:05:37 -0700 Subject: [PATCH 3/5] added tests for @Produces with @Named and @Qualifier --- .../cdi/src/main/java/org/treblereel/App.java | 6 +- .../typed/ApplicationCommandManager.java | 2 - .../treblereel/produces/named/ParentBean.java | 20 +++++ .../produces/named/ParentBeanProducer.java | 46 ++++++++++++ .../named/ProducesNamedBeanHolder.java | 74 +++++++++++++++++++ .../qualifier/QualifierBeanProducer.java | 14 +++- .../QualifierBeanProducerHolder.java | 43 ++++++++++- .../java/org/treblereel/BeanManagerTest.java | 4 +- .../treblereel/SimpleBeanProducerTest.java | 2 +- .../org/treblereel/injection/TypedTest.java | 6 +- .../ManagedInstanceBeanTest.java | 8 +- .../named/ProducesNamedBeanHolderTest.java | 71 ++++++++++++++++++ .../ProducesNamedBeanHolderTest.java | 66 +++++++++++++++++ 13 files changed, 343 insertions(+), 19 deletions(-) create mode 100644 tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ParentBean.java create mode 100644 tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ParentBeanProducer.java create mode 100644 tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ProducesNamedBeanHolder.java create mode 100644 tests/jre-tests/cdi/src/test/java/org/treblereel/produces/named/ProducesNamedBeanHolderTest.java create mode 100644 tests/jre-tests/cdi/src/test/java/org/treblereel/produces/qualifier/ProducesNamedBeanHolderTest.java diff --git a/tests/jre-tests/cdi/src/main/java/org/treblereel/App.java b/tests/jre-tests/cdi/src/main/java/org/treblereel/App.java index 17c3892e..cac32d43 100644 --- a/tests/jre-tests/cdi/src/main/java/org/treblereel/App.java +++ b/tests/jre-tests/cdi/src/main/java/org/treblereel/App.java @@ -34,7 +34,7 @@ import org.treblereel.injection.singleton.SimpleSingletonTest; import org.treblereel.postconstruct.PostConstructs; import org.treblereel.produces.SimpleBeanProducerTest; -import org.treblereel.produces.qualifier.QualifierBeanProducerTest; +import org.treblereel.produces.qualifier.QualifierBeanProducerHolder; /** * @author Dmitrii Tikhomirov Created by treblereel 3/21/20 @@ -65,7 +65,7 @@ public class App { private SimpleBeanProducerTest simpleBeanProducerTest; @Inject - private QualifierBeanProducerTest qualifierBeanProducerTest; + private QualifierBeanProducerHolder qualifierBeanProducerTest; @Inject private ManagedInstanceBean managedInstanceBean; @@ -130,7 +130,7 @@ public void setSimpleBeanProducerTest(SimpleBeanProducerTest simpleBeanProducerT this.simpleBeanProducerTest = simpleBeanProducerTest; } - public QualifierBeanProducerTest getQualifierBeanProducerTest() { + public QualifierBeanProducerHolder getQualifierBeanProducerTest() { return qualifierBeanProducerTest; } diff --git a/tests/jre-tests/cdi/src/main/java/org/treblereel/injection/qualifiers/typed/ApplicationCommandManager.java b/tests/jre-tests/cdi/src/main/java/org/treblereel/injection/qualifiers/typed/ApplicationCommandManager.java index 4472e26b..24ba1fa8 100644 --- a/tests/jre-tests/cdi/src/main/java/org/treblereel/injection/qualifiers/typed/ApplicationCommandManager.java +++ b/tests/jre-tests/cdi/src/main/java/org/treblereel/injection/qualifiers/typed/ApplicationCommandManager.java @@ -14,8 +14,6 @@ package org.treblereel.injection.qualifiers.typed; -import io.crysknife.client.ManagedInstance; - import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Typed; import jakarta.inject.Inject; diff --git a/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ParentBean.java b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ParentBean.java new file mode 100644 index 00000000..7714ce4d --- /dev/null +++ b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ParentBean.java @@ -0,0 +1,20 @@ +/* + * Copyright © 2023 Treblereel + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.treblereel.produces.named; + +public interface ParentBean { + + String getType(); +} diff --git a/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ParentBeanProducer.java b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ParentBeanProducer.java new file mode 100644 index 00000000..e94a7b08 --- /dev/null +++ b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ParentBeanProducer.java @@ -0,0 +1,46 @@ +/* + * Copyright © 2023 Treblereel + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.treblereel.produces.named; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Default; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Named; + +@ApplicationScoped +public class ParentBeanProducer { + + @Produces + @Default + public ParentBean produceDefault() { + return new ParentBean() { + @Override + public String getType() { + return "ParentBean"; + } + }; + } + + @Produces + @Named("nameOne") + public ParentBean produceNameOne() { + return new ParentBean() { + @Override + public String getType() { + return "ParentBeanNamedOne"; + } + }; + } +} diff --git a/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ProducesNamedBeanHolder.java b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ProducesNamedBeanHolder.java new file mode 100644 index 00000000..c6e50f84 --- /dev/null +++ b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/named/ProducesNamedBeanHolder.java @@ -0,0 +1,74 @@ +/* + * Copyright © 2023 Treblereel + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.treblereel.produces.named; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Default; +import jakarta.inject.Inject; +import jakarta.inject.Named; + +@ApplicationScoped +public class ProducesNamedBeanHolder { + + + @Inject + @Default + private ParentBean parentBeanDefault; + + @Inject + private ParentBean parentBean; + + @Inject + @Named("nameOne") + private ParentBean parentBeanNamedOne; + + private ParentBean parentBeanConstructor; + private ParentBean parentBeanDefaultConstructor; + + private ParentBean parentBeanNamedOneConstructor; + + + @Inject + public ProducesNamedBeanHolder(ParentBean parentBeanConstructor, @Default ParentBean parentBeanDefaultConstructor, @Named("nameOne") ParentBean parentBeanNamedOneConstructor) { + this.parentBeanConstructor = parentBeanConstructor; + this.parentBeanDefaultConstructor = parentBeanDefaultConstructor; + this.parentBeanNamedOneConstructor = parentBeanNamedOneConstructor; + } + + + public ParentBean getParentBean() { + return parentBean; + } + + public ParentBean getParentBeanDefault() { + return parentBeanDefault; + } + + public ParentBean getParentBeanNamedOne() { + return parentBeanNamedOne; + } + + public ParentBean getParentBeanConstructor() { + return parentBeanConstructor; + } + + public ParentBean getParentBeanDefaultConstructor() { + return parentBeanDefaultConstructor; + } + + public ParentBean getParentBeanNamedOneConstructor() { + return parentBeanNamedOneConstructor; + } +} diff --git a/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java index d7c984e1..dd73ab75 100644 --- a/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java +++ b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java @@ -28,7 +28,19 @@ public QualifierBean getSimpleQualifierBean() { return new QualifierBean() { @Override public String say() { - return "REDHAT"; + return "Default"; + } + }; + } + + @Produces + @Dependent + @QualifierOne + public QualifierBean getSimpleQualifierBeanQualifierOne() { + return new QualifierBean() { + @Override + public String say() { + return "QualifierOne"; } }; } diff --git a/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerHolder.java b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerHolder.java index c50b8c73..06fe2660 100644 --- a/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerHolder.java +++ b/tests/jre-tests/cdi/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerHolder.java @@ -14,6 +14,7 @@ package org.treblereel.produces.qualifier; +import jakarta.enterprise.inject.Default; import jakarta.inject.Inject; import jakarta.inject.Singleton; @@ -21,13 +22,53 @@ * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 */ @Singleton -public class QualifierBeanProducerTest { +public class QualifierBeanProducerHolder { @Inject private QualifierBean qualifierBean; + @Inject + @Default + private QualifierBean qualifierBeanDefault; + + @Inject + @QualifierOne + private QualifierBean qualifierBeanQualifierOne; + + private QualifierBean qualifierBeanConstructor; + + private QualifierBean qualifierBeanConstructorDefault; + + private QualifierBean qualifierBeanConstructorQualifierOne; + + @Inject + public QualifierBeanProducerHolder(QualifierBean qualifierBeanConstructor, @Default QualifierBean qualifierBeanConstructorDefault, @QualifierOne QualifierBean qualifierBeanConstructorQualifierOne) { + this.qualifierBeanConstructor = qualifierBeanConstructor; + this.qualifierBeanConstructorDefault = qualifierBeanConstructorDefault; + this.qualifierBeanConstructorQualifierOne = qualifierBeanConstructorQualifierOne; + } + public QualifierBean getQualifierBean() { return qualifierBean; } + public QualifierBean getQualifierBeanDefault() { + return qualifierBeanDefault; + } + + public QualifierBean getQualifierBeanQualifierOne() { + return qualifierBeanQualifierOne; + } + + public QualifierBean getQualifierBeanConstructor() { + return qualifierBeanConstructor; + } + + public QualifierBean getQualifierBeanConstructorDefault() { + return qualifierBeanConstructorDefault; + } + + public QualifierBean getQualifierBeanConstructorQualifierOne() { + return qualifierBeanConstructorQualifierOne; + } } diff --git a/tests/jre-tests/cdi/src/test/java/org/treblereel/BeanManagerTest.java b/tests/jre-tests/cdi/src/test/java/org/treblereel/BeanManagerTest.java index 216adf96..5b4de0f9 100644 --- a/tests/jre-tests/cdi/src/test/java/org/treblereel/BeanManagerTest.java +++ b/tests/jre-tests/cdi/src/test/java/org/treblereel/BeanManagerTest.java @@ -19,6 +19,7 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import io.crysknife.client.SyncBeanDef; import jakarta.enterprise.inject.Default; import jakarta.inject.Named; @@ -123,8 +124,6 @@ public Class annotationType() { StreamSupport.stream(super.app.beanManager .lookupBeans(ComponentIface.class, componentQualifierOne, componentQualifierTwo) .spliterator(), false).count()); - - } @Test @@ -225,7 +224,6 @@ public String value() { .stream(super.app.beanManager.lookupBeans(NamedBean.class, named2).spliterator(), false) .count()); - NamedBean _componentQualifierTwo = super.app.beanManager.lookupBeans(NamedBean.class, named2).iterator().next().getInstance(); assertEquals("org.treblereel.injection.named.NamedBeanTwo", _componentQualifierTwo.say()); diff --git a/tests/jre-tests/cdi/src/test/java/org/treblereel/SimpleBeanProducerTest.java b/tests/jre-tests/cdi/src/test/java/org/treblereel/SimpleBeanProducerTest.java index ce9bec3b..cc6834a8 100644 --- a/tests/jre-tests/cdi/src/test/java/org/treblereel/SimpleBeanProducerTest.java +++ b/tests/jre-tests/cdi/src/test/java/org/treblereel/SimpleBeanProducerTest.java @@ -44,7 +44,7 @@ public void testAppSimpleBean() { @Test public void testQualifierBeanProducerTest() { assertNotNull(app.getQualifierBeanProducerTest().getQualifierBean()); - assertEquals("REDHAT", app.getQualifierBeanProducerTest().getQualifierBean().say()); + assertEquals("Default", app.getQualifierBeanProducerTest().getQualifierBean().say()); } @Test diff --git a/tests/jre-tests/cdi/src/test/java/org/treblereel/injection/TypedTest.java b/tests/jre-tests/cdi/src/test/java/org/treblereel/injection/TypedTest.java index 010035df..d545bcda 100644 --- a/tests/jre-tests/cdi/src/test/java/org/treblereel/injection/TypedTest.java +++ b/tests/jre-tests/cdi/src/test/java/org/treblereel/injection/TypedTest.java @@ -20,10 +20,6 @@ import org.treblereel.injection.qualifiers.typed.ApplicationCommandManager; import org.treblereel.injection.qualifiers.typed.RegistryAwareCommandManager; import org.treblereel.injection.qualifiers.typed.SessionCommandManager; -import org.treblereel.injection.typed.DefaultDefinitionsCacheRegistry; -import org.treblereel.injection.typed.DefinitionUtils; -import org.treblereel.injection.typed.DefinitionsCacheRegistry; -import org.treblereel.injection.typed.SimpleDefinitionsCacheRegistry; import org.treblereel.injection.typed.case2.BeanOne; import org.treblereel.injection.typed.case2.BeanTwo; import org.treblereel.injection.typed.case2.Iface; @@ -37,6 +33,8 @@ public class TypedTest extends AbstractTest { @Test public void testQualifierFieldInjectionBean() { + assertEquals(ApplicationCommandManager.class, app.beanManager.lookupBean(SessionCommandManager.class).getInstance().getClass()); + SessionCommandManager sessionCommandManager = app.qualifierFieldInjection.morphNodeToolboxAction.sessionCommandManager; diff --git a/tests/jre-tests/cdi/src/test/java/org/treblereel/injection/managedinstance/ManagedInstanceBeanTest.java b/tests/jre-tests/cdi/src/test/java/org/treblereel/injection/managedinstance/ManagedInstanceBeanTest.java index 7cdbc9d1..b8ebc04a 100644 --- a/tests/jre-tests/cdi/src/test/java/org/treblereel/injection/managedinstance/ManagedInstanceBeanTest.java +++ b/tests/jre-tests/cdi/src/test/java/org/treblereel/injection/managedinstance/ManagedInstanceBeanTest.java @@ -201,7 +201,7 @@ public void testInstance2() { @Test public void testInstanceProducerBean() { Instance managedInstanceBean = app.getManagedInstanceBean().getBean2(); - assertEquals("REDHAT", managedInstanceBean.get().say()); + assertEquals("Default", managedInstanceBean.get().say()); } @Test @@ -230,7 +230,7 @@ public void isUnsatisfied() { assertTrue(managedInstanceTestsHolder.uselessInterfaces.isUnsatisfied()); assertFalse(managedInstanceTestsHolder.componentIface.isUnsatisfied()); - assertFalse(managedInstanceTestsHolder.simpleBean.select(new Default() { + assertTrue(managedInstanceTestsHolder.simpleBean.select(new Default() { @Override public Class annotationType() { @@ -268,7 +268,7 @@ public Class annotationType() { }).getInstance(); }); assertEquals( - "No beans matched org.treblereel.injection.managedinstance.SimpleBean with qualifiers {{ org.treblereel.injection.managedinstance.ComponentQualifierTwo, }}", + "No beans matched org.treblereel.injection.managedinstance.SimpleBean with qualifiers { org.treblereel.injection.managedinstance.ComponentQualifierTwo, }", exception.getMessage()); } @@ -287,7 +287,7 @@ public Class annotationType() { }).get(); }); assertEquals( - "No beans matched org.treblereel.injection.managedinstance.SimpleBean with qualifiers {{ org.treblereel.injection.managedinstance.ComponentQualifierTwo, }}", + "No beans matched org.treblereel.injection.managedinstance.SimpleBean with qualifiers { org.treblereel.injection.managedinstance.ComponentQualifierTwo, }", exception.getMessage()); } diff --git a/tests/jre-tests/cdi/src/test/java/org/treblereel/produces/named/ProducesNamedBeanHolderTest.java b/tests/jre-tests/cdi/src/test/java/org/treblereel/produces/named/ProducesNamedBeanHolderTest.java new file mode 100644 index 00000000..4a0e5da9 --- /dev/null +++ b/tests/jre-tests/cdi/src/test/java/org/treblereel/produces/named/ProducesNamedBeanHolderTest.java @@ -0,0 +1,71 @@ +/* + * Copyright © 2023 Treblereel + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.treblereel.produces.named; + +import io.crysknife.client.internal.QualifierUtil; +import jakarta.enterprise.inject.Default; +import jakarta.inject.Named; +import org.junit.Test; +import org.treblereel.AbstractTest; + +import java.lang.annotation.Annotation; + +import static org.junit.Assert.assertEquals; + +public class ProducesNamedBeanHolderTest extends AbstractTest { + + private final Named namedBeanOne = new Named() { + + public Class annotationType() { + return jakarta.inject.Named.class; + } + + public String value() { + return "nameOne"; + } + }; + + + @Test + public void testBean() { + assertEquals("ParentBean", + app.beanManager.lookupBean(ParentBean.class).getInstance().getType()); + assertEquals("ParentBean", + app.beanManager.lookupBean(ProducesNamedBeanHolder.class).getInstance().getParentBean().getType()); + assertEquals("ParentBean", + app.beanManager.lookupBean(ProducesNamedBeanHolder.class).getInstance().getParentBeanConstructor().getType()); + } + + @Test + public void testBeanDefault() { + assertEquals("ParentBean", + app.beanManager.lookupBean(ParentBean.class, QualifierUtil.DEFAULT_ANNOTATION).getInstance().getType()); + assertEquals("ParentBean", + app.beanManager.lookupBean(ProducesNamedBeanHolder.class).getInstance().getParentBeanDefault().getType()); + assertEquals("ParentBean", + app.beanManager.lookupBean(ProducesNamedBeanHolder.class).getInstance().getParentBeanDefaultConstructor().getType()); + } + + @Test + public void testBeanNamedOne() { + assertEquals("ParentBeanNamedOne", + app.beanManager.lookupBean(ParentBean.class, namedBeanOne).getInstance().getType()); + assertEquals("ParentBeanNamedOne", + app.beanManager.lookupBean(ProducesNamedBeanHolder.class).getInstance().getParentBeanNamedOne().getType()); + assertEquals("ParentBeanNamedOne", + app.beanManager.lookupBean(ProducesNamedBeanHolder.class).getInstance().getParentBeanNamedOneConstructor().getType()); + + } +} diff --git a/tests/jre-tests/cdi/src/test/java/org/treblereel/produces/qualifier/ProducesNamedBeanHolderTest.java b/tests/jre-tests/cdi/src/test/java/org/treblereel/produces/qualifier/ProducesNamedBeanHolderTest.java new file mode 100644 index 00000000..ff40c8ed --- /dev/null +++ b/tests/jre-tests/cdi/src/test/java/org/treblereel/produces/qualifier/ProducesNamedBeanHolderTest.java @@ -0,0 +1,66 @@ +/* + * Copyright © 2023 Treblereel + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.treblereel.produces.qualifier; + +import io.crysknife.client.internal.QualifierUtil; +import org.junit.Test; +import org.treblereel.AbstractTest; + +import java.lang.annotation.Annotation; + +import static org.junit.Assert.assertEquals; + +public class ProducesNamedBeanHolderTest extends AbstractTest { + + + private final QualifierOne qualifierOne = new QualifierOne() { + + @Override + public Class annotationType() { + return QualifierOne.class; + } + }; + + @Test + public void testBean() { + assertEquals("Default", + app.beanManager.lookupBean(QualifierBean.class).getInstance().say()); + assertEquals("Default", + app.beanManager.lookupBean(QualifierBeanProducerHolder.class).getInstance().getQualifierBean().say()); + assertEquals("Default", + app.beanManager.lookupBean(QualifierBeanProducerHolder.class).getInstance().getQualifierBeanConstructor().say()); + } + + @Test + public void testBeanDefault() { + assertEquals("Default", + app.beanManager.lookupBean(QualifierBean.class, QualifierUtil.DEFAULT_ANNOTATION).getInstance().say()); + assertEquals("Default", + app.beanManager.lookupBean(QualifierBeanProducerHolder.class).getInstance().getQualifierBeanDefault().say()); + assertEquals("Default", + app.beanManager.lookupBean(QualifierBeanProducerHolder.class).getInstance().getQualifierBeanConstructorDefault().say()); + } + + @Test + public void testBeanNamedOne() { + assertEquals("QualifierOne", + app.beanManager.lookupBean(QualifierBean.class, qualifierOne).getInstance().say()); + assertEquals("QualifierOne", + app.beanManager.lookupBean(QualifierBeanProducerHolder.class).getInstance().getQualifierBeanQualifierOne().say()); + assertEquals("QualifierOne", + app.beanManager.lookupBean(QualifierBeanProducerHolder.class).getInstance().getQualifierBeanConstructorQualifierOne().say()); + + } +} From 1c78291bd6cc7c8af9e4b9bfd72d7e1dc0cbb5ef Mon Sep 17 00:00:00 2001 From: Dmitrii Tikhomirov Date: Wed, 16 Aug 2023 22:39:57 -0700 Subject: [PATCH 4/5] register EventListener via EventHandlerRegistration (and unregister on @PreDestroy) --- .../templates/client/EventHandlerHolder.java | 60 +++++++++++++++++++ .../client/EventHandlerRegistration.java | 43 +++++++++++++ .../generator/TemplateGenerator.java | 12 ++++ .../src/main/resources/templates/ui.ftlh | 10 ++-- 4 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 ui/templates/api/src/main/java/io/crysknife/ui/templates/client/EventHandlerHolder.java create mode 100644 ui/templates/api/src/main/java/io/crysknife/ui/templates/client/EventHandlerRegistration.java diff --git a/ui/templates/api/src/main/java/io/crysknife/ui/templates/client/EventHandlerHolder.java b/ui/templates/api/src/main/java/io/crysknife/ui/templates/client/EventHandlerHolder.java new file mode 100644 index 00000000..5e63b0f7 --- /dev/null +++ b/ui/templates/api/src/main/java/io/crysknife/ui/templates/client/EventHandlerHolder.java @@ -0,0 +1,60 @@ +/* + * Copyright © 2023 Treblereel + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package io.crysknife.ui.templates.client; + +import elemental2.dom.EventListener; +import elemental2.dom.HTMLElement; + +import java.util.Objects; + +public class EventHandlerHolder { + + + final String eventType; + final HTMLElement element; + final EventListener eventListener; + + public EventHandlerHolder(String eventType, HTMLElement element, EventListener eventListener) { + this.eventType = eventType; + this.element = element; + this.eventListener = eventListener; + } + + public EventHandlerHolder attach() { + element.addEventListener(eventType, eventListener); + return this; + } + + public EventHandlerHolder remove() { + element.removeEventListener(eventType, eventListener); + return this; + } + + @Override + public int hashCode() { + return Objects.hash(eventType, element, eventListener); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + EventHandlerHolder that = (EventHandlerHolder) o; + return Objects.equals(eventType, that.eventType) && Objects.equals(element, that.element) + && Objects.equals(eventListener, that.eventListener); + } +} diff --git a/ui/templates/api/src/main/java/io/crysknife/ui/templates/client/EventHandlerRegistration.java b/ui/templates/api/src/main/java/io/crysknife/ui/templates/client/EventHandlerRegistration.java new file mode 100644 index 00000000..60348907 --- /dev/null +++ b/ui/templates/api/src/main/java/io/crysknife/ui/templates/client/EventHandlerRegistration.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2023 Treblereel + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package io.crysknife.ui.templates.client; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EventHandlerRegistration { + + private final Map> handlers = new HashMap<>(); + + public void add(Object instance, EventHandlerHolder handler) { + handlers.computeIfAbsent(instance, k -> new ArrayList<>()).add(handler.attach()); + } + + public void remove(Object key, EventHandlerHolder handler) { + handlers.get(key).remove(handler.remove()); + } + + public void clear(Object instance) { + List handlers = this.handlers.get(instance); + for (EventHandlerHolder eventHandlerHolder : handlers) { + eventHandlerHolder.remove(); + } + handlers.clear(); + this.handlers.remove(instance); + } + +} diff --git a/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateGenerator.java b/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateGenerator.java index 55287aa5..b52a710c 100644 --- a/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateGenerator.java +++ b/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateGenerator.java @@ -29,10 +29,12 @@ import com.google.auto.common.MoreTypes; import com.google.common.base.Splitter; import com.google.common.base.Strings; +import com.google.common.base.Supplier; import com.google.common.escape.Escaper; import com.google.common.escape.Escapers; import com.inet.lib.less.Less; import elemental2.dom.DomGlobal; +import elemental2.dom.EventListener; import elemental2.dom.HTMLElement; import freemarker.template.Configuration; import freemarker.template.Template; @@ -50,6 +52,8 @@ import io.crysknife.generator.context.IOCContext; import io.crysknife.generator.helpers.MethodCallGenerator; import io.crysknife.logger.TreeLogger; +import io.crysknife.ui.templates.client.EventHandlerHolder; +import io.crysknife.ui.templates.client.EventHandlerRegistration; import io.crysknife.ui.templates.client.StyleInjector; import io.crysknife.ui.templates.client.TemplateUtil; import io.crysknife.ui.templates.client.annotation.DataField; @@ -252,6 +256,7 @@ private void code(ClassMetaInfo builder, BeanDefinition beanDefinition, processDataFields(templateContext, templateDefinition); processEventHandlers(beanDefinition, templateContext, templateDefinition); + processOnDestroy(builder); } private void addImports(ClassMetaInfo builder) { @@ -259,6 +264,9 @@ private void addImports(ClassMetaInfo builder) { builder.addImport(Js.class); builder.addImport(Reflect.class); builder.addImport(TemplateUtil.class); + builder.addImport(EventListener.class); + builder.addImport(EventHandlerHolder.class); + builder.addImport(EventHandlerRegistration.class); } private void setInnerHTML(TemplateContext templateContext, @@ -347,6 +355,10 @@ private void processEventHandlers(BeanDefinition beanDefinition, TemplateContext } } + private void processOnDestroy(ClassMetaInfo builder) { + builder.addToOnDestroy((Supplier) () -> "eventHandlerRegistration.clear(instance);"); + } + private void setStylesheet(ClassMetaInfo builder, TemplateContext templateContext, TemplateDefinition templateDefinition) { if (templateContext.getStylesheet() != null) { diff --git a/ui/templates/generator/src/main/resources/templates/ui.ftlh b/ui/templates/generator/src/main/resources/templates/ui.ftlh index bc42b883..18e7d8bf 100644 --- a/ui/templates/generator/src/main/resources/templates/ui.ftlh +++ b/ui/templates/generator/src/main/resources/templates/ui.ftlh @@ -4,11 +4,11 @@ private interface HTMLElementAccessor { elemental2.dom.HTMLElement getElement(); } +private final EventHandlerRegistration eventHandlerRegistration = new EventHandlerRegistration(); - -private void setAndInitTemplate() { + private void setAndInitTemplate() { <#if css??> - StyleInjector.fromString("${css?no_esc}").inject(); + StyleInjector.fromString("${css?no_esc}").inject(); <#if initRootElement> elemental2.core.Reflect.set(instance, "__root_element__", elemental2.dom.DomGlobal.document.createElement("div")); @@ -44,9 +44,9 @@ private void setAndInitTemplate() { <#list events as event> <#list event.eventTypes as type> - ((elemental2.dom.HTMLElement) Js.asPropertyMap(instance).get(Reflect.objectProperty("${event.mangleName}", instance))).addEventListener("${type}", (e) -> { + eventHandlerRegistration.add(instance, new EventHandlerHolder("${type}", ((elemental2.dom.HTMLElement) Js.asPropertyMap(instance).get(Reflect.objectProperty("${event.mangleName}", instance))), (e) -> { ${event.call?no_esc} - }); + })); } From b5cb3cb18614c0bdcd74735326cb95ad6db835eb Mon Sep 17 00:00:00 2001 From: Dmitrii Tikhomirov Date: Wed, 16 Aug 2023 22:43:27 -0700 Subject: [PATCH 5/5] update demo --- demo/pom.xml | 48 ++++--------------- .../java/io/crysknife/demo/client/App.java | 3 +- .../demo/client/events/BeanWithCDIEvents.java | 24 +++------- .../demo/client/inject/DependentBean.java | 6 +++ .../MutationObserverDemo.java | 7 +++ .../client/qualifiers/QualifierBeans.java | 2 +- .../QualifierBeansConstructorInjection.java | 2 +- .../transitive/TransitiveInjection.java | 3 +- .../io/crysknife/demo/client/main.html | 4 +- .../io/crysknife/demo/public/index.html | 8 ++-- demo/src/main/webapp/index.html | 4 +- 11 files changed, 42 insertions(+), 69 deletions(-) diff --git a/demo/pom.xml b/demo/pom.xml index 2ece6770..048de6a0 100644 --- a/demo/pom.xml +++ b/demo/pom.xml @@ -6,16 +6,22 @@ io.crysknife.demo demo 0.5.2-SNAPSHOT - war + jar + UTF-8 + UTF-8 + + 11 + 11 + 9.4.31.v20200723 + 2.2 + 1.0.0 + ${project.build.directory}/webapp ${webappdir}/WEB-INF/lib 1.1.0 0.21-SNAPSHOT - 9.4.31.v20200723 - 2.2 - 1.0.0 0.6-SNAPSHOT @@ -108,23 +114,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-war-plugin - 3.3.1 - - WEB-INF/classes/** - - com.vertispan.j2cl j2cl-maven-plugin @@ -143,23 +132,6 @@ ADVANCED - - org.apache.tomcat.maven - tomcat7-maven-plugin - ${maven.tomcat.plugin.version} - - tomcatconf/context.xml - - - - - - snapshots-repo - https://oss.sonatype.org/content/repositories/snapshots - false - true - - diff --git a/demo/src/main/java/io/crysknife/demo/client/App.java b/demo/src/main/java/io/crysknife/demo/client/App.java index 6ca99a0c..2f1ef66c 100644 --- a/demo/src/main/java/io/crysknife/demo/client/App.java +++ b/demo/src/main/java/io/crysknife/demo/client/App.java @@ -14,6 +14,7 @@ package io.crysknife.demo.client; +import elemental2.dom.HTMLBodyElement; import jakarta.annotation.PostConstruct; import jakarta.enterprise.event.Observes; import jakarta.inject.Inject; @@ -25,7 +26,7 @@ import io.crysknife.annotation.Application; import org.treblereel.j2cl.processors.annotations.GWT3EntryPoint; -@Application +@Application(packages = {"io.crysknife"}) public class App { @Inject diff --git a/demo/src/main/java/io/crysknife/demo/client/events/BeanWithCDIEvents.java b/demo/src/main/java/io/crysknife/demo/client/events/BeanWithCDIEvents.java index 06a613c9..cae20886 100644 --- a/demo/src/main/java/io/crysknife/demo/client/events/BeanWithCDIEvents.java +++ b/demo/src/main/java/io/crysknife/demo/client/events/BeanWithCDIEvents.java @@ -15,23 +15,25 @@ package io.crysknife.demo.client.events; import java.util.Random; +import java.util.function.BiConsumer; +import elemental2.core.Function; +import elemental2.dom.*; +import io.crysknife.client.Reflect; import jakarta.annotation.PostConstruct; import jakarta.enterprise.event.Event; import jakarta.enterprise.event.Observes; import jakarta.inject.Inject; import jakarta.inject.Singleton; -import elemental2.dom.HTMLButtonElement; -import elemental2.dom.HTMLDivElement; -import elemental2.dom.HTMLInputElement; -import elemental2.dom.MouseEvent; import io.crysknife.client.IsElement; import io.crysknife.ui.templates.client.annotation.DataField; import io.crysknife.ui.templates.client.annotation.EventHandler; import io.crysknife.ui.templates.client.annotation.ForEvent; import io.crysknife.ui.templates.client.annotation.Templated; import io.crysknife.ui.navigation.client.local.Page; +import jsinterop.base.Js; +import jsinterop.base.JsForEachCallbackFn; /** * @author Dmitrii Tikhomirov @@ -66,19 +68,7 @@ private void init() { } private void initBtn() { - sendUserEvent.addEventListener("click", evt -> { - User user = new User(); - user.setId(new Random().nextInt()); - user.setName("IAMUSER"); - eventUser.fire(user); - }); - - sendAddressEvent.addEventListener("click", evt -> { - Address address = new Address(); - address.setId(new Random().nextInt()); - address.setName("Redhat"); - eventAddress.fire(address); - }); + } private void onUserEvent(@Observes User user) { diff --git a/demo/src/main/java/io/crysknife/demo/client/inject/DependentBean.java b/demo/src/main/java/io/crysknife/demo/client/inject/DependentBean.java index 36d63eb3..a9aa0d5a 100644 --- a/demo/src/main/java/io/crysknife/demo/client/inject/DependentBean.java +++ b/demo/src/main/java/io/crysknife/demo/client/inject/DependentBean.java @@ -17,6 +17,7 @@ import java.util.Random; import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import jakarta.enterprise.context.Dependent; import jakarta.inject.Inject; import jakarta.inject.Named; @@ -65,4 +66,9 @@ public void init() { public int getRandom() { return random; } + + @PreDestroy + private void onDetach() { + DomGlobal.console.log(this.getClass().getCanonicalName() + " destroyed"); + } } diff --git a/demo/src/main/java/io/crysknife/demo/client/mutationobserver/MutationObserverDemo.java b/demo/src/main/java/io/crysknife/demo/client/mutationobserver/MutationObserverDemo.java index 83c7d5be..1d0c1103 100644 --- a/demo/src/main/java/io/crysknife/demo/client/mutationobserver/MutationObserverDemo.java +++ b/demo/src/main/java/io/crysknife/demo/client/mutationobserver/MutationObserverDemo.java @@ -15,6 +15,7 @@ package io.crysknife.demo.client.mutationobserver; import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import jakarta.inject.Inject; import jakarta.inject.Singleton; @@ -132,4 +133,10 @@ protected void onDetach(MutationRecord mutationRecord) { public HTMLDivElement getElement() { return mutationobserverdemo; } + + @PreDestroy + public void onDestroy() { + observer.disconnect(); + DomGlobal.console.log("onDestroy"); + } } diff --git a/demo/src/main/java/io/crysknife/demo/client/qualifiers/QualifierBeans.java b/demo/src/main/java/io/crysknife/demo/client/qualifiers/QualifierBeans.java index 49df1bed..310ad5d5 100644 --- a/demo/src/main/java/io/crysknife/demo/client/qualifiers/QualifierBeans.java +++ b/demo/src/main/java/io/crysknife/demo/client/qualifiers/QualifierBeans.java @@ -12,7 +12,7 @@ * the License. */ -package io.crysknife.demo.client; +package io.crysknife.demo.client.qualifiers; import jakarta.annotation.PostConstruct; import jakarta.enterprise.inject.Default; diff --git a/demo/src/main/java/io/crysknife/demo/client/qualifiers/QualifierBeansConstructorInjection.java b/demo/src/main/java/io/crysknife/demo/client/qualifiers/QualifierBeansConstructorInjection.java index 57304498..15806273 100644 --- a/demo/src/main/java/io/crysknife/demo/client/qualifiers/QualifierBeansConstructorInjection.java +++ b/demo/src/main/java/io/crysknife/demo/client/qualifiers/QualifierBeansConstructorInjection.java @@ -12,7 +12,7 @@ * the License. */ -package io.crysknife.demo.client; +package io.crysknife.demo.client.qualifiers; import jakarta.annotation.PostConstruct; import jakarta.inject.Inject; diff --git a/demo/src/main/java/io/crysknife/demo/client/transitive/TransitiveInjection.java b/demo/src/main/java/io/crysknife/demo/client/transitive/TransitiveInjection.java index 228bbc1e..34bb09af 100644 --- a/demo/src/main/java/io/crysknife/demo/client/transitive/TransitiveInjection.java +++ b/demo/src/main/java/io/crysknife/demo/client/transitive/TransitiveInjection.java @@ -12,7 +12,7 @@ * the License. */ -package io.crysknife.demo.client; +package io.crysknife.demo.client.transitive; import jakarta.inject.Inject; import jakarta.inject.Singleton; @@ -65,4 +65,3 @@ protected void onClick(@ForEvent("click") final MouseEvent event) { setText(injector.callBeanTwo()); } } - diff --git a/demo/src/main/resources/io/crysknife/demo/client/main.html b/demo/src/main/resources/io/crysknife/demo/client/main.html index 63b113c2..8fe671cf 100644 --- a/demo/src/main/resources/io/crysknife/demo/client/main.html +++ b/demo/src/main/resources/io/crysknife/demo/client/main.html @@ -6,7 +6,7 @@

Crysknife demo

    -

    0.4-SNAPSHOT

    +

    0.6-SNAPSHOT

  • @@ -46,4 +46,4 @@

    Crysknife demo

    - \ No newline at end of file + diff --git a/demo/src/main/resources/io/crysknife/demo/public/index.html b/demo/src/main/resources/io/crysknife/demo/public/index.html index 4098726c..9e32782a 100644 --- a/demo/src/main/resources/io/crysknife/demo/public/index.html +++ b/demo/src/main/resources/io/crysknife/demo/public/index.html @@ -26,9 +26,7 @@ - + - - - - \ No newline at end of file + + diff --git a/demo/src/main/webapp/index.html b/demo/src/main/webapp/index.html index 7644997c..b2185657 100644 --- a/demo/src/main/webapp/index.html +++ b/demo/src/main/webapp/index.html @@ -26,8 +26,8 @@ + - - \ No newline at end of file +