diff --git a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierOne.java b/annotations/src/main/java/io/crysknife/annotation/CircularDependency.java similarity index 68% rename from tests/src/main/java/org/treblereel/injection/qualifiers/QualifierOne.java rename to annotations/src/main/java/io/crysknife/annotation/CircularDependency.java index 499d9c94..97ed56b2 100644 --- a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierOne.java +++ b/annotations/src/main/java/io/crysknife/annotation/CircularDependency.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright (C) 2021 * * 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 @@ -12,23 +12,18 @@ * the License. */ -package org.treblereel.injection.qualifiers; +package io.crysknife.annotation; -import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.inject.Qualifier; - /** - * @author Dmitrii Tikhomirov Created by treblereel 4/13/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/30/21 TODO */ -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) -@Documented -@Qualifier -public @interface QualifierOne { +@Target(ElementType.TYPE) +public @interface CircularDependency { } diff --git a/annotations/src/main/java/javax/enterprise/inject/Any.java b/annotations/src/main/java/javax/enterprise/inject/Any.java new file mode 100644 index 00000000..5a4568a2 --- /dev/null +++ b/annotations/src/main/java/javax/enterprise/inject/Any.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. and/or its affiliates. + * + * 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 javax.enterprise.inject; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + *

+ * The built-in qualifier type. + *

+ * + *

+ * Every bean has the qualifier @Any, even if it does not explicitly declare this + * qualifier, except for the special {@link javax.enterprise.inject.New @New qualified beans}. + *

+ * + *

+ * Every event has the qualifier @Any, even if it was raised without explicitly + * declaration of this qualifier. + *

+ * + *

+ * The @Any qualifier allows an injection point to refer to all beans or all events of + * a certain bean type. + *

+ * + *
+ * @Inject
+ * @Any
+ * Instance<PaymentProcessor> anyPaymentProcessor;
+ * 
+ * + *
+ * @Inject
+ * @Any
+ * Event<User> anyUserEvent;
+ * 
+ * + *
+ * @Inject
+ * @Delegate
+ * @Any
+ * Logger logger;
+ * 
+ * + * @author Gavin King + * @author David Allen + */ + +@Qualifier +@Retention(RUNTIME) +@Target({TYPE, METHOD, FIELD, PARAMETER}) +@Documented +public @interface Any { + +} diff --git a/annotations/src/main/java/javax/enterprise/inject/Specializes.java b/annotations/src/main/java/javax/enterprise/inject/Specializes.java new file mode 100644 index 00000000..b2559966 --- /dev/null +++ b/annotations/src/main/java/javax/enterprise/inject/Specializes.java @@ -0,0 +1,71 @@ +/* + * JBoss, Home of Professional Open Source Copyright 2010, Red Hat, Inc., and individual + * contributors by the @authors tag. See the copyright.txt in the distribution for a full listing of + * individual contributors. + * + * 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 javax.enterprise.inject; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + *

+ * Indicates that a bean directly specializes another bean. May be applied to a bean class or + * producer method. + *

+ * + *

+ * If a bean directly specializes a second bean, it inherits: + *

+ * + * + * + *

+ * If the second bean has a name, the bean may not declare a name using {@link javax.inject.Named + * @Named}. Furthermore, the bean must have all the bean types of the second bean. + *

+ * + * + * + *

+ * If a bean is specialized by any enabled bean, the first bean is disabled. + *

+ * + * @author Gavin King + * @author Pete Muir + */ + +@Target({TYPE, METHOD}) +@Retention(RUNTIME) +@Documented +public @interface Specializes { + +} diff --git a/tests/src/main/java/org/treblereel/produces/qualifier/QualifierOne.java b/annotations/src/main/java/javax/enterprise/inject/Typed.java similarity index 72% rename from tests/src/main/java/org/treblereel/produces/qualifier/QualifierOne.java rename to annotations/src/main/java/javax/enterprise/inject/Typed.java index 63b93c8e..8bff1d17 100644 --- a/tests/src/main/java/org/treblereel/produces/qualifier/QualifierOne.java +++ b/annotations/src/main/java/javax/enterprise/inject/Typed.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright (C) 2009 The JSR-330 Expert Group * * 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 @@ -12,7 +12,7 @@ * the License. */ -package org.treblereel.produces.qualifier; +package javax.enterprise.inject; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -20,15 +20,10 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.inject.Qualifier; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/13/19 - */ -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented -@Qualifier -public @interface QualifierOne { +public @interface Typed { + Class[] value() default {}; } diff --git a/bom/pom.xml b/bom/pom.xml new file mode 100644 index 00000000..b9429a23 --- /dev/null +++ b/bom/pom.xml @@ -0,0 +1,127 @@ + + + 4.0.0 + + io.crysknife + bom + 0.3-SNAPSHOT + pom + + + BOM (Bill Of Materials) + POC DI for GWT 3 or j2cl + https://github.com/treblereel + + + + treblereel + Dmitrii Tikhomirov + chani.liet@gmail.com + + + + + + Apache License Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo + + + + + Treblereel + https://github.com/treblereel + + + + + + io.crysknife + internal-bom + ${project.version} + pom + import + + + + io.crysknife + crysknife-annotations + ${project.version} + + + + io.crysknife + crysknife-core + ${project.version} + + + + io.crysknife + crysknife-processor + ${project.version} + + + + io.crysknife + elemental2-generator + ${project.version} + + + io.crysknife + gwt-dom-generator + ${project.version} + + + + io.crysknife + databinding-api + ${project.version} + + + + io.crysknife + databinding-generator + ${project.version} + + + + io.crysknife + mutationobserver-api + ${project.version} + + + + io.crysknife + mutationobserver-generator + ${project.version} + + + + io.crysknife + navigation-api + ${project.version} + + + + io.crysknife + navigation-generator + ${project.version} + + + + io.crysknife + templates-api + ${project.version} + + + + io.crysknife + templates-generator + ${project.version} + + + + + \ No newline at end of file diff --git a/core/src/main/java/io/crysknife/client/BeanManager.java b/core/src/main/java/io/crysknife/client/BeanManager.java index eadfb1bb..067e2e47 100644 --- a/core/src/main/java/io/crysknife/client/BeanManager.java +++ b/core/src/main/java/io/crysknife/client/BeanManager.java @@ -13,19 +13,117 @@ */ package io.crysknife.client; +import io.crysknife.client.internal.BeanManagerUtil; +import io.crysknife.client.internal.QualifierUtil; +import io.crysknife.client.internal.SyncBeanDefImpl; + 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.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * @author Dmitrii Tikhomirov Created by treblereel 3/28/19 */ -public interface BeanManager { +public abstract class BeanManager { + + private final Map beans = new HashMap<>(); + + BeanManager() { + + } + + void register(SyncBeanDefImpl beanDefinition) { + BeanDefinitionHolder holder = get(beanDefinition.getType()); + holder.beanDefinition = beanDefinition; + beanDefinition.getAssignableTypes().forEach(superType -> { + get((Class) superType).subTypes.add(holder); + }); + } + + private BeanDefinitionHolder get(Class type) { + if (!beans.containsKey(type)) { + BeanDefinitionHolder holder = new BeanDefinitionHolder(); + beans.put(type, holder); + } + return beans.get(type); + } + + public Collection> lookupBeans(final Class type, Annotation... qualifiers) { + List asList = Arrays.stream(qualifiers).collect(Collectors.toList()); + + Set> result = new HashSet<>(); + if (beans.get(type).beanDefinition != null) { - void destroyBean(Object ref); + if (beans.get(type).beanDefinition + .matches(Arrays.stream(qualifiers).collect(Collectors.toSet()))) { + result.add(beans.get(type).beanDefinition); + } + } - Instance lookupBean(final Class type, Annotation... qualifiers); + if (asList.isEmpty()) { + beans.get(type).subTypes.stream().filter(f -> f.beanDefinition != null) + .filter(f -> QualifierUtil.matches(asList, + (Collection) f.beanDefinition.getQualifiers())) + .forEach(bean -> result.add(bean.beanDefinition)); + } else { + beans.get(type).subTypes.stream().filter(f -> f.beanDefinition != null) + .filter(f -> QualifierUtil.matches(asList, + (Collection) f.beanDefinition.getActualQualifiers())) + .forEach(bean -> result.add(bean.beanDefinition)); + } + return result; + } - Instance lookupBean(final Class type); + public SyncBeanDef lookupBean(final Class type) { + return lookupBean(type, QualifierUtil.DEFAULT_ANNOTATION); + } - Set> lookupBeans(final Class type, Annotation... qualifiers); + public SyncBeanDef lookupBean(final Class type, final Annotation... qualifiers) { + if (!beans.containsKey(type)) { + throw BeanManagerUtil.unsatisfiedResolutionException(type, qualifiers); + } + + List asList = Arrays.stream(qualifiers).collect(Collectors.toList()); + Collection> candidates = new HashSet<>(); + if (beans.get(type).beanDefinition != null) { + SyncBeanDefImpl def = beans.get(type).beanDefinition; + if (QualifierUtil.matches(asList, (Collection) def.getActualQualifiers())) { + return def; + } + candidates.add(def); + } + + beans.get(type).subTypes.stream().filter(bean -> bean.beanDefinition != null) + .filter(f -> QualifierUtil.matches(asList, + (Collection) f.beanDefinition.getActualQualifiers())) + .forEach(bean -> candidates.add(bean.beanDefinition)); + + 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) { + // DO NOTHING ATM + } + + + private static class BeanDefinitionHolder { + + SyncBeanDefImpl beanDefinition; + Set subTypes = new HashSet<>(); + } } + diff --git a/core/src/main/java/io/crysknife/client/IOCBeanDef.java b/core/src/main/java/io/crysknife/client/IOCBeanDef.java new file mode 100644 index 00000000..86d858f1 --- /dev/null +++ b/core/src/main/java/io/crysknife/client/IOCBeanDef.java @@ -0,0 +1,81 @@ +/* + * Copyright © 2021 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; + +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Set; + +/** + * Definition of a managed bean. + * + * @author Max Barkley + * @author Christian Sadilek + */ +public interface IOCBeanDef { + + /** + * @param type Must not be null. + * @return True if this bean is assginable to the given type. + */ + boolean isAssignableTo(Class type); + + /** + * Returns the type of the bean. + * + * @see #getBeanClass() + * @return the type of the bean. + */ + Class getType(); + + /** + * Returns the actual bean class represented by this bean. + * + * @return the actual type of the bean. + */ + Class getBeanClass(); + + /** + * Returns the scope of the bean. + * + * @returns the annotation type representing the scope of the bean. + */ + Class getScope(); + + /** + * Returns any qualifiers associated with the bean. + * + * @return Must never be null. + */ + Collection getQualifiers(); + + Collection getActualQualifiers(); + + /** + * Returns true if the beans qualifiers match the specified set of qualifiers. + * + * @param annotations the qualifiers to compare + * @return returns whether or not the bean matches the set of qualifiers + */ + boolean matches(Set annotations); + + /** + * Returns the name of the bean. + * + * @return the name of the bean. If the bean does not have a name, returns null. + */ + String getName(); + +} diff --git a/core/src/main/java/io/crysknife/client/InstanceFactory.java b/core/src/main/java/io/crysknife/client/InstanceFactory.java new file mode 100644 index 00000000..c16d3f06 --- /dev/null +++ b/core/src/main/java/io/crysknife/client/InstanceFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2021 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; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/27/21 + */ +public interface InstanceFactory { + + /** + * Returns an instance of the bean within the active scope. + * + * @return The bean instance. + */ + T getInstance(); + +} diff --git a/core/src/main/java/io/crysknife/client/IsElement.java b/core/src/main/java/io/crysknife/client/IsElement.java new file mode 100644 index 00000000..76b9b17f --- /dev/null +++ b/core/src/main/java/io/crysknife/client/IsElement.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2021 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; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/4/21 + */ +import elemental2.dom.HTMLElement; + +/** Interface for custom components returning a single element. */ +public interface IsElement { + + /** @return the element of the custom component */ + default E getElement() { + throw new Error("Method must be implemented manually or by crysknife-ui template engine"); + } +} diff --git a/core/src/main/java/io/crysknife/client/ManagedInstance.java b/core/src/main/java/io/crysknife/client/ManagedInstance.java index f0c461d1..1c4534af 100644 --- a/core/src/main/java/io/crysknife/client/ManagedInstance.java +++ b/core/src/main/java/io/crysknife/client/ManagedInstance.java @@ -17,6 +17,7 @@ import java.lang.annotation.Annotation; import javax.enterprise.context.Dependent; +import javax.enterprise.inject.Instance; import javax.inject.Provider; /** diff --git a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentQualifierTwo.java b/core/src/main/java/io/crysknife/client/SyncBeanDef.java similarity index 52% rename from tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentQualifierTwo.java rename to core/src/main/java/io/crysknife/client/SyncBeanDef.java index 119f35c4..1eb34577 100644 --- a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentQualifierTwo.java +++ b/core/src/main/java/io/crysknife/client/SyncBeanDef.java @@ -12,23 +12,27 @@ * the License. */ -package org.treblereel.managedinstance; +package io.crysknife.client; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import io.crysknife.client.internal.BeanFactory; -import javax.inject.Qualifier; +import java.util.Optional; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 + * Represents a bean definition within the bean manager. + * + * @author Max Barkley */ -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Qualifier -public @interface ComponentQualifierTwo { +public interface SyncBeanDef extends InstanceFactory, IOCBeanDef { + + /** + * Returns a new instance of the bean. Calling this method overrides the underlying scope and + * instantiates a new instance of the bean. + * + * @return a new instance of the bean. + */ + T newInstance(); + + Optional> getFactory(); } diff --git a/core/src/main/java/io/crysknife/client/internal/AbstractBeanManager.java b/core/src/main/java/io/crysknife/client/internal/AbstractBeanManager.java deleted file mode 100644 index 94923ada..00000000 --- a/core/src/main/java/io/crysknife/client/internal/AbstractBeanManager.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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 java.lang.annotation.Annotation; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import javax.enterprise.inject.Default; -import javax.inject.Named; -import javax.inject.Provider; - -import io.crysknife.client.BeanManager; -import io.crysknife.client.Instance; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/29/19 - */ -public abstract class AbstractBeanManager implements BeanManager { - - final private Map> beanStore = new java.util.HashMap<>(); - - protected AbstractBeanManager() { - - } - - @Override - public void destroyBean(Object ref) { - - } - - @Override - public Instance lookupBean(Class type, Annotation... qualifiers) { - if (beanStore.get(type) != null) { - InstanceKey instanceKey = new InstanceKey(type, qualifiers); - if (beanStore.get(type).containsKey(instanceKey)) { - return new InstanceImpl(beanStore.get(type).get(instanceKey)); - } - } - throw new Error("Unable to find the bean [" + type.getCanonicalName() - + "] with the qualifiers [" + Arrays.stream(qualifiers) - .map(q -> q.annotationType().getCanonicalName()).collect(Collectors.joining(",")) - + "]"); - } - - @Override - public Instance lookupBean(Class type) { - return lookupBean(type, new Default() { - - @Override - public Class annotationType() { - return Default.class; - } - }); - } - - @Override - public Set> lookupBeans(Class type, Annotation... qualifiers) { - if (beanStore.get(type) != null) { - final Set> beans = new HashSet<>(); - if (qualifiers.length == 0) { - beanStore.get(type).values().stream() - .map((Function) InstanceImpl::new) - .forEach(bean -> beans.add(bean)); - } else { - InstanceKey key = new InstanceKey(type, qualifiers); - - beanStore.get(type).entrySet().stream().filter(pre -> pre.getKey().equals(key)) - .map(provider -> new InstanceImpl<>(provider.getValue())) - .forEach(bean -> beans.add((InstanceImpl) bean)); - } - - return Collections.unmodifiableSet(beans); - } - - throw new Error("Unable to find the bean [" + type.getCanonicalName() - + "] with the qualifiers [" + Arrays.stream(qualifiers) - .map(elm -> elm.annotationType().getCanonicalName()).collect(Collectors.joining(",")) - + " ]"); - } - - protected void register(Class type, Provider provider) { - register(type, provider, new Default() { - - @Override - public Class annotationType() { - return Default.class; - } - }); - } - - protected void register(Class type, Provider provider, Annotation... annotation) { - if (!beanStore.containsKey(type)) { - beanStore.put(type, new HashMap<>()); - } - beanStore.get(type).put(new InstanceKey(type, annotation), provider); - } - - private static class InstanceKey { - - private final Class type; - private final Set qualifiers; - - private InstanceKey(final Class type, final Annotation... qualifiers) { - this.type = type; - this.qualifiers = Arrays.stream(qualifiers).map(q -> { - Key key; - if (q instanceof Named) { - key = new Key(q.annotationType(), ((Named) q).value()); - } else { - key = new Key(q.annotationType()); - } - return key; - }).collect(Collectors.toSet()); - } - - @Override - public int hashCode() { - - return Arrays.hashCode(qualifiers.toArray()); - } - - @Override - public boolean equals(final Object obj) { - if (obj instanceof InstanceKey) { - final InstanceKey other = (InstanceKey) obj; - return type.equals(other.type) && qualifiers.equals(other.qualifiers); - } else { - return false; - } - } - - private static class Key { - - private Class annotation; - private String named; - - private Key(Class annotation, String named) { - this(annotation); - this.named = named; - } - - private Key(Class annotation) { - this.annotation = annotation; - } - - @Override - public int hashCode() { - return Objects.hash(annotation, named); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Key key = (Key) o; - return annotation.equals(key.annotation) && Objects.equals(named, key.named); - } - } - } -} diff --git a/core/src/main/java/io/crysknife/client/internal/BeanFactory.java b/core/src/main/java/io/crysknife/client/internal/BeanFactory.java new file mode 100644 index 00000000..5fdb7b0d --- /dev/null +++ b/core/src/main/java/io/crysknife/client/internal/BeanFactory.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2021 + * + * 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.SyncBeanDef; + +import javax.enterprise.context.Dependent; +import java.lang.annotation.Annotation; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/25/21 + */ +public abstract class BeanFactory { + + protected BeanManager beanManager; + + protected SyncBeanDef beanDef; + protected T instance; + private T incompleteInstance; + private boolean initialized = false; + + protected BeanFactory(BeanManager beanManager) { + this.beanManager = beanManager; + } + + public T getIncompleteInstance() { + return incompleteInstance; + } + + protected void setIncompleteInstance(final T instance) { + incompleteInstance = instance; + } + + public abstract T getInstance(); + + public void initInstance() { + if (beanDef.getScope().equals(Dependent.class) || !initialized) { + doInitInstance(); + initialized = true; + } + } + + protected void doInitInstance() {} + + public T createNewInstance() { + if (instance != null) { + createInstance(); + } + return (T) instance; + } + + protected T createInstance() { + throw new UnsupportedOperationException( + "The factory, " + getClass().getSimpleName() + ", only supports contextual instances."); + } + + public T createContextualInstance(final Class[] typeArgs, final Annotation[] qualifiers) { + throw new UnsupportedOperationException( + "The factory, " + getClass().getSimpleName() + ", does not support contextual instances."); + } + +} diff --git a/core/src/main/java/io/crysknife/client/internal/BeanManagerUtil.java b/core/src/main/java/io/crysknife/client/internal/BeanManagerUtil.java new file mode 100644 index 00000000..59f31e2e --- /dev/null +++ b/core/src/main/java/io/crysknife/client/internal/BeanManagerUtil.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. + * + * 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.IOCBeanDef; + +import javax.inject.Named; +import java.lang.annotation.Annotation; +import java.util.Collection; + +/** + * + * @author Max Barkley + */ +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"); + for (final IOCBeanDef beanDef : resolved) { + builder.append(" ").append(beanDef.toString()).append("\n"); + } + builder.append("}"); + IOCResolutionException iocResolutionException = new IOCResolutionException(builder.toString()); + return iocResolutionException; + } + + public static IOCResolutionException unsatisfiedResolutionException(Class type, + Annotation... 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) + "}"); + } + + public static String qualifiersToString(Collection qualifiers) { + return qualifiersToString(qualifiers.toArray(new Annotation[qualifiers.size()])); + } + + public static String qualifiersToString(final Annotation[] qualifiers) { + final StringBuilder builder = new StringBuilder().append("{ "); + for (final Annotation qualifier : qualifiers) { + builder.append(qualifierToString(qualifier)); + builder.append(", "); + } + builder.append(" }"); + + return builder.toString(); + } + + public static String qualifierToString(final Annotation qualifier) { + final StringBuilder builder = new StringBuilder(); + builder.append(qualifier.annotationType().getName()); + + if (qualifier instanceof Named) { + Named named = (Named) qualifier; + builder.append("(\"").append(named.value()).append("\")"); + } + + return builder.toString(); + } + +} diff --git a/core/src/main/java/io/crysknife/client/internal/CircularDependencyProxy.java b/core/src/main/java/io/crysknife/client/internal/CircularDependencyProxy.java new file mode 100644 index 00000000..bdd8104a --- /dev/null +++ b/core/src/main/java/io/crysknife/client/internal/CircularDependencyProxy.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 + * + * 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; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 10/3/21 + */ +public interface CircularDependencyProxy { + + void setInstance(T instance); + + T unwrap(); +} diff --git a/core/src/main/java/io/crysknife/client/internal/IOCResolutionException.java b/core/src/main/java/io/crysknife/client/internal/IOCResolutionException.java new file mode 100644 index 00000000..cdbb312a --- /dev/null +++ b/core/src/main/java/io/crysknife/client/internal/IOCResolutionException.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. and/or its affiliates. + * + * 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; + +/** + * An exception that is thrown if a bean cannot be resolved. + * + * @author Mike Brock + */ +public class IOCResolutionException extends RuntimeException { + public IOCResolutionException(final String message) { + super(message); + } +} diff --git a/core/src/main/java/io/crysknife/client/internal/InstanceImpl.java b/core/src/main/java/io/crysknife/client/internal/InstanceImpl.java index 6034760d..4e2af062 100644 --- a/core/src/main/java/io/crysknife/client/internal/InstanceImpl.java +++ b/core/src/main/java/io/crysknife/client/internal/InstanceImpl.java @@ -13,19 +13,30 @@ */ package io.crysknife.client.internal; -import javax.inject.Provider; +import io.crysknife.client.InstanceFactory; +import io.crysknife.client.SyncBeanDef; -import io.crysknife.client.Instance; +import javax.enterprise.inject.Instance; +import javax.inject.Provider; +import java.lang.annotation.Annotation; +import java.util.Iterator; +import java.util.function.Supplier; /** + * TODO this class must be refactored + * * @author Dmitrii Tikhomirov Created by treblereel 3/29/19 */ -public class InstanceImpl implements Instance { +public class InstanceImpl implements Instance, InstanceFactory { + + private Supplier provider; - Provider provider; + public InstanceImpl(T provider) { + this.provider = () -> provider; + } - public InstanceImpl(Provider provider) { - this.provider = provider; + public InstanceImpl(SyncBeanDef provider) { + this.provider = () -> provider.getInstance(); } @Override @@ -34,10 +45,36 @@ public T get() { } @Override - public void destroy(T var1) {} + public T getInstance() { + return provider.get(); + } + + @Override + public Instance select(Annotation... var1) { + return null; + } + + @Override + public Instance select(Class var1, Annotation... var2) { + return null; + } @Override - public void destroyAll() { + public boolean isUnsatisfied() { + return false; + } + @Override + public boolean isAmbiguous() { + return false; } + + @Override + public void destroy(T var1) {} + + @Override + public Iterator iterator() { + return null; + } + } 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 9a2ec858..ea9d6143 100644 --- a/core/src/main/java/io/crysknife/client/internal/ManagedInstanceImpl.java +++ b/core/src/main/java/io/crysknife/client/internal/ManagedInstanceImpl.java @@ -17,11 +17,10 @@ import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Iterator; -import java.util.Set; import io.crysknife.client.BeanManager; -import io.crysknife.client.Instance; import io.crysknife.client.ManagedInstance; +import io.crysknife.client.SyncBeanDef; /** * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 @@ -32,15 +31,23 @@ public class ManagedInstanceImpl implements ManagedInstance { private final Class type; - private final Set> beans; + private final Collection> beans; - public ManagedInstanceImpl(Class type, BeanManager beanManager) { + private Annotation[] qualifiers; + + public ManagedInstanceImpl(BeanManager beanManager, Class type) { + this(beanManager, type, new Annotation[] {}); + } + + public ManagedInstanceImpl(BeanManager beanManager, Class type, Annotation... qualifiers) { this.type = type; this.beanManager = beanManager; + this.qualifiers = qualifiers; this.beans = beanManager.lookupBeans(type); } - public ManagedInstanceImpl(Class type, BeanManager beanManager, Set> beans) { + public ManagedInstanceImpl(Class type, BeanManager beanManager, + Collection> beans) { this.type = type; this.beanManager = beanManager; this.beans = beans; @@ -62,7 +69,7 @@ public boolean isAmbiguous() { } @Override - public void destroy(Object instance) { + public void destroy(T instance) { } @@ -73,19 +80,19 @@ public void destroyAll() { @Override public Iterator iterator() { - return new ManagedInstanceImplIterator(beans); + return new ManagedInstanceImplIterator(beans); } @Override public T get() { - return beanManager.lookupBean(type).get(); + return beanManager.lookupBean(type, qualifiers).getInstance(); } private static class ManagedInstanceImplIterator implements Iterator { - private final Iterator> delegate; + private final Iterator> delegate; - public ManagedInstanceImplIterator(final Collection> beans) { + public ManagedInstanceImplIterator(final Collection> beans) { this.delegate = beans.iterator(); } @@ -96,8 +103,8 @@ public boolean hasNext() { @Override public T next() { - final Instance bean = delegate.next(); - final T instance = bean.get(); + final SyncBeanDef bean = delegate.next(); + final T instance = bean.getInstance(); return instance; } } diff --git a/core/src/main/java/io/crysknife/client/internal/OnFieldAccessed.java b/core/src/main/java/io/crysknife/client/internal/OnFieldAccessed.java index 9527ea0d..e9588b74 100644 --- a/core/src/main/java/io/crysknife/client/internal/OnFieldAccessed.java +++ b/core/src/main/java/io/crysknife/client/internal/OnFieldAccessed.java @@ -16,24 +16,27 @@ import java.util.function.BiFunction; import java.util.function.Supplier; -import jsinterop.base.Js; +import elemental2.core.Reflect; +import io.crysknife.client.InstanceFactory; + +import javax.enterprise.inject.Instance; /** * @author Dmitrii Tikhomirov Created by treblereel 1/1/20 */ public final class OnFieldAccessed implements BiFunction { - private final Supplier supplier; + private final Supplier supplier; - public OnFieldAccessed(Supplier supplier) { + public OnFieldAccessed(Supplier supplier) { this.supplier = supplier; } @Override public Object apply(Object o, String propertyKey) { - if (Js.asPropertyMap(o).get(propertyKey) == null) { - Js.asPropertyMap(o).set(propertyKey, supplier.get()); + if (Reflect.get(o, propertyKey) == null) { + Reflect.set(o, propertyKey, supplier.get().getInstance()); } - return Js.asPropertyMap(o).get(propertyKey); + return Reflect.get(o, propertyKey); } } diff --git a/core/src/main/java/io/crysknife/client/internal/Pair.java b/core/src/main/java/io/crysknife/client/internal/Pair.java new file mode 100644 index 00000000..d9034986 --- /dev/null +++ b/core/src/main/java/io/crysknife/client/internal/Pair.java @@ -0,0 +1,29 @@ +/* + * 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; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 10/4/21 + */ +public class Pair { + public final K a; + public final V b; + + public Pair(K a, V b) { + this.a = a; + this.b = b; + } + +} diff --git a/core/src/main/java/io/crysknife/client/internal/ProducesBeanFactory.java b/core/src/main/java/io/crysknife/client/internal/ProducesBeanFactory.java new file mode 100644 index 00000000..268171b3 --- /dev/null +++ b/core/src/main/java/io/crysknife/client/internal/ProducesBeanFactory.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2021 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 javax.enterprise.context.Dependent; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/29/21 + */ +public class ProducesBeanFactory extends BeanFactory { + + private final Supplier producer; + + public ProducesBeanFactory(BeanManager beanManager, Supplier producer) { + super(beanManager); + this.producer = producer; + } + + @Override() + public T createInstance() { + this.instance = producer.get(); + return instance; + } + + @Override() + public T getInstance() { + if (!beanDef.getScope().equals(Dependent.class)) { + if (getIncompleteInstance() != null) + return getIncompleteInstance(); + else if (instance != null) + return instance; + } + return createInstance(); + } + + @Override + public void initInstance() { + + } +} diff --git a/core/src/main/java/io/crysknife/client/internal/ProxyBeanFactory.java b/core/src/main/java/io/crysknife/client/internal/ProxyBeanFactory.java new file mode 100644 index 00000000..5c2ab854 --- /dev/null +++ b/core/src/main/java/io/crysknife/client/internal/ProxyBeanFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 + * + * 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; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/30/21 + */ +public abstract class ProxyBeanFactory extends BeanFactory { + + protected ProxyBeanFactory(BeanManager beanManager) { + super(beanManager); + } + + public abstract void dependantBeanReady(Class clazz); +} diff --git a/core/src/main/java/io/crysknife/client/internal/QualifierUtil.java b/core/src/main/java/io/crysknife/client/internal/QualifierUtil.java new file mode 100644 index 00000000..f4e0aa45 --- /dev/null +++ b/core/src/main/java/io/crysknife/client/internal/QualifierUtil.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. and/or its affiliates. + * + * 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 javax.enterprise.inject.Any; +import javax.enterprise.inject.Default; +import javax.enterprise.inject.Specializes; +import javax.inject.Named; +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * A utility class for testing the equality of qualifiers at runtime. + * + * @author Mike Brock + */ +public class QualifierUtil { + + public static final Annotation DEFAULT_ANNOTATION = new Default() { + @Override + public Class annotationType() { + return Default.class; + } + + @Override + public String toString() { + return "@Default"; + }; + }; + + public static final Annotation SPECIALIZES_ANNOTATION = new Specializes() { + @Override + public Class annotationType() { + return Specializes.class; + } + + @Override + public String toString() { + return "@Specializes"; + }; + }; + + public static final Annotation ANY_ANNOTATION = new Any() { + @Override + public Class annotationType() { + return Any.class; + } + + @Override + public String toString() { + return "@Any"; + }; + }; + + public static final Annotation[] DEFAULT_QUALIFIERS = + new Annotation[] {DEFAULT_ANNOTATION, ANY_ANNOTATION}; + + private static final Map DEFAULT_MATCHING_MAP = + new HashMap() { + { + for (final Annotation a : DEFAULT_QUALIFIERS) { + put(a.annotationType().getName(), a); + } + } + }; + + public static boolean isSameType(final Annotation a1, final Annotation a2) { + return !(a1 == null || a2 == null) && a1.annotationType().equals(a2.annotationType()); + } + + /** + * @param allOf A collection of qualifiers that must be satisfied. + * @param in A collection of qualifiers for potentially satisfying {@code allOf}. If this + * 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. + */ + public static boolean matches(final Collection allOf, + final Collection in) { + if (in.isEmpty()) { + return true; + } else { + return contains(allOf, in); + } + } + + public static boolean contains(final Collection allOf, + final Collection in) { + if (allOf.isEmpty()) + return true; + + final Map allOfMap = new HashMap<>(); + final Map inMap = new HashMap<>(); + + for (final Annotation a : in) { + inMap.put(BeanManagerUtil.qualifierToString(a), a); + } + + for (final Annotation a : allOf) { + allOfMap.put(BeanManagerUtil.qualifierToString(a), a); + } + + if (!inMap.keySet().containsAll(allOfMap.keySet())) { + return false; + } + + return true; + } + + public static boolean isDefaultAnnotations(final Annotation[] annotations) { + return annotations == null || isDefaultAnnotations(Arrays.asList(annotations)); + } + + + public static boolean isDefaultAnnotations(final Collection annotations) { + return annotations == null + || (annotations.size() == 2 && contains(DEFAULT_MATCHING_MAP.values(), annotations)); + } + + public static Named createNamed(final String name) { + return new Named() { + + @Override + public Class annotationType() { + return Named.class; + } + + @Override + public String value() { + return name; + } + }; + } + +} diff --git a/core/src/main/java/io/crysknife/client/internal/SyncBeanDefImpl.java b/core/src/main/java/io/crysknife/client/internal/SyncBeanDefImpl.java new file mode 100644 index 00000000..350b748c --- /dev/null +++ b/core/src/main/java/io/crysknife/client/internal/SyncBeanDefImpl.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. and/or its affiliates. + * + * 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.SyncBeanDef; + +import javax.enterprise.context.Dependent; +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/25/21 + */ +public class SyncBeanDefImpl implements SyncBeanDef { + + private static final List defaultQualifiers = + Arrays.asList(QualifierUtil.DEFAULT_QUALIFIERS); + + private final Class actualType; + private final Class scope; + private List qualifiers; + private List> assignableTypes; + private Optional> factory = Optional.empty(); + + protected SyncBeanDefImpl(final Class actualType) { + this.actualType = actualType; + this.scope = Dependent.class; + } + + protected SyncBeanDefImpl(final Class actualType, final Class scope) { + this.actualType = actualType; + this.scope = scope; + } + + @Override + public boolean isAssignableTo(Class type) { + return getAssignableTypes().contains(type); + } + + public Collection> getAssignableTypes() { + return Collections.unmodifiableCollection(assignableTypes); + } + + @Override + public Class getType() { + return actualType; + } + + @Override + public Class getBeanClass() { + return actualType; + } + + public Class getScope() { + return scope; + } + + @Override + public Collection getQualifiers() { + Set temp = new HashSet<>(defaultQualifiers); + if (qualifiers != null) + temp.addAll(qualifiers); + return Collections.unmodifiableCollection(temp); + } + + @Override + public Collection getActualQualifiers() { + if (qualifiers == null) { + return Collections.emptySet(); + } else { + return Collections.unmodifiableCollection(qualifiers); + } + } + + @Override + public Optional> getFactory() { + return factory; + } + + @Override + public boolean matches(Set annotations) { + return QualifierUtil.matches(annotations, getQualifiers()); + } + + @Override + 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, + qualifiers.toArray(new Annotation[qualifiers.size()])); + } + return factory.get().getInstance(); + } + + @Override + public T newInstance() { + if (!factory.isPresent()) { + BeanManagerUtil.noFactoryResolutionException(actualType, + qualifiers.toArray(new Annotation[qualifiers.size()])); + } + return factory.get().createInstance(); + } + + public static class Builder { + + private final Class actualType; + private final Class scope; + private List qualifiers; + private List> assignableTypes; + private BeanFactory factory; + + public Builder(final Class actualType, final Class scope) { + this.actualType = actualType; + this.scope = scope; + } + + public Builder withQualifiers(final Annotation[] qualifiers) { + this.qualifiers = Arrays.asList(qualifiers); + return this; + } + + public Builder withAssignableTypes(final Class[] assignableTypes) { + this.assignableTypes = Arrays.asList(assignableTypes); + return this; + } + + public Builder withFactory(BeanFactory factory) { + this.factory = factory; + return this; + } + + public SyncBeanDefImpl build() { + SyncBeanDefImpl definition = new SyncBeanDefImpl(actualType, scope); + if (qualifiers != null) { + definition.qualifiers = qualifiers; + } + + if (assignableTypes != null) { + definition.assignableTypes = assignableTypes; + } + + if (factory != null) { + factory.beanDef = definition; + definition.factory = Optional.of(factory); + } + + return definition; + } + } +} diff --git a/core/src/main/java/io/crysknife/client/ioc/ContextualTypeProvider.java b/core/src/main/java/io/crysknife/client/ioc/ContextualTypeProvider.java new file mode 100644 index 00000000..4d315925 --- /dev/null +++ b/core/src/main/java/io/crysknife/client/ioc/ContextualTypeProvider.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. and/or its affiliates. + * + * 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.ioc; + +import java.lang.annotation.Annotation; + +/** + * A contextual type provider is a provider which receives contextual information about the + * injection point which is being satisfied with this provider. The provider provides two pieces of + * contextual information: the raw class values of the most outer type arguments (if present) of the + * type of the injection point, as well as any qualifiers at that injection point. + * + * @param the type provided by this class + * @see IOCProvider + */ +public interface ContextualTypeProvider { + /** + * Called to provide an instance of the type provided for by this type provider. This method + * accepts two arguments which are provided by the container at runtime, describing the type + * arguments and qualifiers at the injection point. + * + * @param typeargs the raw class values of the outer-most type arguments. For example, if the + * injection point is of the type + * Map<String, List<? extends Number<>> then the values passed to + * this argument will be [String.class, List.class]. + * + * @param qualifiers and array of qualifiers at the injection point. + * + * @return the type produced by this provider. + */ + public T provide(Class[] typeargs, Annotation[] qualifiers); +} diff --git a/core/src/main/java/io/crysknife/client/ioc/Disposer.java b/core/src/main/java/io/crysknife/client/ioc/Disposer.java new file mode 100644 index 00000000..30785ac2 --- /dev/null +++ b/core/src/main/java/io/crysknife/client/ioc/Disposer.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. + * + * 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.ioc; + +/** + * A disposer exposes the bean managers explicit disposal functionality. An injected disposer can be + * used to dispose of the parameterized bean type. + * + * @author Mike Brock + */ +public interface Disposer { + + /** + * Requests that the bean manager dispose of the specified bean instance. + * + * @param beanInstance the instance of the bean to be disposed. + */ + public void dispose(T beanInstance); +} diff --git a/core/src/main/java/io/crysknife/client/ioc/IOCProvider.java b/core/src/main/java/io/crysknife/client/ioc/IOCProvider.java new file mode 100644 index 00000000..3ab74f1c --- /dev/null +++ b/core/src/main/java/io/crysknife/client/ioc/IOCProvider.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. and/or its affiliates. + * + * 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.ioc; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Defines a top-level provider for the IOC Container. Top-level providers are a special feature of + * the container used for defining injectable beans which are available anywhere within the + * container, from any scope, at any point of the runtime lifecycle. + *

+ * Top-level providers are used for defining framework-level features such as support for injecting + * instances of the MessageBus or the RPC Callable interface. + *

+ * The production of top-level providers are not managed beans. But the instances of the + * top-level providers are themselves, managed and are scopable. Thus, all top-level providers that + * do not declare an explicit scope are of the pseudo-dependant scope and are instantiated + * prior to all invocations of the provider. + *

+ * Classes which are annotated with @IOCProvider MUST implement either: + *

    + *
  • {@link javax.inject.Provider}
  • + *
  • {@link ContextualTypeProvider}
  • + *
+ * + * A provider can also implement {@link Disposer}, allowing it to clean up resources when a provided + * bean is destroyed. + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface IOCProvider { +} diff --git a/demo/pom.xml b/demo/pom.xml index bd033c19..9ffcefb5 100644 --- a/demo/pom.xml +++ b/demo/pom.xml @@ -12,7 +12,7 @@ ${project.build.directory}/webapp ${webappdir}/WEB-INF/lib 1.1.0 - 0.16-SNAPSHOT + 0.17-SNAPSHOT 9.4.31.v20200723 2.2 1.0.0 @@ -70,23 +70,57 @@ navigation-api ${project.version} + + io.crysknife + navigation-generator + ${project.version} + provided + org.gwtproject.user.window gwt-window - 1.0.0-RC2 + HEAD-SNAPSHOT io.crysknife - navigation-generator + databinding-api + ${project.version} + + + io.crysknife + databinding-generator + ${project.version} + provided + + + + io.crysknife + gwt-dom-generator ${project.version} provided - + + + org.gwtproject.dom + gwt-dom + HEAD-SNAPSHOT + + + + + src/main/java + + **/*.java + **/*.html + **/*.css + **/*.less + + src/main/resources @@ -118,6 +152,7 @@ + org.apache.maven.plugins maven-compiler-plugin 3.8.0 @@ -128,11 +163,13 @@ org.apache.maven.plugins maven-war-plugin - + 3.3.1 + WEB-INF/classes/** + org.apache.maven.plugins maven-source-plugin 3.0.1 @@ -160,7 +197,7 @@ ${project.build.directory}/gwt/launcherDir/${project.artifactId}/ - ADVANCED + BUNDLE @@ -198,6 +235,20 @@ + + + treblereel-snapshots + treblereel hosted artifacts-snapshots + https://repo.treblereel.org/snapshots + + true + + + true + daily + + + vertispan-releases Vertispan hosted artifacts-releases @@ -211,7 +262,7 @@ - + sonatype-snapshots-repo https://oss.sonatype.org/content/repositories/snapshots 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 6fa5e5ff..a772e51c 100644 --- a/demo/src/main/java/io/crysknife/demo/client/App.java +++ b/demo/src/main/java/io/crysknife/demo/client/App.java @@ -22,7 +22,6 @@ import elemental2.dom.HTMLDivElement; import io.crysknife.demo.client.events.Address; import io.crysknife.demo.client.events.User; -import io.crysknife.demo.client.named.NamedBeanConstructorInjectionPanel; import io.crysknife.annotation.Application; import io.crysknife.annotation.ComponentScan; import io.crysknife.ui.navigation.client.local.DefaultPage; @@ -35,9 +34,6 @@ public class App { @Inject private HTMLDivElement toast; - @Inject - private NamedBeanConstructorInjectionPanel namedBeanConstructorInjectionPanel; - @Inject private Main main; diff --git a/demo/src/main/java/io/crysknife/demo/client/Main.java b/demo/src/main/java/io/crysknife/demo/client/Main.java index c54495d8..8cf25f6f 100644 --- a/demo/src/main/java/io/crysknife/demo/client/Main.java +++ b/demo/src/main/java/io/crysknife/demo/client/Main.java @@ -16,9 +16,12 @@ import javax.annotation.PostConstruct; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; import elemental2.dom.HTMLDivElement; +import elemental2.dom.HTMLElement; +import org.gwtproject.dom.client.LabelElement; import org.jboss.elemento.IsElement; import io.crysknife.ui.templates.client.annotation.DataField; import io.crysknife.ui.templates.client.annotation.Templated; @@ -39,6 +42,14 @@ public class Main implements IsElement { @Inject private Navigation navigation; + @Inject + @DataField + @Named("span") + private HTMLElement span; + + @Inject + LabelElement repeatCountReachesLabel; + @PostConstruct public void init() { navigation.setNavigationContainer(container); diff --git a/demo/src/main/java/io/crysknife/demo/client/UI.java b/demo/src/main/java/io/crysknife/demo/client/UI.java deleted file mode 100644 index f44cdc56..00000000 --- a/demo/src/main/java/io/crysknife/demo/client/UI.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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.demo.client; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.inject.Singleton; - -import elemental2.dom.DomGlobal; -import elemental2.dom.HTMLDivElement; -import org.jboss.elemento.IsElement; -import io.crysknife.demo.client.databinding.Databinding; -import io.crysknife.demo.client.events.BeanWithCDIEvents; -import io.crysknife.demo.client.mutationobserver.MutationObserverDemo; -import io.crysknife.demo.client.named.NamedBeanConstructorInjectionPanel; -import io.crysknife.demo.client.named.NamedBeanFieldInjectionPanel; -import io.crysknife.demo.client.singletonbeans.SingletonBeans; -import io.crysknife.ui.templates.client.annotation.DataField; -import io.crysknife.ui.templates.client.annotation.Templated; -import io.crysknife.ui.navigation.client.local.PageHidden; -import io.crysknife.ui.navigation.client.local.PageHiding; -import io.crysknife.ui.navigation.client.local.PageShowing; -import io.crysknife.ui.navigation.client.local.PageShown; - -/** - * @author Dmitrii Tikhomirov - * Created by treblereel 12/5/19 - */ -@Singleton -//@Page(role = DefaultPage.class) -@Templated(value = "ui.html") -public class UI implements IsElement { - - @Inject - @DataField - protected NamedBeanFieldInjectionPanel namedBeanFieldInjectionPanel; - @Inject - @DataField - protected NamedBeanConstructorInjectionPanel namedBeanConstructorInjectionPanel; - @Inject - @DataField - protected SingletonBeans singletonBeans; - @Inject - @DataField - protected TransitiveInjection transitiveInjection; - @Inject - @DataField - protected BeanWithCDIEvents beanWithCDIEvents; - @Inject - @DataField - protected Databinding databinding; - @Inject - @DataField - protected MutationObserverDemo mutationObserverDemo; - @Inject - @DataField - HTMLDivElement root; - - @PostConstruct - public void init() { - - } - - @Override - public HTMLDivElement element() { - return root; - } - - @PageShown - public void onPageShown() { - DomGlobal.console.log(this.getClass().getCanonicalName() + " PageShown"); - } - - @PageShowing - public void onPageShowing() { - DomGlobal.console.log(this.getClass().getCanonicalName() + " PageShowing"); - } - - @PageHidden - public void onPageHidden() { - DomGlobal.console.log(this.getClass().getCanonicalName() + " PageHidden"); - } - - @PageHiding - public void onPageHiding() { - DomGlobal.console.log(this.getClass().getCanonicalName() + " PageHiding"); - } -} diff --git a/demo/src/main/java/io/crysknife/demo/client/bug/FormDisplayerView.java b/demo/src/main/java/io/crysknife/demo/client/bug/FormDisplayerView.java new file mode 100644 index 00000000..68479289 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/bug/FormDisplayerView.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * 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.demo.client.bug; + +public interface FormDisplayerView extends UberElement { + + void show(); + + void hide(); + + interface Presenter { + + } +} diff --git a/demo/src/main/java/io/crysknife/demo/client/bug/FormDisplayerViewImpl.java b/demo/src/main/java/io/crysknife/demo/client/bug/FormDisplayerViewImpl.java new file mode 100644 index 00000000..cc5dae50 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/bug/FormDisplayerViewImpl.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * 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.demo.client.bug; + +import elemental2.dom.HTMLDivElement; +import io.crysknife.client.IsElement; +import io.crysknife.ui.templates.client.annotation.DataField; +import io.crysknife.ui.templates.client.annotation.Templated; + +import javax.enterprise.context.Dependent; +import javax.inject.Inject; + +@Templated +@Dependent +public class FormDisplayerViewImpl implements FormDisplayerView, + IsElement { + + private Presenter presenter; + + @Inject + @DataField + private HTMLDivElement content; + + @Override + public void show() { + getElement().hidden = (false); + } + + @Override + public void hide() { + getElement().hidden = (true); + } + + @Override + public void init(Presenter presenter) { + + } +} diff --git a/demo/src/main/java/io/crysknife/demo/client/bug/HasPresenter.java b/demo/src/main/java/io/crysknife/demo/client/bug/HasPresenter.java new file mode 100644 index 00000000..4c163eb9 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/bug/HasPresenter.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * 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.demo.client.bug; + + +/** + * Interface to inject a Presenter into a View for MVP-based Element + * implementations. Due to limitations with CDI it is not possible to {@code @Inject} + * the correct instance of a Presenter into a View. + *

+ * Developers wishing to implement MVP-based UIs are encouraged to have + * their View implement this interface if they require access to the appropriate + * Presenter. + * @param The Presenter type + */ +public interface HasPresenter { + + void init(T presenter); + +} diff --git a/demo/src/main/java/io/crysknife/demo/client/bug/UberElement.java b/demo/src/main/java/io/crysknife/demo/client/bug/UberElement.java new file mode 100644 index 00000000..3aeb4962 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/bug/UberElement.java @@ -0,0 +1,32 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates. + * + * 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.demo.client.bug; + +/** + * Interface to inject a Presenter into a View for MVP-based Element + * implementations. Due to limitations with CDI it is not possible to {@code @Inject} + * the correct instance of a Presenter into a View. + *

+ * Developers wishing to implement MVP-based Elements are encouraged to have + * their View implement this interface if they require access to the appropriate + * Presenter. + * @param The Presenter type + * @deprecated Use {@link UberElemental} and elemental2 instead. + */ +@Deprecated +public interface UberElement extends io.crysknife.client.IsElement, HasPresenter { +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/Address.java b/demo/src/main/java/io/crysknife/demo/client/databinding/Address.java index 564c1dac..53afc423 100644 --- a/demo/src/main/java/io/crysknife/demo/client/databinding/Address.java +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/Address.java @@ -14,14 +14,14 @@ package io.crysknife.demo.client.databinding; -//import io.crysknife.databinding.client.api.Bindable; +import io.crysknife.ui.databinding.client.api.Bindable; /** * @author Dmitrii Tikhomirov * Created by treblereel 11/25/19 */ -//@Bindable -public class Address { +@Bindable +public class Address extends HasId { private String city; diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/Customer.java b/demo/src/main/java/io/crysknife/demo/client/databinding/Customer.java index 487a40bc..ca028bcc 100644 --- a/demo/src/main/java/io/crysknife/demo/client/databinding/Customer.java +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/Customer.java @@ -14,19 +14,32 @@ package io.crysknife.demo.client.databinding; -//import io.crysknife.databinding.client.api.Bindable; +import io.crysknife.ui.databinding.client.api.Bindable; + +import java.util.List; +import java.util.Set; /** * @author Dmitrii Tikhomirov * Created by treblereel 11/18/19 */ -//@Bindable -public class Customer { +@Bindable +public class Customer extends HasId { + + private long _long; + + private boolean active; private String name; private Address address; + private Set sets; + + private List lists; + + private String[] arrays; + private int age; public String getName() { @@ -63,4 +76,44 @@ public String toString() { ", age=" + age + '}'; } + + public Set getSets() { + return sets; + } + + public void setSets(Set sets) { + this.sets = sets; + } + + public String[] getArrays() { + return arrays; + } + + public void setArrays(String[] arrays) { + this.arrays = arrays; + } + + public List getLists() { + return lists; + } + + public void setLists(List lists) { + this.lists = lists; + } + + public long get_long() { + return _long; + } + + public void set_long(long _long) { + this._long = _long; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } } diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/Databinding.java b/demo/src/main/java/io/crysknife/demo/client/databinding/Databinding.java index d2d8aba2..c054080c 100644 --- a/demo/src/main/java/io/crysknife/demo/client/databinding/Databinding.java +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/Databinding.java @@ -19,20 +19,29 @@ import javax.inject.Singleton; import elemental2.dom.DomGlobal; +import elemental2.dom.HTMLBRElement; import elemental2.dom.HTMLButtonElement; import elemental2.dom.HTMLDivElement; import elemental2.dom.HTMLInputElement; +import io.crysknife.demo.client.databinding.listcomponent.KeyValueRow; +import io.crysknife.demo.client.databinding.listcomponent.RolesEditorWidgetView; +import io.crysknife.ui.databinding.client.api.AutoBound; +import io.crysknife.ui.databinding.client.api.Bound; +import io.crysknife.ui.databinding.client.api.DataBinder; +import io.crysknife.ui.databinding.client.api.StateSync; +import io.crysknife.ui.databinding.client.api.handler.property.PropertyChangeHandler; +import io.crysknife.ui.templates.client.annotation.EventHandler; import org.gwtproject.event.dom.client.ClickEvent; -//import org.gwtproject.user.client.ui.TextBox; +import org.gwtproject.user.client.ui.CheckBox; +import org.gwtproject.user.client.ui.TextBox; import org.jboss.elemento.IsElement; import io.crysknife.ui.templates.client.annotation.DataField; -import io.crysknife.ui.templates.client.annotation.EventHandler; import io.crysknife.ui.templates.client.annotation.Templated; -/*import io.crysknife.databinding.client.api.DataBinder; -import io.crysknife.databinding.client.api.StateSync; -import io.crysknife.databinding.client.api.handler.property.PropertyChangeHandler;*/ import io.crysknife.ui.navigation.client.local.Page; +import java.util.ArrayList; +import java.util.List; + /** * @author Dmitrii Tikhomirov * Created by treblereel 11/18/19 @@ -42,22 +51,35 @@ @Templated(value = "databinding.html") public class Databinding implements IsElement { - @DataField HTMLDivElement root; + @DataField + HTMLDivElement root = (HTMLDivElement) DomGlobal.document.createElement("div"); -/* @Inject - protected DataBinder dataBinder;*/ -/* @DataField @Inject - protected TextBox nameBox;*/ - //@DataField - //@Inject - //protected MyTextBox cityBox; + @AutoBound + protected DataBinder dataBinder; + + @DataField + @Inject + @Bound(property= "name") + protected TextBox nameBox; + + @DataField + @Inject + @Bound + protected CheckBox active; + + @DataField + @Inject + @Bound(property= "address.city") + protected MyTextBox cityBox; @Inject @DataField + @Bound(property= "address.street.name") protected HTMLInputElement streetBox; @Inject @DataField - protected HTMLInputElement ageBox; + @Bound + protected HTMLInputElement age; @Inject @DataField protected HTMLInputElement resultBox; @@ -73,22 +95,45 @@ public class Databinding implements IsElement { @Inject @DataField("resumeBtn") protected HTMLButtonElement resume; + private Customer customer; + @Inject + @DataField("rolesEditorWidgetView") + RolesEditorWidgetView rolesEditorWidgetView; + @PostConstruct public void init() { + Customer customer = new Customer(); + customer.setName("AAAAAAAAA"); + dataBinder.setModel(customer); + + + /* customer = dataBinder .bind(nameBox, "name") .bind(cityBox, "address.city") .bind(streetBox, "address.street.name") - .bind(ageBox, "age") - .getModel(); + .bind(age, "age") + .getModel();*/ dataBinder.addPropertyChangeHandler((PropertyChangeHandler) event -> { DomGlobal.console.log("new value " + event.toString()); onPropertyChange(event.toString()); - });*/ + }); + + List list = new ArrayList<>(); + + + list.add(new KeyValueRow("AAA","AAA")); + list.add(new KeyValueRow("BBB","BBB")); + list.add(new KeyValueRow("CCC","CCC")); + list.add(new KeyValueRow("DDD","DDD")); + + HTMLBRElement br = (HTMLBRElement) DomGlobal.document.createElement("br"); + + rolesEditorWidgetView.setRows(list); } @@ -101,12 +146,12 @@ private void onPropertyChange(String state) { resultBox.value = state; } - //@EventHandler("cityBox") + @EventHandler("cityBox") void onCityClick(final ClickEvent e) { - DomGlobal.console.log("cityBox click"); + } -/* @EventHandler("modelBtn") + @EventHandler("modelBtn") void getModel(final ClickEvent e) { onPropertyChange(dataBinder.getModel().toString()); } @@ -123,6 +168,6 @@ void onPause(final ClickEvent e) { @EventHandler("resumeBtn") void onResume(final ClickEvent e) { - dataBinder.resume(StateSync.FROM_UI); - }*/ + dataBinder.resume(StateSync.FROM_UI); + } } diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/DefaultSelectorOption.java b/demo/src/main/java/io/crysknife/demo/client/databinding/DefaultSelectorOption.java new file mode 100644 index 00000000..5f6bd62f --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/DefaultSelectorOption.java @@ -0,0 +1,39 @@ +/* + * Copyright © 2021 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.demo.client.databinding; + +import io.crysknife.ui.databinding.client.api.Bindable; + +import javax.validation.constraints.NotNull; + +/** + * @author Dmitrii Tikhomirov + * Created by treblereel 9/12/21 + */ +//@Bindable +public class DefaultSelectorOption { + + + @NotNull + private Object value; + + public Object getValue() { + return value; + } + + public void setValue(T value) { + this.value = value; + } +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/HasId.java b/demo/src/main/java/io/crysknife/demo/client/databinding/HasId.java new file mode 100644 index 00000000..d043f065 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/HasId.java @@ -0,0 +1,32 @@ +/* + * Copyright © 2021 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.demo.client.databinding; + +/** + * @author Dmitrii Tikhomirov + * Created by treblereel 9/22/21 + */ +public class HasId { + + private long id; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/MyCustomDateConverter.java b/demo/src/main/java/io/crysknife/demo/client/databinding/MyCustomDateConverter.java new file mode 100644 index 00000000..9dcb192b --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/MyCustomDateConverter.java @@ -0,0 +1,53 @@ +/* + * Copyright © 2021 + * + * 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.demo.client.databinding; + +import io.crysknife.ui.databinding.client.api.Converter; +import io.crysknife.ui.databinding.client.api.DefaultConverter; +import org.gwtproject.i18n.client.DateTimeFormat; + +import java.util.Date; + +/** + * @author Dmitrii Tikhomirov + * Created by treblereel 9/22/21 + */ +@DefaultConverter +public class MyCustomDateConverter implements Converter { + + private static final String DATE_FORMAT = "YY_DD_MM"; + + @Override + public Class getModelType() { + return Date.class; + } + + @Override + public Class getComponentType() { + return String.class; + } + + @Override + public Date toModelValue(String widgetValue) { + + return DateTimeFormat.getFormat(DATE_FORMAT).parse(widgetValue); + + } + + @Override + public String toWidgetValue(Date modelValue) { + return DateTimeFormat.getFormat(DATE_FORMAT).format((Date) modelValue); + } +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/MyTextBox.java b/demo/src/main/java/io/crysknife/demo/client/databinding/MyTextBox.java index 48f7eacf..eaa723f3 100644 --- a/demo/src/main/java/io/crysknife/demo/client/databinding/MyTextBox.java +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/MyTextBox.java @@ -14,16 +14,16 @@ package io.crysknife.demo.client.databinding; -import javax.enterprise.context.Dependent; +import org.gwtproject.user.client.ui.TextBox; -//import org.gwtproject.user.client.ui.TextBox; +import javax.enterprise.context.Dependent; /** * @author Dmitrii Tikhomirov * Created by treblereel 12/3/19 */ @Dependent -public class MyTextBox //extends TextBox +public class MyTextBox extends TextBox { } diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/Street.java b/demo/src/main/java/io/crysknife/demo/client/databinding/Street.java index d51746d7..2ef76875 100644 --- a/demo/src/main/java/io/crysknife/demo/client/databinding/Street.java +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/Street.java @@ -14,14 +14,14 @@ package io.crysknife.demo.client.databinding; -//import io.crysknife.databinding.client.api.Bindable; +import io.crysknife.ui.databinding.client.api.Bindable; /** * @author Dmitrii Tikhomirov * Created by treblereel 11/25/19 */ -//@Bindable -public class Street { +@Bindable +public class Street extends HasId { private String name; diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/ValueHolder.java b/demo/src/main/java/io/crysknife/demo/client/databinding/ValueHolder.java new file mode 100644 index 00000000..76f46755 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/ValueHolder.java @@ -0,0 +1,36 @@ +/* + * 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.demo.client.databinding; + +import io.crysknife.ui.databinding.client.api.Bindable; + +/** + * @author Dmitrii Tikhomirov + * Created by treblereel 9/1/21 + */ +@Bindable +public class ValueHolder { + + private T value; + + + public T getValue() { + return value; + } + + public void setValue(T value) { + this.value = value; + } +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/ValueHolderBoolean.java b/demo/src/main/java/io/crysknife/demo/client/databinding/ValueHolderBoolean.java new file mode 100644 index 00000000..8f5cb835 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/ValueHolderBoolean.java @@ -0,0 +1,25 @@ +/* + * 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.demo.client.databinding; + +import io.crysknife.ui.databinding.client.api.Bindable; + +/** + * @author Dmitrii Tikhomirov + * Created by treblereel 9/22/21 + */ +@Bindable +public class ValueHolderBoolean extends ValueHolder { +} diff --git a/processor/src/main/java/io/crysknife/generator/api/Builder.java b/demo/src/main/java/io/crysknife/demo/client/databinding/ValueHolderString.java similarity index 57% rename from processor/src/main/java/io/crysknife/generator/api/Builder.java rename to demo/src/main/java/io/crysknife/demo/client/databinding/ValueHolderString.java index e2b83370..3b78fde0 100644 --- a/processor/src/main/java/io/crysknife/generator/api/Builder.java +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/ValueHolderString.java @@ -12,20 +12,24 @@ * the License. */ -package io.crysknife.generator.api; +package io.crysknife.demo.client.databinding; -import io.crysknife.generator.definition.BeanDefinition; +import io.crysknife.ui.databinding.client.api.Bindable; /** - * @author Dmitrii Tikhomirov Created by treblereel 3/3/19 + * @author Dmitrii Tikhomirov + * Created by treblereel 9/22/21 */ -public abstract class Builder { +@Bindable +public class ValueHolderString extends ValueHolder{ - protected final ClassBuilder classBuilder; + private Boolean activeBoolean; - public Builder(ClassBuilder classBuilder) { - this.classBuilder = classBuilder; - } + public Boolean isActiveBoolean() { + return activeBoolean; + } - abstract void build(BeanDefinition argument); + public void setActiveBoolean(Boolean activeBoolean) { + this.activeBoolean = activeBoolean; + } } diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/KeyValueRow.java b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/KeyValueRow.java new file mode 100644 index 00000000..d985ed09 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/KeyValueRow.java @@ -0,0 +1,85 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * 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.demo.client.databinding.listcomponent; + +import io.crysknife.ui.databinding.client.api.Bindable; + +import java.util.Objects; + +@Bindable +public class KeyValueRow { + + private String key; + + private String value; + + private String uuid; + + public KeyValueRow() { + this("", ""); + } + + public KeyValueRow(String key, String value) { + this.key = Objects.isNull(key) ? "" : key; + this.value = Objects.isNull(value) ? "" : value; + this.uuid = UUID.uuid(); + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof KeyValueRow)) { + return false; + } + KeyValueRow that = (KeyValueRow) o; + return Objects.equals(getKey(), that.getKey()) && + Objects.equals(getValue(), that.getValue()) && + Objects.equals(uuid, that.uuid); + } + + @Override + public int hashCode() { + + return Objects.hash(getKey(), getValue(), uuid); + } +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesEditorWidget.html b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesEditorWidget.html new file mode 100644 index 00000000..38c8b0c3 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesEditorWidget.html @@ -0,0 +1,52 @@ + + +

+
+
+
+ + + + + + + + + + + + + + + +
+ Name + + Cardinality + + +
+
+
+
+
diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesEditorWidgetView.java b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesEditorWidgetView.java new file mode 100644 index 00000000..24d0b1f9 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesEditorWidgetView.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * 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.demo.client.databinding.listcomponent; + +import org.gwtproject.user.client.ui.IsWidget; + +import java.util.List; + +public interface RolesEditorWidgetView extends IsWidget { + + interface Presenter { + + List deserialize(final String s); + + String serialize(final List rows); + } + + void init(final Presenter presenter); + + void doSave(); + + void notifyModelChanged(); + + int getRowsCount(); + + void setRows(final List rows); + + List getRows(); + + RolesListItemWidgetView getWidget(int index); + + void setVisible(final boolean visible); + + void remove(final KeyValueRow row); + + void setReadOnly(final boolean readOnly); + + boolean isDuplicateName(final String name); +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesEditorWidgetViewImpl.java b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesEditorWidgetViewImpl.java new file mode 100644 index 00000000..d7b810e0 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesEditorWidgetViewImpl.java @@ -0,0 +1,198 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * 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.demo.client.databinding.listcomponent; + +import elemental2.dom.DomGlobal; +import elemental2.dom.NotificationEvent; +import io.crysknife.client.BeanManager; +import io.crysknife.ui.databinding.client.api.AutoBound; +import io.crysknife.ui.databinding.client.api.Bound; +import io.crysknife.ui.databinding.client.api.Convert; +import io.crysknife.ui.databinding.client.api.DataBinder; +import io.crysknife.ui.databinding.client.api.handler.property.PropertyChangeHandler; +import io.crysknife.ui.databinding.client.components.ListComponent; +import io.crysknife.ui.databinding.client.components.ListContainer; +import io.crysknife.ui.templates.client.annotation.DataField; +import io.crysknife.ui.templates.client.annotation.Templated; +import org.gwtproject.event.logical.shared.ValueChangeEvent; +import org.gwtproject.event.logical.shared.ValueChangeHandler; +import org.gwtproject.event.shared.HandlerRegistration; +import org.gwtproject.user.client.ui.Button; +import org.gwtproject.user.client.ui.Composite; +import org.gwtproject.user.client.ui.HasValue; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.Dependent; +import javax.enterprise.event.Event; +import javax.enterprise.inject.Default; +import javax.inject.Inject; +import java.lang.annotation.Annotation; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * @author Dmitrii Tikhomirov + * Created by treblereel 9/17/21 + */ +@Dependent +@Templated("RolesEditorWidget.html") +public class RolesEditorWidgetViewImpl extends Composite implements RolesEditorWidgetView, + HasValue { + + @Inject + @DataField("addButton") + protected Button addButton; + @Inject + @AutoBound + protected DataBinder> binder; + @Inject + @DataField("list") + @Bound + @ListContainer("tbody") + protected ListComponent list; + @Inject + protected Event notification; + @Inject + BeanManager beanManager; + private String serializedRoles; + private Optional presenter; + private boolean readOnly = false; + + public RolesEditorWidgetViewImpl() { + this.presenter = Optional.empty(); + } + + @Override + public String getValue() { + return serializedRoles; + } + + @Override + public void setValue(final String value) { + doSetValue(value, false, true); + } + + @Override + public void setValue(final String value, + final boolean fireEvents) { + doSetValue(value, fireEvents, false); + } + + protected void doSetValue(final String value, + final boolean fireEvents, + final boolean initializeView) { + final String oldValue = serializedRoles; + serializedRoles = value; + if (initializeView) { + initView(); + } + if (fireEvents) { + ValueChangeEvent.fireIfNotEqual(this, oldValue, serializedRoles); + } + setReadOnly(readOnly); + } + + private List removeEmptyRoles(List roles) { + return roles.stream().filter(row -> !StringUtils.isEmpty(row.getKey())).collect(Collectors.toList()); + } + + protected void initView() { + setRows(presenter.map(p -> p.deserialize(serializedRoles)).orElse(null)); + } + + @Override + public HandlerRegistration addValueChangeHandler(final ValueChangeHandler handler) { + return addHandler(handler, ValueChangeEvent.getType()); + } + + @Override + public void init(final Presenter presenter) { + + } + + @Override + public void doSave() { + presenter.map(p -> p.serialize(removeEmptyRoles(getRows()))).ifPresent(newValue -> setValue(newValue, true)); + } + + @Override + public void notifyModelChanged() { + doSave(); + } + + @PostConstruct + public void init2() { + addButton.addClickHandler((e) -> handleAddVarButton()); + //binder.bind(list, "this", Convert.getConverter(List.class, List.class), null, false); + + binder.addPropertyChangeHandler((PropertyChangeHandler>) + event -> event.getNewValue() + .forEach(elm -> DomGlobal.console.log("elm -> " + elm.getKey() + " " + elm.getValue()))); + } + + protected void handleAddVarButton() { + getRows().add(getRowsCount(), new KeyValueRow()); + final RolesListItemWidgetView widget = getWidget(getRowsCount() - 1); + widget.setParentWidget(this); + } + + @Override + public int getRowsCount() { + return Optional.ofNullable(getRows()).map(List::size).orElse(0); + } + + @Override + public List getRows() { + return binder.getModel(); + } + + @Override + public void setRows(final List rows) { + binder.setModel(rows); + for (int i = 0; i < getRowsCount(); i++) { + RolesListItemWidgetView widget = getWidget(i); + widget.setParentWidget(this); + } + } + + @Override + public RolesListItemWidgetView getWidget(int index) { + return list.getComponent(index); + } + + @Override + public void remove(final KeyValueRow row) { + getRows().remove(row); + doSave(); + } + + @Override + public void setReadOnly(final boolean readOnly) { + this.readOnly = readOnly; + addButton.setEnabled(!readOnly); + for (int i = 0; i < getRowsCount(); i++) { + getWidget(i).setReadOnly(readOnly); + } + } + + @Override + public boolean isDuplicateName(String name) { + return getRows().stream().filter(row -> Objects.equals(row.getKey(), name)).count() > 1; + } +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesListItemWidgetView.java b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesListItemWidgetView.java new file mode 100644 index 00000000..7f521c97 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesListItemWidgetView.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * 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.demo.client.databinding.listcomponent; + +import io.crysknife.client.IsElement; +import io.crysknife.ui.databinding.client.api.HasModel; +import org.gwtproject.user.client.TakesValue; + +public interface RolesListItemWidgetView extends TakesValue, + HasModel, + IsElement { + + void init(); + + void setParentWidget(final RolesEditorWidgetView parentWidget); + + void notifyModelChanged(); + + boolean isDuplicateName(final String name); + + void setReadOnly(final boolean readOnly); +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesListItemWidgetViewImpl.java b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesListItemWidgetViewImpl.java new file mode 100644 index 00000000..c858e38d --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/RolesListItemWidgetViewImpl.java @@ -0,0 +1,156 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * 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.demo.client.databinding.listcomponent; + +import elemental2.dom.DomGlobal; +import elemental2.dom.HTMLTableRowElement; +import elemental2.dom.NotificationEvent; +import io.crysknife.client.IsElement; +import io.crysknife.ui.databinding.client.api.AutoBound; +import io.crysknife.ui.databinding.client.api.Bound; +import io.crysknife.ui.databinding.client.api.DataBinder; +import io.crysknife.ui.templates.client.annotation.DataField; +import io.crysknife.ui.templates.client.annotation.Templated; +import org.gwtproject.user.client.ui.Button; +import org.gwtproject.user.client.ui.TextBox; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.Dependent; +import javax.enterprise.event.Event; +import javax.inject.Inject; +import java.util.Objects; +import java.util.Optional; + +@Templated("RolesEditorWidget.html#tableRow") +@Dependent +public class RolesListItemWidgetViewImpl implements RolesListItemWidgetView, + IsElement { + + public static final String INVALID_CHARACTERS_MESSAGE = "Invalid characters"; + private static final String DUPLICATE_NAME_ERROR_MESSAGE = "A role with this name already exists"; + private static final String EMPTY_ERROR_MESSAGE = "Role name already cannot be empty"; + + @Inject + @AutoBound + protected DataBinder row; + + @Inject + @Bound(property = "key") + @DataField("roleInput") + protected TextBox role; + + @Inject + @Bound(property = "value") + @DataField("cardinalityInput") + protected TextBox cardinality; + + private boolean allowDuplicateNames = false; + + private String previousRole; + + private String previousCardinality; + + @Inject + protected Event notification; + + @Inject + @DataField + protected Button deleteButton; + + @Inject + @DataField("tableRow") + protected HTMLTableRowElement tableRow; + + /** + * Required for implementation of Delete button. + */ + private Optional parentWidget; + + protected RolesListItemWidgetViewImpl() { + } + + public void setParentWidget(final RolesEditorWidgetView parentWidget) { + this.parentWidget = Optional.ofNullable(parentWidget); + } + + @PostConstruct + public void init() { + //role.setRegExp(ALPHA_NUM_REGEXP, INVALID_CHARACTERS_MESSAGE, INVALID_CHARACTERS_MESSAGE); + role.addChangeHandler((e) -> handleValueChanged()); + cardinality.addChangeHandler((e) -> handleValueChanged()); + cardinality.addFocusHandler((e) -> handleFocus()); + //deleteButton.setIcon(IconType.TRASH); + deleteButton.addClickHandler((e) -> handleDeleteButton()); + //show the widget that is hidden on the template + tableRow.hidden = false; + deleteButton.setText("DELETE"); + } + + private void handleFocus() { + if (Objects.equals("0", cardinality.getText())) { + } + } + + private void handleValueChanged() { + } + + @Override + public void setReadOnly(final boolean readOnly) { + deleteButton.setEnabled(!readOnly); + role.setEnabled(!readOnly); + cardinality.setEnabled(!readOnly); + } + + @Override + public boolean isDuplicateName(final String name) { + return parentWidget.map(p -> p.isDuplicateName(name)).orElse(false); + } + + public void handleDeleteButton() { + parentWidget.ifPresent(p -> p.remove(getValue())); + } + + @Override + public void notifyModelChanged() { + parentWidget.ifPresent(RolesEditorWidgetView::notifyModelChanged); + } + + @Override + public void setValue(KeyValueRow value) { + //when first setting the value then set as previous as well + if (Objects.isNull(previousRole)) { + previousRole = value.getKey(); + previousCardinality = value.getValue(); + } + row.setModel(value); + } + + @Override + public KeyValueRow getValue() { + return row.getModel(); + } + + @Override + public KeyValueRow getModel() { + return getValue(); + } + + @Override + public void setModel(KeyValueRow model) { + setValue(model); + } +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/StringUtils.java b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/StringUtils.java new file mode 100644 index 00000000..f2dfa389 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/StringUtils.java @@ -0,0 +1,252 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * 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.demo.client.databinding.listcomponent; + +import java.util.Arrays; + +public class StringUtils { + + private StringUtils() { + } + + public static boolean isEmpty(final String s) { + return null == s || s.trim().length() == 0; + } + + public static boolean nonEmpty(final String s) { + return !isEmpty(s); + } + + public static boolean hasNonEmpty(final String... values) { + return values != null && Arrays.stream(values).anyMatch(StringUtils::nonEmpty); + } + + /** + * Returns true if string starts and ends with double-quote + * @param str + * @return + */ + public static boolean isQuoted(String str) { + if (str == null || str.isEmpty()) { + return false; + } + return (str.startsWith("\"") && str.endsWith("\"")); + } + + /** + * Puts strings inside quotes. + * @param str + * @return + */ + public static String createQuotedString(final String str) { + if (isEmpty(str)) { + return str; + } + return "\"" + str + "\""; + } + + /** + * Puts strings inside quotes and numerics are left as they are. + * @param str + * @return + */ + public static String createQuotedStringIfNotNumeric(String str) { + if (isEmpty(str)) { + return str; + } + try { + Double.parseDouble(str); + } catch (NumberFormatException nfe) { + return "\"" + str + "\""; + } + return str; + } + + /** + * Replacing unsafe characters by HTML escaping. + *

+ * IMPORTANT NOTE + * Url encoding is not supported on the Engine side so this method should be used for attribute values. + * @param value a string to escape illegal characters on the client side + * @return an escaped string + */ + public static String replaceIllegalCharsAttribute(final String value) { + if (isEmpty(value)) { + return value; + } + + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + final char c = value.charAt(i); + switch (c) { + case '<': + sb.append("<"); + break; + case '>': + sb.append(">"); + break; + case '&': + sb.append("&"); + break; + case '"': + sb.append("""); + break; + default: + sb.append(c); + break; + } + } + return sb.toString(); + } + + /** + * Replacing unsafe characters by HTML escaping. + *

+ * IMPORTANT NOTE + * Url encoding is not supported on the Engine side so this method should be used for attribute values. + * @param value a string to escape illegal characters on the client side for Data Objects + * @return an escaped string + */ + public static String replaceIllegalCharsForDataObjects(final String value) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + final char c = value.charAt(i); + + switch (c) { + case '#': + case '"': + case ':': + case ' ': + sb.append("-"); + break; + case '\n': // Leave as is + break; + + // Normal Characters + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case '\'': + case '?': + case '*': + case '/': + case '+': + case '_': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + sb.append(c); + break; + default: + sb.append("-"); + break; + } + } + return sb.toString(); + } + + /** + * Returning unsafe characters by HTML escaping to the string. + * @param value string encoded by {@link StringUtils#replaceIllegalCharsAttribute} + * @return a decoded string + */ + public static String revertIllegalCharsAttribute(final String value) { + if (isEmpty(value)) { + return value; + } + + return value.replace("<", "<") + .replace(">", ">") + .replace("&", "&") + .replace(""", "\""); + } + + /** + * Removes double-quotes from around a string + * @param str + * @return + */ + public static String createUnquotedString(String str) { + if (isEmpty(str)) { + return str; + } + if (str.startsWith("\"")) { + str = str.substring(1); + } + if (str.endsWith("\"")) { + str = str.substring(0, + str.length() - 1); + } + return str; + } +} diff --git a/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/UUID.java b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/UUID.java new file mode 100644 index 00000000..5a884459 --- /dev/null +++ b/demo/src/main/java/io/crysknife/demo/client/databinding/listcomponent/UUID.java @@ -0,0 +1,97 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates. + * + * 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. + */ + +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package io.crysknife.demo.client.databinding.listcomponent; + +public class UUID { + + private static final char[] CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); + + /** + * Generate a random uuid of the specified length. Example: uuid(15) returns + * "VcydxgltxrVZSTV" + * @param len the desired number of characters + */ + public static String uuid(final int len) { + return uuid(len, + CHARS.length); + } + + /** + * Generate a random uuid of the specified length, and radix. Examples: + *

    + *
  • uuid(8, 2) returns "01001010" (8 character ID, base=2) + *
  • uuid(8, 10) returns "47473046" (8 character ID, base=10) + *
  • uuid(8, 16) returns "098F4D35" (8 character ID, base=16) + *
+ * @param len the desired number of characters + * @param radix the number of allowable values for each character (must be <= + * 62) + */ + public static String uuid(final int len, + final int radix) { + if (radix > CHARS.length) { + throw new IllegalArgumentException(); + } + char[] uuid = new char[len]; + // Compact form + for (int i = 0; i < len; i++) { + uuid[i] = CHARS[(int) (Math.random() * radix)]; + } + return new String(uuid); + } + + /** + * Generate a RFC4122, version 4 ID prefixed with an '_' character to make it compatible with the + * https://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName expected by the bpmn2 xsd, and dmn xsd. + * Example: "_92329D39-6F5C-4520-ABFC-AAB64544E172" + */ + public static String uuid() { + char[] uuid = new char[36]; + int r; + // rfc4122 requires these characters + uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; + uuid[14] = '4'; + // Fill in random data. At i==19 set the high bits of clock sequence as + // per rfc4122, sec. 4.1.5 + for (int i = 0; i < 36; i++) { + if (uuid[i] == 0) { + r = (int) (Math.random() * 16); + uuid[i] = CHARS[(i == 19) ? (r & 0x3) | 0x8 : r & 0xf]; + } + } + return new String(prefixWith(uuid, + '_')); + } + + private static char[] prefixWith(char[] original, + char prefix) { + final char[] prefixed = new char[original.length + 1]; + prefixed[0] = prefix; + System.arraycopy(original, + 0, + prefixed, + 1, + original.length); + return prefixed; + } +} diff --git a/demo/src/main/resources/io/crysknife/demo/client/dependent/DependentBeans.gss b/demo/src/main/java/io/crysknife/demo/client/dependent/DependentBeans.gss similarity index 100% rename from demo/src/main/resources/io/crysknife/demo/client/dependent/DependentBeans.gss rename to demo/src/main/java/io/crysknife/demo/client/dependent/DependentBeans.gss diff --git a/demo/src/main/java/io/crysknife/demo/client/dependent/DependentBeans.java b/demo/src/main/java/io/crysknife/demo/client/dependent/DependentBeans.java index 5ab8970a..6e3ece1c 100644 --- a/demo/src/main/java/io/crysknife/demo/client/dependent/DependentBeans.java +++ b/demo/src/main/java/io/crysknife/demo/client/dependent/DependentBeans.java @@ -84,7 +84,7 @@ public void onFallbackInputChange(final ClickEvent e) { @PostConstruct public void init(){ - DomGlobal.console.log("CREATED "); + } @Override 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 1366a7a8..945c7857 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,10 +15,12 @@ package io.crysknife.demo.client.events; import java.util.Random; +import java.util.function.Supplier; import javax.annotation.PostConstruct; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; +import javax.enterprise.inject.Instance; import javax.inject.Inject; import javax.inject.Singleton; @@ -26,6 +28,7 @@ import elemental2.dom.HTMLDivElement; import elemental2.dom.HTMLInputElement; import elemental2.dom.MouseEvent; +import io.crysknife.client.internal.AbstractEventFactory; import org.jboss.elemento.IsElement; import io.crysknife.ui.templates.client.annotation.DataField; import io.crysknife.ui.templates.client.annotation.EventHandler; diff --git a/demo/src/main/java/io/crysknife/demo/client/inject/cyclic/BeanFour.java b/demo/src/main/java/io/crysknife/demo/client/inject/cyclic/BeanFour.java index cb8df7cb..02bbbcca 100644 --- a/demo/src/main/java/io/crysknife/demo/client/inject/cyclic/BeanFour.java +++ b/demo/src/main/java/io/crysknife/demo/client/inject/cyclic/BeanFour.java @@ -36,7 +36,7 @@ public class BeanFour { @PostConstruct public void init() { - beanOne = beanManager.lookupBean(BeanOne.class).get(); + beanOne = beanManager.lookupBean(BeanOne.class).getInstance(); beanOne.say(); } } 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 13e5527a..80b8ce00 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 @@ -41,10 +41,12 @@ */ @Singleton @Page -@Templated(value = "mutationobserverdemo.html#mutationobserverdemo") +@Templated(value = "mutationobserverdemo.html#mutationobserverdemo", stylesheet = "style.css") public class MutationObserverDemo implements IsElement { - @DataField HTMLDivElement mutationobserverdemo; + @DataField + @Inject + private HTMLDivElement mutationobserverdemo; @DataField @Inject diff --git a/demo/src/main/java/io/crysknife/demo/client/navigation/WidgetPanel.java b/demo/src/main/java/io/crysknife/demo/client/navigation/WidgetPanel.java index 1c524b7b..54540409 100644 --- a/demo/src/main/java/io/crysknife/demo/client/navigation/WidgetPanel.java +++ b/demo/src/main/java/io/crysknife/demo/client/navigation/WidgetPanel.java @@ -21,7 +21,6 @@ import elemental2.dom.HTMLButtonElement; import elemental2.dom.HTMLDivElement; import org.gwtproject.event.dom.client.ClickEvent; -import org.jboss.elemento.IsElement; import io.crysknife.demo.client.about.About; import io.crysknife.ui.templates.client.annotation.DataField; import io.crysknife.ui.templates.client.annotation.EventHandler; @@ -41,14 +40,11 @@ @Page(path = "navigation") @Singleton @Templated("navigation.html") -public class WidgetPanel implements IsElement { +public class WidgetPanel implements io.crysknife.client.IsElement { @Inject private Navigation navigation; - @DataField - private HTMLDivElement root; - @Inject private TransitionTo toAboutPage; @@ -56,11 +52,6 @@ public class WidgetPanel implements IsElement { @DataField private HTMLButtonElement button; - @Override - public HTMLDivElement element() { - return root; - } - @EventHandler("button") public void onClick(final ClickEvent e) { toAboutPage.go(); diff --git a/demo/src/main/java/io/crysknife/demo/client/singletonbeans/SingletonBeans.java b/demo/src/main/java/io/crysknife/demo/client/singletonbeans/SingletonBeans.java index 8c59c9ea..2a2f161c 100644 --- a/demo/src/main/java/io/crysknife/demo/client/singletonbeans/SingletonBeans.java +++ b/demo/src/main/java/io/crysknife/demo/client/singletonbeans/SingletonBeans.java @@ -51,12 +51,16 @@ public class SingletonBeans implements IsElement { @DataField private HTMLButtonElement checkBtn; - @Inject private BeanOne beanOne1Instance; - @Inject private BeanOne beanOne2Instance; + @Inject + public SingletonBeans(BeanOne beanOne1Instance, BeanOne beanOne2Instance) { + this.beanOne1Instance = beanOne1Instance; + this.beanOne2Instance = beanOne2Instance; + } + @PostConstruct public void init() { } diff --git a/demo/src/main/resources/io/crysknife/demo/client/bug/FormDisplayerViewImpl.html b/demo/src/main/resources/io/crysknife/demo/client/bug/FormDisplayerViewImpl.html new file mode 100644 index 00000000..d984e82b --- /dev/null +++ b/demo/src/main/resources/io/crysknife/demo/client/bug/FormDisplayerViewImpl.html @@ -0,0 +1,2 @@ +
+
\ No newline at end of file diff --git a/demo/src/main/resources/io/crysknife/demo/client/databinding/databinding.html b/demo/src/main/resources/io/crysknife/demo/client/databinding/databinding.html index 77d1279b..88e7c3cc 100644 --- a/demo/src/main/resources/io/crysknife/demo/client/databinding/databinding.html +++ b/demo/src/main/resources/io/crysknife/demo/client/databinding/databinding.html @@ -31,7 +31,8 @@ Name City Street - Age + Age + Active
@@ -41,6 +42,12 @@
+ +
+ ListComponent demo: +
+ + \ No newline at end of file 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 197affc5..8cf7f9d6 100644 --- a/demo/src/main/resources/io/crysknife/demo/client/main.html +++ b/demo/src/main/resources/io/crysknife/demo/client/main.html @@ -1,4 +1,4 @@ -
+
-
+
+ +
\ No newline at end of file diff --git a/demo/src/main/resources/io/crysknife/demo/client/mutationobserver/style.css b/demo/src/main/resources/io/crysknife/demo/client/mutationobserver/style.css new file mode 100644 index 00000000..dd2aa4e4 --- /dev/null +++ b/demo/src/main/resources/io/crysknife/demo/client/mutationobserver/style.css @@ -0,0 +1,3 @@ +.textBox { + width: 700px; +} \ No newline at end of file diff --git a/demo/src/main/resources/io/crysknife/demo/client/navigation/navigation.html b/demo/src/main/resources/io/crysknife/demo/client/navigation/navigation.html index fecbef24..94b401ec 100644 --- a/demo/src/main/resources/io/crysknife/demo/client/navigation/navigation.html +++ b/demo/src/main/resources/io/crysknife/demo/client/navigation/navigation.html @@ -5,7 +5,7 @@ Title -
+
initialization
diff --git a/demo/src/main/resources/io/crysknife/demo/client/ui.html b/demo/src/main/resources/io/crysknife/demo/client/ui.html
deleted file mode 100644
index a9608f9a..00000000
--- a/demo/src/main/resources/io/crysknife/demo/client/ui.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-    
-    Title
-
-
-
-
-
-
-
-
-
-
-
-
- - \ No newline at end of file diff --git a/demo/src/main/webapp/index.html b/demo/src/main/webapp/index.html index 908751bd..2f1efb22 100644 --- a/demo/src/main/webapp/index.html +++ b/demo/src/main/webapp/index.html @@ -26,10 +26,6 @@ - - diff --git a/internal-bom/pom.xml b/internal-bom/pom.xml new file mode 100644 index 00000000..cb8243c3 --- /dev/null +++ b/internal-bom/pom.xml @@ -0,0 +1,243 @@ + + + 4.0.0 + + io.crysknife + internal-bom + 0.3-SNAPSHOT + pom + + + Internal BOM (Bill Of Materials) + POC DI for GWT 3 or j2cl + https://github.com/treblereel + + + + treblereel + Dmitrii Tikhomirov + chani.liet@gmail.com + + + + + + Apache License Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo + + + + + Treblereel + https://github.com/treblereel + + + + UTF-8 + UTF-8 + + 1.8 + 1.8 + + 3.8.0 + 3.0.1 + 2.8.2 + 3.0 + 1.6 + 1.6.7 + 1.9.5 + 2.5.3 + 3.0.0-M3 + 3.2.4 + 3.2.0 + 3.1.0 + 2.13.0 + 3.0 + 3.2.0 + + + 1.6 + 3.11 + 2.8.0 + + 1.0.3 + 1.11.3 + 1 + 1.10 + 2.0.0 + 28.1-jre + 4.8.53 + + HEAD-SNAPSHOT + 3.15.18 + 1.1.0 + 0.11 + 1.0-rc7 + 4.13.1 + + + + + + + org.gwtproject + gwt-bom + HEAD-SNAPSHOT + pom + import + + + + javax.inject + javax.inject + ${javax.inject.version} + provided + + + com.google.jsinterop + jsinterop-annotations + ${google.jsinterop.annotations.version} + + + com.google.elemental2 + elemental2-dom + ${elemental2.version} + + + org.jboss.elemento + elemento-core + ${elemento.version} + + + com.google.auto + auto-common + ${auto.common.version} + + + org.apache.commons + commons-lang3 + ${apache.commons.commons-lang3.version} + + + com.google.auto.service + auto-service + ${auto.service.version} + + + commons-io + commons-io + ${apache.commons.io.version} + + + com.github.javaparser + javaparser-core + ${javaparser.core.version} + + + org.apache.commons + commons-text + ${apache.commons.commons-text.version} + + + org.apache.maven.scm + maven-scm-provider-gitexe + ${maven.scm.provider.gitexe.plugin.version} + + + com.google.guava + guava + ${google.guava.version} + + + io.github.classgraph + classgraph + ${classgraph.classgraph.version} + + + org.jsoup + jsoup + ${jsoup.version} + + + de.inetsoftware + jlessc + ${lesscss.version} + + + junit + junit + ${junit.version} + test + + + + + + + treblereel-snapshots + treblereel Public Repo + https://repo.treblereel.org/snapshots + + true + + + false + + + + + treblereel-releases + treblereel Public Repo + https://repo.treblereel.org/releases + + true + + + false + + + + + vertispan-jre + Vertispan Public Repo + https://repo.vertispan.com/j2cl/ + + true + + + false + + + + vertispan + Vertispan Public Repo + https://repo.vertispan.com/gwt-snapshot/ + + true + + + false + + + + google-snapshots + Google Snapshots Repo + https://oss.sonatype.org/content/repositories/google-snapshots + + false + + + true + + + + sonatype-public + Sonatype Public Snapshots Repo + https://oss.sonatype.org/content/repositories/public + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 84a92776..a3772c5c 100644 --- a/pom.xml +++ b/pom.xml @@ -1,495 +1,397 @@ - - 4.0.0 + + 4.0.0 - io.crysknife - crysknife-parent - 0.3-SNAPSHOT - pom + io.crysknife + crysknife-parent + 0.3-SNAPSHOT + pom - crysknife-parent - POC DI for GWT 3 or j2cl - https://github.com/treblereel - - - - treblereel - Dmitrii Tikhomirov - chani.liet@gmail.com - - - - - - Apache License Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 - repo - - - - - Treblereel + crysknife-parent + POC DI for GWT 3 or j2cl https://github.com/treblereel - - - https://github.com/crysknife-io/crysknife - scm:git:git@github.com:crysknife-io/crysknife.git - scm:git:git://github.com/crysknife-io/crysknife.git - HEAD - + + + treblereel + Dmitrii Tikhomirov + chani.liet@gmail.com + + - - UTF-8 - UTF-8 + + + Apache License Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo + + - 1.8 - 1.8 + + Treblereel + https://github.com/treblereel + - 3.8.0 - 3.0.1 - 2.8.2 - 3.0 - 1.6 - 1.6.7 - 1.9.5 - 2.5.3 - 3.0.0-M3 - 3.2.4 - 3.2.0 - 3.1.0 - 2.13.0 - 3.0 + + https://github.com/crysknife-io/crysknife + scm:git:git@github.com:crysknife-io/crysknife.git + scm:git:git://github.com/crysknife-io/crysknife.git + HEAD + + + UTF-8 + UTF-8 - 1.6 - 3.11 - 2.8.0 + 1.8 + 1.8 - 1.0.3 - 1.11.3 - 1 - 1.7.0.1.1 - 2.0.0 - 28.1-jre - 4.8.53 + 3.8.1 + 3.0.1 + 2.8.2 + 3.0 + 1.6 + 1.6.7 + 1.9.5 + 2.5.3 + 3.0.0-M3 + 3.2.4 + 3.2.0 + 3.1.0 + 2.13.0 + 3.0 + 3.2.0 - 1.0.0-RC1 - 3.15.18 - 1.1.0 - 0.11 - 1.0-rc7 - 4.13.1 - - - annotations - processor - core - ui - tests - + 1.6 + 3.11 + 2.8.0 - - - - javax.inject - javax.inject - ${javax.inject.version} - provided - - - com.google.jsinterop - jsinterop-annotations - ${google.jsinterop.annotations.version} - - - com.google.elemental2 - elemental2-dom - ${elemental2.version} - - - org.gwtproject.safehtml - gwt-safehtml - ${gwtproject.version} - - - org.gwtproject.regexp - gwt-regexp - ${gwtproject.version} - - - org.gwtproject.event - gwt-event-dom - ${gwtproject.version} - - - org.gwtproject.event - gwt-logical-event - ${gwtproject.version} - - - org.gwtproject.event - gwt-event-legacy - ${gwtproject.version} - - - org.gwtproject.user.history - gwt-history - ${gwtproject.version} - - - org.gwtproject.dom - gwt-dom - ${gwtproject.version} - - - org.gwtproject.user.window - gwt-window - 1.0.0-RC2 - - - org.jboss.elemento - elemento-core - ${elemento.version} - - - com.google.auto - auto-common - ${auto.common.version} - - - org.apache.commons - commons-lang3 - ${apache.commons.commons-lang3.version} - - - com.google.auto.service - auto-service - ${auto.service.version} - - - commons-io - commons-io - ${apache.commons.io.version} - - - com.github.javaparser - javaparser-core - ${javaparser.core.version} - - - org.apache.commons - commons-text - ${apache.commons.commons-text.version} - - - com.google.guava - guava - ${google.guava.version} - - - io.github.classgraph - classgraph - ${classgraph.classgraph.version} - - - org.jsoup - jsoup - ${jsoup.version} - - - org.lesscss - lesscss - ${lesscss.version} - - - junit - junit - ${junit.version} - test - - - + HEAD-SNAPSHOT + 1.11.3 + 1 + 1.7.0.1.1 + 2.0.0 + 28.1-jre + 4.8.115 - - - - - org.apache.maven.plugins - maven-source-plugin - ${maven.source.plugin.version} - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven.compiler.plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - - - - org.apache.maven.plugins - maven-shade-plugin - ${maven.shade.plugin.version} - - - org.apache.maven.plugins - maven-jar-plugin - ${maven.jar.plugin.version} - - - org.apache.maven.plugins - maven-clean-plugin - ${maven.clean.plugin.version} - - - com.coveo - fmt-maven-plugin - ${maven.fmt.plugin.version} - - - - check - - - - - - + 3.15.18 + 1.1.0 + 0.11 + 1.0-rc7 + 4.13.1 + - - - org.commonjava.maven.plugins - directory-maven-plugin - 0.1 - - - directories - - highest-basedir - - initialize - - rootDir - - - - - - com.mycila - license-maven-plugin - ${maven.license.plugin.version} - -
${rootDir}/LICENSE.header
- ${project.build.sourceEncoding} - true - - SLASHSTAR_STYLE - - - .github/** - **/README.md - **/LICENSE - **/LICENSE.header - **/AUTHORS - **/src/test/resources/** - **/src/main/resources/** - **/war - **/pom.xml - **/.flattened-pom.xml - **/gwt-unitcache - **/webapp/** - **/tomcatconf/** - .github/FUNDING.yml - eclipse-java-google-style.xml - docs/** - **/*.less - **/.factorypath - - - ${project.inceptionYear} - ${project.organization.name} - -
- - - - check - - - -
- - net.revelc.code.formatter - formatter-maven-plugin - ${maven.formatter.plugin.version} - - - - format - - - ${rootDir}/eclipse-java-google-style.xml - UTF-8 - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - ${maven.enforcer.plugin.version} - - false - - - - (1.8.0,) - - - - - - enforce-sane-versions - - enforce - - - - - - maven-deploy-plugin - ${maven.deploy.plugin.version} - - - default-deploy - deploy - - deploy - - - - - - org.apache.maven.plugins - maven-release-plugin - ${maven.release.plugin.version} - - true - false - forked-path - -Dgpg.passphrase=${gpg.passphrase} - + + internal-bom + bom + annotations + processor + core + ui + tests + + + - - org.apache.maven.scm - maven-scm-provider-gitexe - ${maven.scm.provider.gitexe.plugin.version} - + + io.crysknife + bom + ${project.version} + pom + import + - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.2.0 - - false - - - - org.sonatype.plugins - nexus-staging-maven-plugin - ${maven.nexus.staging.plugin.version} - true - - ossrh - https://oss.sonatype.org/ - true - - -
- - + - - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - + + + + + org.apache.maven.plugins + maven-source-plugin + ${maven.source.plugin.version} + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.plugin.version} + + + org.apache.maven.plugins + maven-shade-plugin + ${maven.shade.plugin.version} + + + org.apache.maven.plugins + maven-jar-plugin + ${maven.jar.plugin.version} + + + org.apache.maven.plugins + maven-clean-plugin + ${maven.clean.plugin.version} + + + com.coveo + fmt-maven-plugin + ${maven.fmt.plugin.version} + + + com.mycila + license-maven-plugin + ${maven.license.plugin.version} + + + net.revelc.code.formatter + formatter-maven-plugin + ${maven.formatter.plugin.version} + + + org.apache.maven.plugins + maven-enforcer-plugin + ${maven.enforcer.plugin.version} + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven.deploy.plugin.version} + + + org.apache.maven.plugins + maven-release-plugin + ${maven.release.plugin.version} + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven.javadoc.plugin.version} + + + org.sonatype.plugins + nexus-staging-maven-plugin + ${maven.nexus.staging.plugin.version} + + + - - - vertispan - vertispan - https://repo.vertispan.com/gwt-snapshot/ - - - vertispan-releases - Vertispan hosted artifacts-releases - https://repo.vertispan.com/j2cl - - true - - - true - - - - vertispan-snapshots - Vertispan Snapshots - https://repo.vertispan.com/gwt-snapshot/ - - true - daily - fail - - - - - - - - release - - - org.apache.maven.plugins - maven-source-plugin - ${maven.source.plugin.version} - - - attach-sources - - jar-no-fork - - - - - - - org.apache.maven.plugins - maven-gpg-plugin - ${maven.gpg.plugin.version} - - - sign-artifacts - verify - - sign - - - - + + com.mycila + license-maven-plugin + +
${user.dir}/LICENSE.header
+ ${project.build.sourceEncoding} + true + + SLASHSTAR_STYLE + + + .github/** + **/README.md + **/LICENSE + **/LICENSE.header + **/AUTHORS + **/src/test/resources/** + **/src/main/resources/** + **/war + **/pom.xml + **/.flattened-pom.xml + **/gwt-unitcache + **/webapp/** + **/tomcatconf/** + .github/FUNDING.yml + eclipse-java-google-style.xml + docs/** + **/*.less + **/.factorypath + + + ${project.inceptionYear} + ${project.organization.name} + +
+ + + + check + + + +
+ + net.revelc.code.formatter + formatter-maven-plugin + + + + format + + + ${user.dir}/eclipse-java-google-style.xml + UTF-8 + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + false + + + + 3.0 + + + (1.8.0,) + + + + + + enforce-sane-versions + + enforce + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + + default-deploy + deploy + + deploy + + + + + + org.apache.maven.plugins + maven-release-plugin + + true + false + forked-path + -Dgpg.passphrase=${gpg.passphrase} + + + + org.apache.maven.scm + maven-scm-provider-gitexe + ${maven.scm.provider.gitexe.plugin.version} + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + false + + + + org.sonatype.plugins + nexus-staging-maven-plugin + true + + ossrh + https://oss.sonatype.org/ + true + +
-
-
-
+ +
+ + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + treblereel-snapshots + Vertispan hosted artifacts-releases + https://repo.treblereel.org/snapshots + + + vertispan + vertispan + https://repo.vertispan.com/gwt-snapshot/ + + + vertispan-releases + Vertispan hosted artifacts-releases + https://repo.vertispan.com/j2cl + + true + + + true + + + + vertispan-snapshots + Vertispan Snapshots + https://repo.vertispan.com/gwt-snapshot/ + + true + daily + fail + + + + + + + + release + + + + org.apache.maven.plugins + maven-source-plugin + ${maven.source.plugin.version} + + + attach-sources + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + ${maven.gpg.plugin.version} + + + sign-artifacts + verify + + sign + + + + + + + +
\ No newline at end of file diff --git a/processor/pom.xml b/processor/pom.xml index 7ae3de99..20ebd51e 100644 --- a/processor/pom.xml +++ b/processor/pom.xml @@ -61,6 +61,10 @@ org.apache.commons commons-text + + commons-io + commons-io + io.github.classgraph classgraph diff --git a/processor/src/main/java/io/crysknife/ApplicationProcessor.java b/processor/src/main/java/io/crysknife/ApplicationProcessor.java index 6d03e0b1..38bdca2a 100644 --- a/processor/src/main/java/io/crysknife/ApplicationProcessor.java +++ b/processor/src/main/java/io/crysknife/ApplicationProcessor.java @@ -14,11 +14,30 @@ package io.crysknife; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; +import com.google.auto.service.AutoService; +import io.crysknife.annotation.Application; +import io.crysknife.annotation.Generator; +import io.crysknife.exception.GenerationException; +import io.crysknife.generator.BeanManagerGenerator; +import io.crysknife.generator.FactoryGenerator; +import io.crysknife.generator.IOCGenerator; +import io.crysknife.generator.context.GenerationContext; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.generator.info.BeanInfoGenerator; +import io.crysknife.logger.PrintWriterTreeLogger; +import io.crysknife.logger.TreeLogger; +import io.crysknife.task.BeanProcessorTask; +import io.crysknife.task.CheckCyclesTask; +import io.crysknife.task.FireAfterTask; +import io.crysknife.task.FireBeforeTask; +import io.crysknife.task.ProcessComponentScanAnnotationTask; +import io.crysknife.task.ProcessGraphTask; +import io.crysknife.task.ProcessSubClassesTask; +import io.crysknife.task.TaskGroup; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ClassInfoList; +import io.github.classgraph.ScanResult; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Processor; @@ -28,26 +47,10 @@ import javax.lang.model.SourceVersion; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; - -import com.google.auto.common.MoreElements; -import com.google.auto.service.AutoService; -import io.github.classgraph.ClassGraph; -import io.github.classgraph.ClassInfo; -import io.github.classgraph.ClassInfoList; -import io.github.classgraph.ScanResult; -import io.crysknife.annotation.Application; -import io.crysknife.annotation.Generator; -import io.crysknife.annotation.ComponentScan; -import io.crysknife.exception.GenerationException; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.context.GenerationContext; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.graph.Graph; -import io.crysknife.generator.info.BeanInfoGenerator; -import io.crysknife.generator.scanner.ComponentInjectionResolverScanner; -import io.crysknife.generator.scanner.ComponentScanner; -import io.crysknife.generator.scanner.ProducersScan; -import io.crysknife.generator.scanner.QualifiersScan; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Optional; +import java.util.Set; @AutoService(Processor.class) @SupportedSourceVersion(SourceVersion.RELEASE_8) @@ -69,25 +72,32 @@ public boolean process(Set annotations, context = new GenerationContext(roundEnvironment, processingEnv); iocContext = new IOCContext(context); + TreeLogger logger = new PrintWriterTreeLogger(); + Optional maybeApplication = processApplicationAnnotation(iocContext); if (!maybeApplication.isPresent()) { return true; } this.application = maybeApplication.get(); - processComponentScanAnnotation(); initAndRegisterGenerators(); - processQualifiersScan(); - processComponentScan(); - processInjectionScan(); - processProducersScan(); - fireIOCGeneratorBefore(); - processGraph(); - new FactoryGenerator(iocContext).generate(); - new BeanInfoGenerator(iocContext).generate(); - new BeanManagerGenerator(iocContext, context).generate(); - fireIOCGeneratorAfter(); + TaskGroup taskGroup = new TaskGroup(logger.branch(TreeLogger.DEBUG, "start processing")); + // taskGroup.addTask(new InitAndRegisterGeneratorsTask(iocContext, logger)); + taskGroup.addTask(new FireBeforeTask(iocContext, logger)); + + taskGroup.addTask(new ProcessComponentScanAnnotationTask(iocContext, logger, application)); + taskGroup.addTask(new BeanProcessorTask(iocContext, logger)); + taskGroup.addTask(new ProcessSubClassesTask(iocContext, logger)); + // taskGroup.addTask(new FireBeforeTask(iocContext, logger)); + taskGroup.addTask(new ProcessGraphTask(iocContext, logger, application)); + taskGroup.addTask(new CheckCyclesTask(iocContext, logger)); + + taskGroup.addTask(new FactoryGenerator(iocContext)); + taskGroup.addTask(new BeanInfoGenerator(iocContext)); + taskGroup.addTask(new BeanManagerGenerator(iocContext)); + taskGroup.addTask(new FireAfterTask(iocContext, logger)); + taskGroup.execute(); return false; } @@ -110,21 +120,6 @@ private Optional processApplicationAnnotation(IOCContext iocContext return applications.stream().findFirst(); } - private void processComponentScanAnnotation() { - packages = new HashSet<>(); - context.getRoundEnvironment().getElementsAnnotatedWith(ComponentScan.class) - .forEach(componentScan -> { - String[] values = componentScan.getAnnotation(ComponentScan.class).value(); - for (String aPackage : values) { - packages.add(aPackage); - } - }); - - if (packages.isEmpty()) { - packages.add(MoreElements.getPackage(application).getQualifiedName().toString()); - } - } - private void initAndRegisterGenerators() { try (ScanResult scanResult = new ClassGraph().enableAllInfo().scan()) { ClassInfoList routeClassInfoList = @@ -140,32 +135,4 @@ private void initAndRegisterGenerators() { } } } - - private void processQualifiersScan() { - new QualifiersScan(iocContext).process(); - } - - private void processComponentScan() { - new ComponentScanner(iocContext, context).scan(); - } - - private void processInjectionScan() { - new ComponentInjectionResolverScanner(iocContext).scan(); - } - - private void processProducersScan() { - new ProducersScan(iocContext).scan(); - } - - private void fireIOCGeneratorBefore() { - iocContext.getGenerators().forEach((meta, generator) -> generator.before()); - } - - private void processGraph() { - new Graph(iocContext).process(application); - } - - private void fireIOCGeneratorAfter() { - iocContext.getGenerators().forEach((meta, generator) -> generator.after()); - } } diff --git a/processor/src/main/java/io/crysknife/BeanManagerGenerator.java b/processor/src/main/java/io/crysknife/BeanManagerGenerator.java deleted file mode 100644 index 42d8e89d..00000000 --- a/processor/src/main/java/io/crysknife/BeanManagerGenerator.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * 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; - -import java.io.IOException; -import java.io.PrintWriter; -import java.lang.annotation.Annotation; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; - -import javax.inject.Named; -import javax.inject.Provider; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.TypeElement; -import javax.tools.JavaFileObject; - -import com.github.javaparser.ast.CompilationUnit; -import com.github.javaparser.ast.Modifier; -import com.github.javaparser.ast.NodeList; -import com.github.javaparser.ast.body.BodyDeclaration; -import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; -import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.expr.AssignExpr; -import com.github.javaparser.ast.expr.BinaryExpr; -import com.github.javaparser.ast.expr.Expression; -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.NullLiteralExpr; -import com.github.javaparser.ast.expr.ObjectCreationExpr; -import com.github.javaparser.ast.expr.StringLiteralExpr; -import com.github.javaparser.ast.expr.ThisExpr; -import com.github.javaparser.ast.stmt.BlockStmt; -import com.github.javaparser.ast.stmt.IfStmt; -import com.github.javaparser.ast.stmt.ReturnStmt; -import com.github.javaparser.ast.type.ClassOrInterfaceType; -import io.crysknife.annotation.Application; -import io.crysknife.client.BeanManager; -import io.crysknife.client.Instance; -import io.crysknife.client.internal.AbstractBeanManager; -import io.crysknife.exception.GenerationException; -import io.crysknife.generator.context.GenerationContext; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.util.Utils; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/28/19 - */ -public class BeanManagerGenerator { - - private final IOCContext iocContext; - - private final GenerationContext generationContext; - - BeanManagerGenerator(IOCContext iocContext, GenerationContext generationContext) { - this.iocContext = iocContext; - this.generationContext = generationContext; - } - - void generate() { - try { - build(); - } catch (IOException e) { - throw new GenerationException(e); - } - } - - private void build() throws IOException { - JavaFileObject builderFile = generationContext.getProcessingEnvironment().getFiler() - .createSourceFile(BeanManager.class.getCanonicalName() + "Impl"); - try (PrintWriter out = new PrintWriter(builderFile.openWriter())) { - out.append(new BeanManagerGeneratorBuilder().build().toString()); - } - } - - private void maybeAddQualifiers(MethodCallExpr call, TypeElement field, String annotationName) { - if (annotationName != null) { - boolean isNamed = field.getAnnotation(Named.class) != null; - annotationName = isNamed ? Named.class.getCanonicalName() : annotationName; - ObjectCreationExpr annotation = new ObjectCreationExpr(); - annotation.setType(new ClassOrInterfaceType() - .setName(isNamed ? Named.class.getCanonicalName() : annotationName)); - NodeList> anonymousClassBody = new NodeList<>(); - - MethodDeclaration annotationType = new MethodDeclaration(); - annotationType.setModifiers(Modifier.Keyword.PUBLIC); - annotationType.setName("annotationType"); - annotationType.setType(new ClassOrInterfaceType().setName("Class")); - annotationType.getBody().get() - .addAndGetStatement(new ReturnStmt(new NameExpr(annotationName + ".class"))); - anonymousClassBody.add(annotationType); - - if (isNamed) { - MethodDeclaration value = new MethodDeclaration(); - value.setModifiers(Modifier.Keyword.PUBLIC); - value.setName("value"); - value.setType(new ClassOrInterfaceType().setName("String")); - value.getBody().get().addAndGetStatement( - new ReturnStmt(new StringLiteralExpr(field.getAnnotation(Named.class).value()))); - anonymousClassBody.add(value); - } - - annotation.setAnonymousClassBody(anonymousClassBody); - - call.addArgument(annotation); - } - } - - public class BeanManagerGeneratorBuilder { - - private CompilationUnit clazz = new CompilationUnit(); - - private ClassOrInterfaceDeclaration classDeclaration; - - private MethodDeclaration getMethodDeclaration; - - public CompilationUnit build() { - initClass(); - addFields(); - initInitMethod(); - addGetInstanceMethod(); - return clazz; - } - - private void initClass() { - clazz.setPackageDeclaration(BeanManager.class.getPackage().getName()); - classDeclaration = clazz.addClass(BeanManager.class.getSimpleName() + "Impl"); - clazz.addImport(Provider.class); - clazz.addImport(Map.class); - clazz.addImport(HashMap.class); - clazz.addImport(Annotation.class); - clazz.addImport(Instance.class); - clazz.addImport(AbstractBeanManager.class); - - ClassOrInterfaceType factory = new ClassOrInterfaceType(); - factory.setName("AbstractBeanManager"); - - classDeclaration.getExtendedTypes().add(factory); - } - - private void addFields() { - addBeanInstance(); - } - - private void initInitMethod() { - MethodDeclaration init = classDeclaration.addMethod("init", Modifier.Keyword.PRIVATE); - - TypeElement beanManager = - generationContext.getElements().getTypeElement(BeanManager.class.getCanonicalName()); - generateInitEntry(init, beanManager); - - iocContext.getOrderedBeans().stream() - .filter(field -> (field.getAnnotation(Application.class) == null)) - .filter(field -> field.getKind().equals(ElementKind.CLASS)).collect(Collectors.toSet()) - .forEach(field -> generateInitEntry(init, field)); - - iocContext.getQualifiers().forEach((type, beans) -> beans.forEach((annotation, - definition) -> generateInitEntry(init, type, definition.getType(), annotation))); - } - - 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 generateInitEntry(MethodDeclaration init, TypeElement field) { - generateInitEntry(init, field, field, null); - } - - private void generateInitEntry(MethodDeclaration init, TypeElement field, TypeElement factory, - String annotation) { - if (!iocContext.getBlacklist().contains(field.getQualifiedName().toString())) { - MethodCallExpr call = new MethodCallExpr(new ThisExpr(), "register") - .addArgument( - new FieldAccessExpr(new NameExpr(field.getQualifiedName().toString()), "class")) - .addArgument( - new MethodCallExpr(new NameExpr(Utils.getQualifiedFactoryName(factory)), "create")); - maybeAddQualifiers(call, factory, annotation); - init.getBody().ifPresent(body -> body.addAndGetStatement(call)); - } - } - - private void addGetBody() { - NameExpr instance = new NameExpr("instance"); - IfStmt ifStmt = new IfStmt().setCondition( - new BinaryExpr(instance, new NullLiteralExpr(), BinaryExpr.Operator.EQUALS)); - BlockStmt blockStmt = new BlockStmt(); - blockStmt.addAndGetStatement(generateInstanceInitializer()); - blockStmt.addAndGetStatement(new MethodCallExpr(instance, "init")); - ifStmt.setThenStmt(blockStmt); - getMethodDeclaration.getBody().ifPresent(body -> body.addAndGetStatement(ifStmt)); - - getMethodDeclaration.getBody() - .ifPresent(body -> body.getStatements().add(new ReturnStmt(instance))); - } - - protected Expression generateInstanceInitializer() { - ObjectCreationExpr newInstance = new ObjectCreationExpr(); - newInstance - .setType(new ClassOrInterfaceType().setName(BeanManager.class.getSimpleName() + "Impl")); - return new AssignExpr().setTarget(new NameExpr("instance")).setValue(newInstance); - } - } -} diff --git a/processor/src/main/java/io/crysknife/FactoryGenerator.java b/processor/src/main/java/io/crysknife/FactoryGenerator.java deleted file mode 100644 index 5c03d092..00000000 --- a/processor/src/main/java/io/crysknife/FactoryGenerator.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import javax.lang.model.element.TypeElement; - -import io.crysknife.generator.api.ClassBuilder; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 2/20/19 - */ -public class FactoryGenerator { - - private final IOCContext iocContext; - - FactoryGenerator(IOCContext iocContext) { - this.iocContext = iocContext; - } - - void generate() { - Set> beans = - new HashSet<>(iocContext.getBeans().entrySet()); - - for (Map.Entry entry : beans) { - new ClassBuilder(entry.getValue()).build(); - } - } -} diff --git a/processor/src/main/java/io/crysknife/definition/BeanDefinition.java b/processor/src/main/java/io/crysknife/definition/BeanDefinition.java new file mode 100644 index 00000000..90b8b529 --- /dev/null +++ b/processor/src/main/java/io/crysknife/definition/BeanDefinition.java @@ -0,0 +1,143 @@ +/* + * 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.definition; + +import com.google.auto.common.MoreTypes; +import io.crysknife.annotation.CircularDependency; +import io.crysknife.generator.IOCGenerator; +import io.crysknife.util.Utils; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.context.Dependent; +import javax.inject.Singleton; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.type.TypeMirror; +import java.lang.annotation.Annotation; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/3/21 + */ +public class BeanDefinition implements Definition { + + private final TypeMirror type; + + private Set fields = new LinkedHashSet<>(); + private Set constructorParams = new LinkedHashSet<>(); + private Set methods = new LinkedHashSet<>(); + private Set dependencies = new LinkedHashSet<>(); + private Set> decorators = new LinkedHashSet<>(); + private Optional> iocGenerator = Optional.empty(); + + private Set subclasses = new LinkedHashSet<>(); + + public BeanDefinition(TypeMirror type) { + this.type = type; + } + + public TypeMirror getType() { + return type; + } + + public Set getFields() { + return fields; + } + + public Set getConstructorParams() { + return constructorParams; + } + + public List getAnnotationMirrors() { + return MoreTypes.asTypeElement(type).getAnnotationMirrors(); + } + + public Set getSubclasses() { + return subclasses; + } + + public Set getMethods() { + return methods; + } + + public Set getDependencies() { + return dependencies; + } + + public Optional> getIocGenerator() { + return iocGenerator; + } + + public void setIocGenerator(IOCGenerator iocGenerator) { + this.iocGenerator = Optional.of(iocGenerator); + } + + public boolean isProxy() { + return MoreTypes.asTypeElement(type).getAnnotation(CircularDependency.class) != null; + } + + @Override + public int hashCode() { + return Objects.hash(MoreTypes.asTypeElement(type).getQualifiedName().toString()); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + BeanDefinition that = (BeanDefinition) o; + return MoreTypes.asTypeElement(type).getQualifiedName().toString() + .equals(MoreTypes.asTypeElement(that.type).getQualifiedName().toString()); + } + + public String getPackageName() { + return Utils.getPackageName(MoreTypes.asTypeElement(type)); + } + + public String getClassFactoryName() { + return Utils.getQualifiedFactoryName(type); + } + + public String getQualifiedName() { + return MoreTypes.asTypeElement(type).getQualifiedName().toString(); + } + + public Set> getDecorators() { + return decorators; + } + + public Annotation getScope() { + if (MoreTypes.asTypeElement(type).getAnnotation(Singleton.class) != null) { + return MoreTypes.asTypeElement(type).getAnnotation(Singleton.class); + } + + if (MoreTypes.asTypeElement(type).getAnnotation(ApplicationScoped.class) != null) { + return MoreTypes.asTypeElement(type).getAnnotation(ApplicationScoped.class); + } + + return new Dependent() { + + @Override + public Class annotationType() { + return Dependent.class; + } + }; + } +} diff --git a/processor/src/main/java/io/crysknife/definition/BeanDefinitionFactory.java b/processor/src/main/java/io/crysknife/definition/BeanDefinitionFactory.java new file mode 100644 index 00000000..cee7742e --- /dev/null +++ b/processor/src/main/java/io/crysknife/definition/BeanDefinitionFactory.java @@ -0,0 +1,62 @@ +/* + * 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.definition; + +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; +import io.crysknife.processor.ConstructorInjectionPointProcessor; +import io.crysknife.processor.FieldProcessor; + +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.TypeMirror; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/3/21 + */ +public class BeanDefinitionFactory { + + private final IOCContext context; + private final TreeLogger logger; + private final FieldProcessor fieldProcessor; + private final ConstructorInjectionPointProcessor constructorInjectionPointProcessor; + + public BeanDefinitionFactory(IOCContext context, TreeLogger logger) { + this.context = context; + this.logger = logger; + this.fieldProcessor = new FieldProcessor(context, logger); + this.constructorInjectionPointProcessor = + new ConstructorInjectionPointProcessor(context, logger); + } + + public BeanDefinition of(TypeMirror type) throws UnableToCompleteException { + validateBean(type); + BeanDefinition bean = new BeanDefinition(type); + + fieldProcessor.process(bean); + constructorInjectionPointProcessor.process(bean); + + return bean; + } + + public ProducesBeanDefinition of(ExecutableElement produces) throws UnableToCompleteException { + ProducesBeanDefinition bean = new ProducesBeanDefinition(produces); + return bean; + } + + private void validateBean(TypeMirror type) { + + } +} diff --git a/tests/src/test/java/org/treblereel/DependentTest.java b/processor/src/main/java/io/crysknife/definition/Definition.java similarity index 83% rename from tests/src/test/java/org/treblereel/DependentTest.java rename to processor/src/main/java/io/crysknife/definition/Definition.java index d7323a8e..1656f201 100644 --- a/tests/src/test/java/org/treblereel/DependentTest.java +++ b/processor/src/main/java/io/crysknife/definition/Definition.java @@ -12,11 +12,11 @@ * the License. */ -package org.treblereel; +package io.crysknife.definition; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 + * @author Dmitrii Tikhomirov Created by treblereel 9/4/21 */ -public class DependentTest { +public interface Definition { } diff --git a/processor/src/main/java/io/crysknife/processor/TypeProcessor.java b/processor/src/main/java/io/crysknife/definition/Injectable.java similarity index 61% rename from processor/src/main/java/io/crysknife/processor/TypeProcessor.java rename to processor/src/main/java/io/crysknife/definition/Injectable.java index 96c5de91..4b2d2917 100644 --- a/processor/src/main/java/io/crysknife/processor/TypeProcessor.java +++ b/processor/src/main/java/io/crysknife/definition/Injectable.java @@ -12,23 +12,23 @@ * the License. */ -package io.crysknife.processor; - -import javax.lang.model.element.Element; +package io.crysknife.definition; import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.context.IOCContext; + +import java.util.Optional; /** - * @author Dmitrii Tikhomirov Created by treblereel 3/4/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/11/21 */ -public abstract class TypeProcessor { +public interface Injectable { + + Optional> getGenerator(); + + void setGenerator(IOCGenerator generator); - protected IOCGenerator generator; + Optional getImplementation(); - protected TypeProcessor(IOCGenerator generator) { - this.generator = generator; - } + void setImplementation(BeanDefinition implementation); - public abstract void process(IOCContext context, Element element); } diff --git a/processor/src/main/java/io/crysknife/definition/InjectableVariableDefinition.java b/processor/src/main/java/io/crysknife/definition/InjectableVariableDefinition.java new file mode 100644 index 00000000..5fe46e1f --- /dev/null +++ b/processor/src/main/java/io/crysknife/definition/InjectableVariableDefinition.java @@ -0,0 +1,53 @@ +/* + * 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.definition; + +import io.crysknife.generator.IOCGenerator; + +import javax.lang.model.element.VariableElement; +import java.util.Optional; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/11/21 + */ +public class InjectableVariableDefinition extends VariableDefinition implements Injectable { + + private Optional> generator = Optional.empty(); + private Optional implementation = Optional.empty(); + + public InjectableVariableDefinition(BeanDefinition parent, VariableElement variableElement) { + super(parent, variableElement); + } + + @Override + public Optional> getGenerator() { + return generator; + } + + @Override + public void setGenerator(IOCGenerator generator) { + this.generator = Optional.of(generator); + } + + @Override + public Optional getImplementation() { + return implementation; + } + + @Override + public void setImplementation(BeanDefinition implementation) { + this.implementation = Optional.of(implementation); + } +} diff --git a/processor/src/main/java/io/crysknife/definition/InjectionParameterDefinition.java b/processor/src/main/java/io/crysknife/definition/InjectionParameterDefinition.java new file mode 100644 index 00000000..04527771 --- /dev/null +++ b/processor/src/main/java/io/crysknife/definition/InjectionParameterDefinition.java @@ -0,0 +1,27 @@ +/* + * 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.definition; + +import javax.lang.model.element.VariableElement; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/11/21 + */ +public class InjectionParameterDefinition extends InjectableVariableDefinition { + + public InjectionParameterDefinition(BeanDefinition parent, VariableElement variableElement) { + super(parent, variableElement); + } +} diff --git a/processor/src/main/java/io/crysknife/definition/MethodDefinition.java b/processor/src/main/java/io/crysknife/definition/MethodDefinition.java new file mode 100644 index 00000000..dd2d778f --- /dev/null +++ b/processor/src/main/java/io/crysknife/definition/MethodDefinition.java @@ -0,0 +1,50 @@ +/* + * 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.definition; + +import io.crysknife.generator.IOCGenerator; + +import javax.lang.model.element.ExecutableElement; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/4/21 + */ +public class MethodDefinition implements Definition { + + private final ExecutableElement executableElement; + private final BeanDefinition beanDefinition; + private final Set> decorators = new HashSet<>(); + + + MethodDefinition(BeanDefinition beanDefinition, ExecutableElement executableElement) { + this.beanDefinition = beanDefinition; + this.executableElement = executableElement; + } + + public ExecutableElement getExecutableElement() { + return executableElement; + } + + public BeanDefinition getBeanDefinition() { + return beanDefinition; + } + + public Set> getDecorators() { + return decorators; + } + +} diff --git a/processor/src/main/java/io/crysknife/definition/MethodDefinitionFactory.java b/processor/src/main/java/io/crysknife/definition/MethodDefinitionFactory.java new file mode 100644 index 00000000..396b7f41 --- /dev/null +++ b/processor/src/main/java/io/crysknife/definition/MethodDefinitionFactory.java @@ -0,0 +1,40 @@ +/* + * 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.definition; + +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; + +import javax.lang.model.element.ExecutableElement; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/6/21 + */ +public class MethodDefinitionFactory { + + private final IOCContext context; + private final TreeLogger logger; + + public MethodDefinitionFactory(IOCContext context, TreeLogger logger) { + this.context = context; + this.logger = logger; + } + + public MethodDefinition of(BeanDefinition beanDefinition, ExecutableElement executableElement) { + MethodDefinition methodDefinition = new MethodDefinition(beanDefinition, executableElement); + beanDefinition.getMethods().add(methodDefinition); + return methodDefinition; + } +} diff --git a/processor/src/main/java/io/crysknife/definition/ParameterDefinition.java b/processor/src/main/java/io/crysknife/definition/ParameterDefinition.java new file mode 100644 index 00000000..5104ffbb --- /dev/null +++ b/processor/src/main/java/io/crysknife/definition/ParameterDefinition.java @@ -0,0 +1,27 @@ +/* + * 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.definition; + +import javax.lang.model.element.VariableElement; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/11/21 + */ +public class ParameterDefinition extends VariableDefinition { + + public ParameterDefinition(BeanDefinition parent, VariableElement variableElement) { + super(parent, variableElement); + } +} diff --git a/processor/src/main/java/io/crysknife/definition/ProducesBeanDefinition.java b/processor/src/main/java/io/crysknife/definition/ProducesBeanDefinition.java new file mode 100644 index 00000000..6a4898b3 --- /dev/null +++ b/processor/src/main/java/io/crysknife/definition/ProducesBeanDefinition.java @@ -0,0 +1,70 @@ +/* + * 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.definition; + +import com.google.auto.common.MoreElements; +import com.google.auto.common.MoreTypes; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.context.Dependent; +import javax.inject.Singleton; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import java.lang.annotation.Annotation; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/6/21 + */ +public class ProducesBeanDefinition extends BeanDefinition { + + private ExecutableElement method; + + public ProducesBeanDefinition(ExecutableElement method) { + super(method.getReturnType()); + this.method = method; + } + + public ExecutableElement getMethod() { + return method; + } + + public TypeElement getProducer() { + return MoreElements.asType(method.getEnclosingElement()); + } + + public boolean isSingleton() { + return method.getAnnotation(Singleton.class) != null + || method.getAnnotation(ApplicationScoped.class) != null; + } + + @Override + public Annotation getScope() { + if (method.getAnnotation(Singleton.class) != null) { + return method.getAnnotation(Singleton.class); + } + + if (method.getAnnotation(ApplicationScoped.class) != null) { + return method.getAnnotation(ApplicationScoped.class); + } + + return new Dependent() { + + @Override + public Class annotationType() { + return Dependent.class; + } + }; + } +} diff --git a/processor/src/main/java/io/crysknife/definition/UnscopedBeanDefinition.java b/processor/src/main/java/io/crysknife/definition/UnscopedBeanDefinition.java new file mode 100644 index 00000000..ea3c58a1 --- /dev/null +++ b/processor/src/main/java/io/crysknife/definition/UnscopedBeanDefinition.java @@ -0,0 +1,70 @@ +/* + * 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.definition; + +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.LambdaExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.google.auto.common.MoreTypes; +import io.crysknife.client.internal.InstanceImpl; +import io.crysknife.generator.IOCGenerator; +import io.crysknife.generator.api.ClassBuilder; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.util.Utils; + +import javax.lang.model.type.TypeMirror; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/9/21 + */ +public class UnscopedBeanDefinition extends BeanDefinition { + + public UnscopedBeanDefinition(TypeMirror type, IOCContext context) { + super(type); + setIocGenerator(new UnscopedIOCGenerator(context)); + } + + private static class UnscopedIOCGenerator extends IOCGenerator { + + private UnscopedIOCGenerator(IOCContext context) { + super(context); + } + + @Override + public void register() { + + } + + @Override + public void generate(ClassBuilder clazz, Definition beanDefinition) { + + } + + public Expression generateBeanLookupCall(ClassBuilder clazz, + InjectableVariableDefinition fieldPoint) { + + String clazzName = + Utils.getQualifiedName(MoreTypes.asTypeElement(fieldPoint.getVariableElement().asType())); + + clazz.getClassCompilationUnit().addImport(InstanceImpl.class); + + return new ObjectCreationExpr().setType(InstanceImpl.class) + .addArgument(new ObjectCreationExpr().setType(clazzName)); + + } + } + +} diff --git a/processor/src/main/java/io/crysknife/definition/VariableDefinition.java b/processor/src/main/java/io/crysknife/definition/VariableDefinition.java new file mode 100644 index 00000000..ed1b2501 --- /dev/null +++ b/processor/src/main/java/io/crysknife/definition/VariableDefinition.java @@ -0,0 +1,48 @@ +/* + * 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.definition; + +import io.crysknife.generator.IOCGenerator; + +import javax.lang.model.element.VariableElement; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/11/21 + */ +public class VariableDefinition implements Definition { + + private final VariableElement variableElement; + private final BeanDefinition parent; + protected final Set> decorators = new HashSet<>(); + + public VariableDefinition(BeanDefinition parent, VariableElement variableElement) { + this.variableElement = variableElement; + this.parent = parent; + } + + public VariableElement getVariableElement() { + return variableElement; + } + + public BeanDefinition getBeanDefinition() { + return parent; + } + + public Set> getDecorators() { + return decorators; + } +} diff --git a/processor/src/main/java/io/crysknife/exception/UnableToCompleteException.java b/processor/src/main/java/io/crysknife/exception/UnableToCompleteException.java index 3681cb78..a4bc3894 100644 --- a/processor/src/main/java/io/crysknife/exception/UnableToCompleteException.java +++ b/processor/src/main/java/io/crysknife/exception/UnableToCompleteException.java @@ -13,6 +13,12 @@ */ package io.crysknife.exception; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import java.util.Objects; +import java.util.Set; + /** * Used to indicate that some part of a multi-step process failed. Typically, operation can continue * after this exception is caught. @@ -57,6 +63,9 @@ *
*/ public class UnableToCompleteException extends Exception { + + public Set errors; + public UnableToCompleteException(String msg, Exception e) { super(msg, e); } @@ -69,5 +78,27 @@ public UnableToCompleteException(String e) { super(e); } + public UnableToCompleteException(Set e) { + this.errors = e; + } + public UnableToCompleteException() {} + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + + if (!(o instanceof UnableToCompleteException)) + return false; + + UnableToCompleteException that = (UnableToCompleteException) o; + + return new EqualsBuilder().append(getMessage(), that.getMessage()).isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37).append(getMessage()).toHashCode(); + } } diff --git a/processor/src/main/java/io/crysknife/generator/BeanIOCGenerator.java b/processor/src/main/java/io/crysknife/generator/BeanIOCGenerator.java index fca9573f..d4df4965 100644 --- a/processor/src/main/java/io/crysknife/generator/BeanIOCGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/BeanIOCGenerator.java @@ -14,48 +14,29 @@ package io.crysknife.generator; -import java.io.IOException; -import java.io.PrintWriter; - -import javax.annotation.processing.FilerException; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; - -import com.github.javaparser.ast.expr.Expression; import io.crysknife.exception.GenerationException; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.GenerationContext; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.point.FieldPoint; +import io.crysknife.definition.BeanDefinition; import io.crysknife.util.Utils; +import javax.annotation.processing.FilerException; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; +import java.io.IOException; +import java.io.PrintWriter; + /** * @author Dmitrii Tikhomirov Created by treblereel 4/4/19 */ -public abstract class BeanIOCGenerator extends IOCGenerator { +public abstract class BeanIOCGenerator extends IOCGenerator { public BeanIOCGenerator(IOCContext iocContext) { super(iocContext); } - /** - * @param clazz - * @param fieldPoint - * @param beanDefinition - * - * @return Expression, how to call instance of this bean ? - */ - public abstract Expression generateBeanCall(ClassBuilder clazz, FieldPoint fieldPoint, - BeanDefinition beanDefinition); - - @Override - public void generateBeanFactory(ClassBuilder clazz, Definition beanDefinition) { - - } - - public void write(ClassBuilder clazz, BeanDefinition beanDefinition, GenerationContext context) { + public void write(ClassBuilder clazz, T beanDefinition, GenerationContext context) { try { String fileName = Utils.getQualifiedFactoryName(beanDefinition.getType()); String source = clazz.toSourceCode(); diff --git a/processor/src/main/java/io/crysknife/generator/BeanManagerGenerator.java b/processor/src/main/java/io/crysknife/generator/BeanManagerGenerator.java new file mode 100644 index 00000000..5244f329 --- /dev/null +++ b/processor/src/main/java/io/crysknife/generator/BeanManagerGenerator.java @@ -0,0 +1,526 @@ +/* + * 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.generator; + +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.FieldDeclaration; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.expr.ArrayCreationExpr; +import com.github.javaparser.ast.expr.ArrayInitializerExpr; +import com.github.javaparser.ast.expr.AssignExpr; +import com.github.javaparser.ast.expr.BinaryExpr; +import com.github.javaparser.ast.expr.CastExpr; +import com.github.javaparser.ast.expr.EnclosedExpr; +import com.github.javaparser.ast.expr.Expression; +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.NullLiteralExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.ast.expr.StringLiteralExpr; +import com.github.javaparser.ast.expr.ThisExpr; +import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.IfStmt; +import com.github.javaparser.ast.stmt.ReturnStmt; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.google.auto.common.MoreTypes; +import io.crysknife.annotation.Application; +import io.crysknife.client.BeanManager; +import io.crysknife.client.internal.BeanFactory; +import io.crysknife.client.internal.InstanceImpl; +import io.crysknife.client.internal.ProducesBeanFactory; +import io.crysknife.client.internal.QualifierUtil; +import io.crysknife.client.internal.SyncBeanDefImpl; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.ProducesBeanDefinition; +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.task.Task; +import io.crysknife.util.Utils; + +import javax.enterprise.inject.Default; +import javax.enterprise.inject.Instance; +import javax.enterprise.inject.Specializes; +import javax.inject.Named; +import javax.inject.Provider; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.type.TypeMirror; +import javax.tools.JavaFileObject; +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +import static javax.lang.model.element.Modifier.ABSTRACT; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 3/28/19 + */ +public class BeanManagerGenerator implements Task { + + private final IOCContext iocContext; + + private final BeanOracle oracle; + + private final TypeMirror OBJECT; + + public BeanManagerGenerator(IOCContext iocContext) { + this.iocContext = iocContext; + this.oracle = new BeanOracle(iocContext); + OBJECT = iocContext.getGenerationContext().getElements() + .getTypeElement(Object.class.getCanonicalName()).asType(); + } + + public void execute() throws UnableToCompleteException { + try { + build(); + } catch (IOException e) { + throw new GenerationException(e); + } + } + + private void build() throws IOException { + JavaFileObject builderFile = iocContext.getGenerationContext().getProcessingEnvironment() + .getFiler().createSourceFile(BeanManager.class.getCanonicalName() + "Impl"); + try (PrintWriter out = new PrintWriter(builderFile.openWriter())) { + out.append(new BeanManagerGeneratorBuilder().build().toString()); + } + } + + public class BeanManagerGeneratorBuilder { + + private CompilationUnit clazz = new CompilationUnit(); + + private ClassOrInterfaceDeclaration classDeclaration; + + private MethodDeclaration getMethodDeclaration; + + private Set qualifiers = new HashSet<>(); + + private MethodDeclaration init; + + public CompilationUnit build() { + initClass(); + addFields(); + initInitMethod(); + addGetInstanceMethod(); + + for (Expression qualifier : qualifiers) { + init.getBody().ifPresent(body -> body.addAndGetStatement(qualifier)); + + } + + return clazz; + } + + private void initClass() { + clazz.setPackageDeclaration(BeanManager.class.getPackage().getName()); + classDeclaration = clazz.addClass(BeanManager.class.getSimpleName() + "Impl"); + clazz.addImport(Provider.class); + clazz.addImport(Map.class); + clazz.addImport(HashMap.class); + clazz.addImport(Annotation.class); + clazz.addImport(Instance.class); + clazz.addImport(InstanceImpl.class); + clazz.addImport(BeanManager.class); + clazz.addImport(SyncBeanDefImpl.class); + clazz.addImport(BeanFactory.class); + clazz.addImport(QualifierUtil.class); + clazz.addImport("io.crysknife.client.internal.QualifierUtil.DEFAULT_ANNOTATION", true, false); + clazz.addImport("io.crysknife.client.internal.QualifierUtil.SPECIALIZES_ANNOTATION", true, + false); + clazz.addImport("io.crysknife.client.internal.SyncBeanDefImpl.Builder", true, false); + + ClassOrInterfaceType factory = new ClassOrInterfaceType(); + factory.setName("BeanManager"); + + classDeclaration.getExtendedTypes().add(factory); + } + + 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); + + + Set processed = new HashSet<>(); + + iocContext.getOrderedBeans().stream() + .filter( + field -> (MoreTypes.asTypeElement(field).getAnnotation(Application.class) == null)) + .forEach(bean -> { + TypeMirror erased = iocContext.getGenerationContext().getTypes().erasure(bean); + + if (!processed.contains(bean) && !iocContext.getBuildIn().contains(erased.toString())) { + processed.add(bean); + BeanDefinition beanDefinition = iocContext.getBean(erased); + + if (beanDefinition instanceof ProducesBeanDefinition) { + addProducesBeanDefinition((ProducesBeanDefinition) beanDefinition); + } else { + + if (isSuitableBeanDefinition(beanDefinition)) { + Annotation scope = beanDefinition.getScope(); + List assignableTypes = new ArrayList<>(); + assignableTypes.add(erased); + + Utils.getSuperTypes(iocContext.getGenerationContext().getElements(), + MoreTypes.asTypeElement(erased)).forEach(spr -> { + if (!iocContext.getGenerationContext().getTypes().isSameType(spr.asType(), + OBJECT)) { + assignableTypes.add( + iocContext.getGenerationContext().getTypes().erasure(spr.asType())); + } + }); + + List qualifiers = new ArrayList<>(); + + + Utils.getAllElementQualifierAnnotations(iocContext, MoreTypes.asElement(erased)) + .forEach(anno -> qualifiers.add(anno)); + Set qualifiersExpression = new HashSet<>(); + + qualifiers + .forEach(type -> qualifiersExpression.add(createQualifierExpression(type))); + + if (MoreTypes.asTypeElement(bean).getAnnotation(Named.class) != 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); + } + builderCallExpr = new MethodCallExpr(builderCallExpr, "withFactory").addArgument( + new ObjectCreationExpr().setType(Utils.getQualifiedFactoryName(erased)) + .addArgument(new ThisExpr())); + + builderCallExpr = new MethodCallExpr(builderCallExpr, "build"); + registerCallExpr.addArgument(builderCallExpr); + init.getBody().get().addAndGetStatement(registerCallExpr); + + } + } + } + }); + } + + private Expression createQualifierExpression(AnnotationMirror qualifier) { + + ObjectCreationExpr annotation = new ObjectCreationExpr(); + annotation + .setType(new ClassOrInterfaceType().setName(qualifier.getAnnotationType().toString())); + + NodeList> anonymousClassBody = new NodeList<>(); + + MethodDeclaration annotationType = new MethodDeclaration(); + annotationType.setModifiers(Modifier.Keyword.PUBLIC); + annotationType.setName("annotationType"); + annotationType.setType(new ClassOrInterfaceType().setName("Class")); + annotationType.getBody().get().addAndGetStatement( + new ReturnStmt(new NameExpr(qualifier.getAnnotationType().toString() + ".class"))); + anonymousClassBody.add(annotationType); + + annotation.setAnonymousClassBody(anonymousClassBody); + + return annotation; + } + + private boolean isSuitableBeanDefinition(BeanDefinition beanDefinition) { + return MoreTypes.asTypeElement(beanDefinition.getType()).getKind().isClass() + && !MoreTypes.asTypeElement(beanDefinition.getType()).getModifiers().contains(ABSTRACT) + && beanDefinition.getIocGenerator().isPresent(); + } + + private void addProducesBeanDefinition(ProducesBeanDefinition beanDefinition) { + ProducesBeanDefinition producesBeanDefinition = beanDefinition; + + TypeMirror erased = + iocContext.getGenerationContext().getTypes().erasure(producesBeanDefinition.getType()); + + Annotation scope = producesBeanDefinition.getScope(); + List assignableTypes = new ArrayList<>(); + assignableTypes.add(erased); + + Utils.getSuperTypes(iocContext.getGenerationContext().getElements(), + MoreTypes.asTypeElement(erased)).forEach(spr -> { + if (!iocContext.getGenerationContext().getTypes().isSameType(spr.asType(), OBJECT)) { + assignableTypes + .add(iocContext.getGenerationContext().getTypes().erasure(spr.asType())); + } + }); + + ArrayInitializerExpr withAssignableTypesValues = new ArrayInitializerExpr(); + 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); + + + ClassOrInterfaceType producerType = new ClassOrInterfaceType(); + producerType.setName(ProducesBeanFactory.class.getCanonicalName()) + .setTypeArguments(new ClassOrInterfaceType().setName(erased.toString())); + + ClassOrInterfaceType supplierType = + new ClassOrInterfaceType().setName(Supplier.class.getCanonicalName()) + .setTypeArguments(new ClassOrInterfaceType().setName(erased.toString())); + + + ObjectCreationExpr supplier = new ObjectCreationExpr().setType(supplierType); + + NodeList> supplierClassBody = new NodeList<>(); + + MethodDeclaration annotationType = new MethodDeclaration(); + annotationType.setModifiers(Modifier.Keyword.PUBLIC); + 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); + + 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); + + + + /* + **************************** + */ + + String qualifiedName = MoreTypes.asTypeElement( + iocContext.getGenerationContext().getTypes().erasure(producesBeanDefinition.getType())) + .getQualifiedName().toString(); + + + ObjectCreationExpr newInstance = new ObjectCreationExpr(); + newInstance.setType(new ClassOrInterfaceType().setName(InstanceImpl.class.getSimpleName())); + + ObjectCreationExpr provider = new ObjectCreationExpr(); + provider.setType(new ClassOrInterfaceType().setName(Provider.class.getSimpleName())); + + newInstance.addArgument(provider); + + NodeList> anonymousClassBody = new NodeList<>(); + + MethodDeclaration get = new MethodDeclaration(); + get.setModifiers(Modifier.Keyword.PUBLIC); + get.addAnnotation(Override.class); + get.setName("get"); + get.setType(new ClassOrInterfaceType().setName(qualifiedName)); + + String producerClass = producesBeanDefinition.getProducer().toString(); + + ClassOrInterfaceType instance = + new ClassOrInterfaceType().setName(Instance.class.getSimpleName()); + instance.setTypeArguments(new ClassOrInterfaceType().setName(producerClass)); + + Expression getNewInstance; + + if (producesBeanDefinition.getMethod().getModifiers() + .contains(javax.lang.model.element.Modifier.STATIC)) { + getNewInstance = new MethodCallExpr( + new NameExpr(Utils.getQualifiedName(producesBeanDefinition.getProducer())), + producesBeanDefinition.getMethod().getSimpleName().toString()); + } else { + getNewInstance = new MethodCallExpr(new EnclosedExpr(new CastExpr( + new ClassOrInterfaceType().setName(producerClass), + new MethodCallExpr( + new MethodCallExpr("lookupBean").addArgument(producerClass + ".class"), "get"))), + producesBeanDefinition.getMethod().getSimpleName().toString()); + } + + if (producesBeanDefinition.isSingleton()) { + + IfStmt ifStmt = new IfStmt().setCondition(new BinaryExpr(new NameExpr("holder"), + new NullLiteralExpr(), BinaryExpr.Operator.EQUALS)); + BlockStmt blockStmt = new BlockStmt(); + + blockStmt.addAndGetStatement( + new AssignExpr().setTarget(new NameExpr("holder")).setValue(getNewInstance)); + + ifStmt.setThenStmt(blockStmt); + get.getBody().get().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"))); + } else { + get.getBody().get().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("javax.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 addGetInstanceMethod() { + getMethodDeclaration = + classDeclaration.addMethod("get", Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC); + getMethodDeclaration.setType(BeanManager.class.getSimpleName()); + addGetBody(); + } + + private void addGetBody() { + NameExpr instance = new NameExpr("instance"); + IfStmt ifStmt = new IfStmt().setCondition( + new BinaryExpr(instance, new NullLiteralExpr(), BinaryExpr.Operator.EQUALS)); + BlockStmt blockStmt = new BlockStmt(); + blockStmt.addAndGetStatement(generateInstanceInitializer()); + blockStmt.addAndGetStatement(new MethodCallExpr(instance, "init")); + ifStmt.setThenStmt(blockStmt); + getMethodDeclaration.getBody().ifPresent(body -> body.addAndGetStatement(ifStmt)); + + getMethodDeclaration.getBody() + .ifPresent(body -> body.getStatements().add(new ReturnStmt(instance))); + } + + protected Expression generateInstanceInitializer() { + ObjectCreationExpr newInstance = new ObjectCreationExpr(); + newInstance + .setType(new ClassOrInterfaceType().setName(BeanManager.class.getSimpleName() + "Impl")); + return new AssignExpr().setTarget(new NameExpr("instance")).setValue(newInstance); + } + } +} diff --git a/processor/src/main/java/io/crysknife/generator/BeanManagerProducerGenerator.java b/processor/src/main/java/io/crysknife/generator/BeanManagerProducerGenerator.java index 68950132..376c305c 100644 --- a/processor/src/main/java/io/crysknife/generator/BeanManagerProducerGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/BeanManagerProducerGenerator.java @@ -23,7 +23,7 @@ import io.crysknife.client.BeanManager; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; +import io.crysknife.definition.BeanDefinition; /** * @author Dmitrii Tikhomirov Created by treblereel 3/30/19 diff --git a/processor/src/main/java/io/crysknife/generator/BootstrapperGenerator.java b/processor/src/main/java/io/crysknife/generator/BootstrapperGenerator.java index ceb1084f..61146283 100644 --- a/processor/src/main/java/io/crysknife/generator/BootstrapperGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/BootstrapperGenerator.java @@ -14,35 +14,43 @@ package io.crysknife.generator; -import java.io.IOException; - -import javax.inject.Provider; - import com.github.javaparser.ast.Modifier; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.expr.AssignExpr; +import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.FieldAccessExpr; +import com.github.javaparser.ast.expr.LambdaExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.github.javaparser.ast.expr.ThisExpr; +import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.google.auto.common.MoreTypes; import io.crysknife.annotation.Application; import io.crysknife.annotation.Generator; -import io.crysknife.client.Instance; +import io.crysknife.client.BeanManager; +import io.crysknife.client.InstanceFactory; import io.crysknife.client.Interceptor; import io.crysknife.client.Reflect; +import io.crysknife.client.SyncBeanDef; +import io.crysknife.client.internal.BeanFactory; import io.crysknife.client.internal.Factory; import io.crysknife.client.internal.OnFieldAccessed; -import io.crysknife.exception.GenerationException; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.Definition; +import io.crysknife.definition.InjectableVariableDefinition; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.GenerationContext; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.Definition; import io.crysknife.util.Utils; +import javax.enterprise.inject.Instance; +import javax.inject.Provider; +import java.io.IOException; +import java.util.function.Supplier; + /** * @author Dmitrii Tikhomirov Created by treblereel 4/5/19 */ @@ -61,25 +69,42 @@ public void register() { } @Override - public void generateBeanFactory(ClassBuilder clazz, Definition definition) { - super.generateBeanFactory(clazz, definition); + public void generate(ClassBuilder clazz, BeanDefinition definition) { + super.generate(clazz, definition); } @Override public void initClassBuilder(ClassBuilder clazz, BeanDefinition beanDefinition) { - clazz.getClassCompilationUnit().setPackageDeclaration(beanDefinition.getPackageName()); - clazz.getClassCompilationUnit().addImport(beanDefinition.getQualifiedName()); + String pkg = Utils.getPackageName(MoreTypes.asTypeElement(beanDefinition.getType())); + + clazz.getClassCompilationUnit().setPackageDeclaration(pkg); if (!iocContext.getGenerationContext().isGwt2()) { clazz.getClassCompilationUnit().addImport(OnFieldAccessed.class); clazz.getClassCompilationUnit().addImport(Reflect.class); - clazz.getClassCompilationUnit().addImport(Factory.class); + clazz.getClassCompilationUnit().addImport(SyncBeanDef.class); + clazz.getClassCompilationUnit().addImport(BeanFactory.class); + clazz.getClassCompilationUnit().addImport(Supplier.class); clazz.getClassCompilationUnit().addImport(Provider.class); + clazz.getClassCompilationUnit().addImport(BeanManager.class); + clazz.getClassCompilationUnit().addImport(InstanceFactory.class); } - clazz.setClassName(beanDefinition.getType().getSimpleName().toString() + BOOTSTRAP_EXTENSION); + clazz.setClassName(MoreTypes.asTypeElement(beanDefinition.getType()).getSimpleName().toString() + + BOOTSTRAP_EXTENSION); + + clazz.addField(MoreTypes.asTypeElement(beanDefinition.getType()).getQualifiedName().toString(), + "instance", Modifier.Keyword.PRIVATE); + + clazz.addFieldWithInitializer(BeanManager.class.getSimpleName(), "beanManager", + new MethodCallExpr(new NameExpr(BeanManager.class.getCanonicalName() + "Impl"), "get"), + Modifier.Keyword.PRIVATE, Modifier.Keyword.FINAL); + + } + + @Override + public void generateNewInstanceMethodBuilder(ClassBuilder classBuilder) { - clazz.addField(beanDefinition.getClassName(), "instance", Modifier.Keyword.PRIVATE); } @Override @@ -102,11 +127,15 @@ public void generateInstanceGetMethodBuilder(ClassBuilder classBuilder, .addAndGetStatement(new AssignExpr().setTarget(new NameExpr("instance")) .setValue(new MethodCallExpr(new NameExpr("interceptor"), "getProxy"))); } + if (!iocContext.getGenerationContext().isJre()) { - beanDefinition.getFieldInjectionPoints() - .forEach(fieldPoint -> classBuilder.getGetMethodDeclaration().getBody().get() - .addStatement(getFieldAccessorExpression(classBuilder, beanDefinition, fieldPoint))); + for (InjectableVariableDefinition fieldPoint : beanDefinition.getFields()) { + classBuilder.getGetMethodDeclaration().getBody().get().addStatement( + getFieldAccessorExpression(classBuilder, beanDefinition, fieldPoint, "field")); + } } + + getMethodDeclaration.getBody().get().addAndGetStatement(new MethodCallExpr("doInitInstance")); } @Override @@ -115,13 +144,10 @@ public void generateDependantFieldDeclaration(ClassBuilder classBuilder, classBuilder.addConstructorDeclaration(); Parameter arg = new Parameter(); arg.setName("application"); - arg.setType(beanDefinition.getType().getSimpleName().toString()); + arg.setType(MoreTypes.asTypeElement(beanDefinition.getType()).getSimpleName().toString()); classBuilder.addParametersToConstructor(arg); - beanDefinition.getFieldInjectionPoints().forEach(fieldPoint -> iocContext.getBeans() - .get(fieldPoint.getType()).generateBeanCall(iocContext, classBuilder, fieldPoint)); - AssignExpr assign = new AssignExpr().setTarget(new FieldAccessExpr(new ThisExpr(), "instance")) .setValue(new NameExpr("application")); classBuilder.addStatementToConstructor(assign); @@ -133,30 +159,15 @@ public void generateInstanceGetMethodReturn(ClassBuilder classBuilder, } - @Override - public void generateFactoryCreateMethod(ClassBuilder classBuilder, - BeanDefinition beanDefinition) { - - } - - protected void generateFactoryFieldDeclaration(ClassBuilder classBuilder, - BeanDefinition beanDefinition) { - String varName = Utils.toVariableName(beanDefinition.getQualifiedName()); - ClassOrInterfaceType type = new ClassOrInterfaceType(); - type.setName(Instance.class.getCanonicalName()); - type.setTypeArguments(new ClassOrInterfaceType().setName(beanDefinition.getQualifiedName())); - - classBuilder.addField(type, varName, Modifier.Keyword.FINAL, Modifier.Keyword.PRIVATE); - } - @Override public void write(ClassBuilder clazz, BeanDefinition beanDefinition, GenerationContext context) { try { - String fileName = Utils.getQualifiedName(beanDefinition.getType()) + BOOTSTRAP_EXTENSION; + String fileName = Utils.getQualifiedName(MoreTypes.asElement(beanDefinition.getType())) + + BOOTSTRAP_EXTENSION; String source = clazz.toSourceCode(); build(fileName, source, context); } catch (IOException e1) { - throw new GenerationException(e1); + // throw new GenerationException(e1); } } } diff --git a/processor/src/main/java/io/crysknife/generator/DependentGenerator.java b/processor/src/main/java/io/crysknife/generator/DependentGenerator.java index c7a25739..dc6162af 100644 --- a/processor/src/main/java/io/crysknife/generator/DependentGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/DependentGenerator.java @@ -20,12 +20,13 @@ import io.crysknife.annotation.Generator; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.util.Utils; /** * @author Dmitrii Tikhomirov Created by treblereel 3/2/19 */ -@Generator(priority = 2) +@Generator(priority = 1) public class DependentGenerator extends ScopedBeanGenerator { public DependentGenerator(IOCContext iocContext) { @@ -41,8 +42,6 @@ public void register() { public void generateInstanceGetMethodBuilder(ClassBuilder builder, BeanDefinition beanDefinition) { super.generateInstanceGetMethodBuilder(builder, beanDefinition); - builder.addField(beanDefinition.getClassName(), "instance", Modifier.Keyword.PRIVATE); - builder.getGetMethodDeclaration().getBody().get() .addAndGetStatement(generateInstanceInitializer(builder, beanDefinition)); } diff --git a/processor/src/main/java/io/crysknife/generator/EventProducerGenerator.java b/processor/src/main/java/io/crysknife/generator/EventProducerGenerator.java index 53983123..c2d9eb30 100644 --- a/processor/src/main/java/io/crysknife/generator/EventProducerGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/EventProducerGenerator.java @@ -14,33 +14,34 @@ package io.crysknife.generator; -import javax.enterprise.event.Event; -import javax.inject.Inject; -import javax.lang.model.element.TypeElement; - import com.github.javaparser.ast.Modifier; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.expr.AssignExpr; import com.github.javaparser.ast.expr.BinaryExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.FieldAccessExpr; +import com.github.javaparser.ast.expr.LambdaExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.expr.NullLiteralExpr; import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.github.javaparser.ast.expr.ThisExpr; import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.stmt.IfStmt; import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.google.auto.common.MoreTypes; import io.crysknife.annotation.Generator; +import io.crysknife.client.internal.InstanceImpl; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.Definition; +import io.crysknife.definition.InjectableVariableDefinition; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.point.FieldPoint; -import io.crysknife.util.Utils; + +import javax.enterprise.event.Event; +import javax.inject.Inject; /** * @author Dmitrii Tikhomirov Created by treblereel 3/31/19 @@ -54,22 +55,28 @@ public EventProducerGenerator(IOCContext iocContext) { @Override public void register() { - iocContext.register(Inject.class, Event.class, WiringElementType.BEAN, this); - iocContext.getBlacklist().add(Event.class.getCanonicalName()); + iocContext.register(Inject.class, Event.class, WiringElementType.FIELD_TYPE, this); + } + + @Override + public Expression generateBeanLookupCall(ClassBuilder classBuilder, + InjectableVariableDefinition fieldPoint) { + classBuilder.getClassCompilationUnit().addImport("javax.enterprise.event.Event_Factory"); + classBuilder.getClassCompilationUnit().addImport(InstanceImpl.class.getCanonicalName()); + MoreTypes.asDeclared(fieldPoint.getVariableElement().asType()).getTypeArguments(); - TypeElement type = iocContext.getGenerationContext().getElements() - .getTypeElement(Event.class.getCanonicalName()); - BeanDefinition beanDefinition = iocContext.getBeanDefinitionOrCreateAndReturn(type); - beanDefinition.setGenerator(this); - iocContext.getBeans().put(type, beanDefinition); + return new ObjectCreationExpr().setType(InstanceImpl.class) + .addArgument(new NameExpr("Event_Factory.get().get(" + MoreTypes + .asDeclared(fieldPoint.getVariableElement().asType()).getTypeArguments().get(0) + + ".class)")); } @Override - public void generateBeanFactory(ClassBuilder clazz, Definition definition) { + public void generate(ClassBuilder clazz, Definition definition) { if (definition instanceof BeanDefinition) { BeanDefinition beanDefinition = (BeanDefinition) definition; initClassBuilder(clazz, beanDefinition); - generateFactoryCreateMethod(clazz, beanDefinition); + generateBeanGetMethod(clazz, beanDefinition); write(clazz, beanDefinition, iocContext.getGenerationContext()); } } @@ -77,7 +84,8 @@ public void generateBeanFactory(ClassBuilder clazz, Definition definition) { @Override public void initClassBuilder(ClassBuilder clazz, BeanDefinition beanDefinition) { clazz.getClassCompilationUnit().setPackageDeclaration(beanDefinition.getPackageName()); - clazz.setClassName(beanDefinition.getClassFactoryName()); + clazz.setClassName( + MoreTypes.asTypeElement(beanDefinition.getType()).getSimpleName().toString() + "_Factory"); clazz.getClassCompilationUnit().addImport("io.crysknife.client.internal.AbstractEventFactory"); ClassOrInterfaceType factory = new ClassOrInterfaceType(); @@ -85,33 +93,7 @@ public void initClassBuilder(ClassBuilder clazz, BeanDefinition beanDefinition) clazz.getExtendedTypes().add(factory); } - @Override - public Expression generateBeanCall(ClassBuilder classBuilder, FieldPoint fieldPoint, - BeanDefinition beanDefinition) { - classBuilder.getClassCompilationUnit().addImport("javax.enterprise.event.Event_Factory"); - MoreTypes.asDeclared(fieldPoint.getField().asType()).getTypeArguments(); - - return new NameExpr("Event_Factory.get().get(" - + MoreTypes.asDeclared(fieldPoint.getField().asType()).getTypeArguments().get(0) - + ".class)"); - } - - @Override - public void addFactoryFieldInitialization(ClassBuilder classBuilder, - BeanDefinition beanDefinition) { - classBuilder.getClassCompilationUnit().addImport("javax.enterprise.event.Event_Factory"); - String varName = Utils.toVariableName(beanDefinition.getQualifiedName()); - MethodCallExpr callForBeanManagerImpl = - new MethodCallExpr(new NameExpr("Event_Factory").getNameAsExpression(), "get"); - ThisExpr clazz = new ThisExpr(); - FieldAccessExpr field = new FieldAccessExpr(clazz, varName); - AssignExpr assign = new AssignExpr().setTarget(field).setValue(callForBeanManagerImpl); - classBuilder.addStatementToConstructor(assign); - } - - @Override - public void generateFactoryCreateMethod(ClassBuilder classBuilder, - BeanDefinition beanDefinition) { + public void generateBeanGetMethod(ClassBuilder classBuilder, BeanDefinition beanDefinition) { MethodDeclaration getMethodDeclaration = classBuilder.addMethod("get", Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC); getMethodDeclaration.setType("Event_Factory"); diff --git a/processor/src/main/java/io/crysknife/generator/FactoryGenerator.java b/processor/src/main/java/io/crysknife/generator/FactoryGenerator.java new file mode 100644 index 00000000..d256d900 --- /dev/null +++ b/processor/src/main/java/io/crysknife/generator/FactoryGenerator.java @@ -0,0 +1,77 @@ +/* + * 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.generator; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import javax.lang.model.type.TypeMirror; + +import com.google.auto.common.MoreTypes; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.api.ClassBuilder; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.ProducesBeanDefinition; +import io.crysknife.generator.context.oracle.BeanOracle; +import io.crysknife.task.Task; + +import static javax.lang.model.element.Modifier.ABSTRACT; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 2/20/19 + */ +public class FactoryGenerator implements Task { + + private final IOCContext iocContext; + private final BeanOracle oracle; + + public FactoryGenerator(IOCContext iocContext) { + this.iocContext = iocContext; + this.oracle = new BeanOracle(iocContext); + } + + public void execute() throws UnableToCompleteException { + Set processed = new HashSet<>(); + + for (TypeMirror bean : iocContext.getOrderedBeans()) { + TypeMirror erased = iocContext.getGenerationContext().getTypes().erasure(bean); + if (!processed.contains(bean)) { + processed.add(bean); + BeanDefinition beanDefinition = iocContext.getBean(erased); + if (beanDefinition instanceof ProducesBeanDefinition) { + continue; + } + + if (isSuitableBeanDefinition(beanDefinition)) { + new ClassBuilder(beanDefinition).build(); + } else { + Optional maybe = oracle.guessDefaultImpl(erased); + maybe.ifPresent(candidate -> new ClassBuilder(candidate).build()); + } + } + } + } + + private boolean isSuitableBeanDefinition(BeanDefinition beanDefinition) { + if (beanDefinition.getIocGenerator().isPresent()) { + return true; + } + return MoreTypes.asTypeElement(beanDefinition.getType()).getKind().isClass() + && !MoreTypes.asTypeElement(beanDefinition.getType()).getModifiers().contains(ABSTRACT); + } + +} diff --git a/processor/src/main/java/io/crysknife/generator/IOCGenerator.java b/processor/src/main/java/io/crysknife/generator/IOCGenerator.java index e8eca4fa..de690f4a 100644 --- a/processor/src/main/java/io/crysknife/generator/IOCGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/IOCGenerator.java @@ -14,24 +14,54 @@ package io.crysknife.generator; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.FieldAccessExpr; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.NameExpr; +import com.google.auto.common.MoreTypes; +import io.crysknife.definition.InjectableVariableDefinition; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.Definition; +import io.crysknife.definition.Definition; +import io.crysknife.util.GenerationUtils; + +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeParameterElement; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import java.util.List; /** * @author Dmitrii Tikhomirov Created by treblereel 3/2/19 */ -public abstract class IOCGenerator { +public abstract class IOCGenerator { protected final IOCContext iocContext; + protected final GenerationUtils generationUtils; + + protected final Types types; + protected final Elements elements; + public IOCGenerator(IOCContext iocContext) { this.iocContext = iocContext; + this.generationUtils = new GenerationUtils(iocContext); + + types = iocContext.getGenerationContext().getTypes(); + elements = iocContext.getGenerationContext().getElements(); } public abstract void register(); - public abstract void generateBeanFactory(ClassBuilder clazz, Definition beanDefinition); + public abstract void generate(ClassBuilder clazz, T beanDefinition); + + public Expression generateBeanLookupCall(ClassBuilder clazz, + InjectableVariableDefinition fieldPoint) { + String typeQualifiedName = generationUtils.getActualQualifiedBeanName(fieldPoint); + MethodCallExpr callForProducer = new MethodCallExpr(new NameExpr("beanManager"), "lookupBean") + .addArgument(new FieldAccessExpr(new NameExpr(typeQualifiedName), "class")); + return callForProducer; + } public void before() { diff --git a/processor/src/main/java/io/crysknife/generator/ManagedInstanceGenerator.java b/processor/src/main/java/io/crysknife/generator/ManagedInstanceGenerator.java index f80679cd..bff26f7c 100644 --- a/processor/src/main/java/io/crysknife/generator/ManagedInstanceGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/ManagedInstanceGenerator.java @@ -14,20 +14,22 @@ package io.crysknife.generator; -import javax.inject.Inject; -import javax.lang.model.type.TypeMirror; - import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.google.auto.common.MoreTypes; import io.crysknife.annotation.Generator; import io.crysknife.client.ManagedInstance; import io.crysknife.client.internal.InstanceImpl; +import io.crysknife.client.internal.ManagedInstanceImpl; +import io.crysknife.definition.InjectableVariableDefinition; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.point.FieldPoint; + +import javax.enterprise.inject.Instance; +import javax.inject.Inject; +import javax.lang.model.type.TypeMirror; /** * @author Dmitrii Tikhomirov Created by treblereel 4/27/21 @@ -35,33 +37,68 @@ @Generator public class ManagedInstanceGenerator extends BeanIOCGenerator { + private final TypeMirror instanceTypeMirror; + private final TypeMirror managedInstanceTypeMirror; + public ManagedInstanceGenerator(IOCContext iocContext) { super(iocContext); + instanceTypeMirror = iocContext.getGenerationContext().getTypes() + .erasure(iocContext.getTypeMirror(Instance.class.getCanonicalName())); + managedInstanceTypeMirror = iocContext.getGenerationContext().getTypes() + .erasure(iocContext.getTypeMirror(ManagedInstance.class.getCanonicalName())); + } @Override - public Expression generateBeanCall(ClassBuilder clazz, FieldPoint fieldPoint, - BeanDefinition beanDefinition) { - - TypeMirror param = - MoreTypes.asDeclared(fieldPoint.getField().asType()).getTypeArguments().get(0); - - // new InstanceImpl>(new - // io.crysknife.client.internal.ManagedInstanceImpl(org.treblereel.injection.managedinstance.ComponentIface.class, - // io.crysknife.client.BeanManagerImpl.get()));; + public void register() { + iocContext.register(Inject.class, ManagedInstance.class, WiringElementType.FIELD_TYPE, this); + iocContext.register(Inject.class, Instance.class, WiringElementType.FIELD_TYPE, this); + } - StringBuffer sb = new StringBuffer(); - sb.append("new ").append("io.crysknife.client.internal.ManagedInstanceImpl"); - sb.append("(").append(param.toString()).append(".class").append(", "); - sb.append("io.crysknife.client.BeanManagerImpl.get()"); - sb.append(")"); + @Override + public void generate(ClassBuilder clazz, io.crysknife.definition.Definition beanDefinition) { - return new NameExpr(sb.toString()); } @Override - public void register() { - iocContext.register(Inject.class, ManagedInstance.class, WiringElementType.FIELD_TYPE, this); - iocContext.getBlacklist().add(ManagedInstance.class.getCanonicalName()); + public Expression generateBeanLookupCall(ClassBuilder clazz, + InjectableVariableDefinition fieldPoint) { + + clazz.getClassCompilationUnit().addImport(ManagedInstance.class); + clazz.getClassCompilationUnit().addImport(ManagedInstanceImpl.class); + clazz.getClassCompilationUnit().addImport(InstanceImpl.class); + + TypeMirror erased = iocContext.getGenerationContext().getTypes() + .erasure(fieldPoint.getVariableElement().asType()); + Expression result; + + if (iocContext.getGenerationContext().getTypes().isSameType(instanceTypeMirror, erased)) { + TypeMirror param = + MoreTypes.asDeclared(fieldPoint.getVariableElement().asType()).getTypeArguments().get(0); + + ObjectCreationExpr instance = new ObjectCreationExpr().setType(InstanceImpl.class) + .addArgument(new MethodCallExpr(new NameExpr("beanManager"), "lookupBean").addArgument( + new NameExpr(iocContext.getGenerationContext().getTypes().erasure(param).toString() + + ".class"))); + + result = instance; + } else { + + TypeMirror param = + MoreTypes.asDeclared(fieldPoint.getVariableElement().asType()).getTypeArguments().get(0); + + ObjectCreationExpr instance = new ObjectCreationExpr().setType(ManagedInstanceImpl.class) + .addArgument(new NameExpr("beanManager")).addArgument(new NameExpr( + iocContext.getGenerationContext().getTypes().erasure(param).toString() + ".class")); + + result = instance; + } + + + ObjectCreationExpr rtrn = + new ObjectCreationExpr().setType(InstanceImpl.class).addArgument(result); + + return rtrn; } + } diff --git a/processor/src/main/java/io/crysknife/generator/ObservesGenerator.java b/processor/src/main/java/io/crysknife/generator/ObservesGenerator.java index 806d71e4..f101a79f 100644 --- a/processor/src/main/java/io/crysknife/generator/ObservesGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/ObservesGenerator.java @@ -14,12 +14,6 @@ package io.crysknife.generator; -import java.util.function.Consumer; - -import javax.enterprise.event.Observes; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.VariableElement; - import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.body.VariableDeclarator; import com.github.javaparser.ast.expr.CastExpr; @@ -31,17 +25,21 @@ import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.type.ClassOrInterfaceType; import io.crysknife.annotation.Generator; +import io.crysknife.definition.MethodDefinition; import io.crysknife.exception.GenerationException; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.definition.ExecutableDefinition; + +import javax.enterprise.event.Observes; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import java.util.function.Consumer; /** * @author Dmitrii Tikhomirov Created by treblereel 4/5/19 */ @Generator(priority = 1000) -public class ObservesGenerator extends IOCGenerator { +public class ObservesGenerator extends IOCGenerator { public ObservesGenerator(IOCContext iocContext) { super(iocContext); @@ -53,55 +51,51 @@ public void register() { } @Override - public void generateBeanFactory(ClassBuilder classBuilder, Definition definition) { - if (definition instanceof ExecutableDefinition) { - ExecutableDefinition methodDefinition = (ExecutableDefinition) definition; - - ExecutableElement method = methodDefinition.getExecutableElement(); - if (method.getParameters().size() > 1) { - throw new GenerationException( - "Method annotated with @Observes must contains only one param " - + method.getEnclosingElement() + " " + method); - } - - classBuilder.getClassCompilationUnit().addImport(Consumer.class); - - VariableElement parameter = method.getParameters().get(0); - classBuilder.getClassCompilationUnit().addImport("javax.enterprise.event.Event_Factory"); - MethodCallExpr eventFactory = - new MethodCallExpr(new NameExpr("Event_Factory").getNameAsExpression(), "get"); - MethodCallExpr getEventHandler = new MethodCallExpr(eventFactory, "get") - .addArgument(new FieldAccessExpr(new NameExpr(parameter.asType().toString()), "class")); - - Parameter argument = new Parameter(); - argument.setName("(event)"); - - ExpressionStmt expressionStmt = new ExpressionStmt(); - VariableDeclarationExpr variableDeclarationExpr = new VariableDeclarationExpr(); - - VariableDeclarator variableDeclarator = new VariableDeclarator(); - variableDeclarator.setName(parameter.getEnclosingElement().getSimpleName().toString()); - - ClassOrInterfaceType consumerClassDecloration = - new ClassOrInterfaceType().setName(Consumer.class.getCanonicalName()); - consumerClassDecloration - .setTypeArguments(new ClassOrInterfaceType().setName(parameter.asType().toString())); - variableDeclarator.setType(consumerClassDecloration); - variableDeclarator.setInitializer( - "event -> this.instance." + method.getSimpleName().toString() + "(event)"); - variableDeclarationExpr.getVariables().add(variableDeclarator); - expressionStmt.setExpression(variableDeclarationExpr); - - classBuilder.getGetMethodDeclaration().getBody().get().addAndGetStatement(expressionStmt); - - EnclosedExpr castToAbstractEventHandler = new EnclosedExpr(new CastExpr( - new ClassOrInterfaceType().setName("io.crysknife.client.internal.AbstractEventHandler"), - getEventHandler)); - - MethodCallExpr addSubscriber = new MethodCallExpr(castToAbstractEventHandler, "addSubscriber") - .addArgument(parameter.getEnclosingElement().getSimpleName().toString()); - - classBuilder.getGetMethodDeclaration().getBody().get().addAndGetStatement(addSubscriber); + public void generate(ClassBuilder classBuilder, MethodDefinition methodDefinition) { + ExecutableElement method = methodDefinition.getExecutableElement(); + if (method.getParameters().size() > 1) { + throw new GenerationException("Method annotated with @Observes must contains only one param " + + method.getEnclosingElement() + " " + method); } + + classBuilder.getClassCompilationUnit().addImport(Consumer.class); + + VariableElement parameter = method.getParameters().get(0); + classBuilder.getClassCompilationUnit().addImport("javax.enterprise.event.Event_Factory"); + MethodCallExpr eventFactory = + new MethodCallExpr(new NameExpr("Event_Factory").getNameAsExpression(), "get"); + MethodCallExpr getEventHandler = new MethodCallExpr(eventFactory, "get") + .addArgument(new FieldAccessExpr(new NameExpr(parameter.asType().toString()), "class")); + + Parameter argument = new Parameter(); + argument.setName("(event)"); + + ExpressionStmt expressionStmt = new ExpressionStmt(); + VariableDeclarationExpr variableDeclarationExpr = new VariableDeclarationExpr(); + + VariableDeclarator variableDeclarator = new VariableDeclarator(); + variableDeclarator.setName(parameter.getEnclosingElement().getSimpleName().toString()); + + ClassOrInterfaceType consumerClassDecloration = + new ClassOrInterfaceType().setName(Consumer.class.getCanonicalName()); + consumerClassDecloration + .setTypeArguments(new ClassOrInterfaceType().setName(parameter.asType().toString())); + variableDeclarator.setType(consumerClassDecloration); + variableDeclarator + .setInitializer("event -> this.instance." + method.getSimpleName().toString() + "(event)"); + variableDeclarationExpr.getVariables().add(variableDeclarator); + expressionStmt.setExpression(variableDeclarationExpr); + + classBuilder.getInitInstanceMethod().getBody().get().addAndGetStatement(expressionStmt); + + EnclosedExpr castToAbstractEventHandler = new EnclosedExpr(new CastExpr( + new ClassOrInterfaceType().setName("io.crysknife.client.internal.AbstractEventHandler"), + getEventHandler)); + + MethodCallExpr addSubscriber = new MethodCallExpr(castToAbstractEventHandler, "addSubscriber") + .addArgument(parameter.getEnclosingElement().getSimpleName().toString()); + + classBuilder.getInitInstanceMethod().getBody().get().addAndGetStatement(addSubscriber); } + } diff --git a/processor/src/main/java/io/crysknife/generator/PostConstructGenerator.java b/processor/src/main/java/io/crysknife/generator/PostConstructGenerator.java index 01d75f10..07390560 100644 --- a/processor/src/main/java/io/crysknife/generator/PostConstructGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/PostConstructGenerator.java @@ -14,22 +14,21 @@ package io.crysknife.generator; -import javax.annotation.PostConstruct; - import com.github.javaparser.ast.expr.FieldAccessExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.ThisExpr; import io.crysknife.annotation.Generator; +import io.crysknife.definition.MethodDefinition; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.definition.ExecutableDefinition; + +import javax.annotation.PostConstruct; /** * @author Dmitrii Tikhomirov Created by treblereel 3/3/19 */ -@Generator(priority = 100000) -public class PostConstructGenerator extends IOCGenerator { +@Generator(priority = Integer.MAX_VALUE) +public class PostConstructGenerator extends IOCGenerator { public PostConstructGenerator(IOCContext iocContext) { super(iocContext); @@ -40,13 +39,12 @@ public void register() { iocContext.register(PostConstruct.class, WiringElementType.METHOD_DECORATOR, this); } - public void generateBeanFactory(ClassBuilder builder, Definition definition) { - if (definition instanceof ExecutableDefinition) { - ExecutableDefinition postConstract = (ExecutableDefinition) definition; - FieldAccessExpr instance = new FieldAccessExpr(new ThisExpr(), "instance"); - MethodCallExpr method = new MethodCallExpr(instance, - postConstract.getExecutableElement().getSimpleName().toString()); - builder.getGetMethodDeclaration().getBody().get().addAndGetStatement(method); - } + @Override + public void generate(ClassBuilder clazz, MethodDefinition postConstract) { + FieldAccessExpr instance = new FieldAccessExpr(new ThisExpr(), "instance"); + MethodCallExpr method = new MethodCallExpr(instance, + postConstract.getExecutableElement().getSimpleName().toString()); + clazz.getGetMethodDeclaration().getBody().get().addAndGetStatement(method); + } } diff --git a/processor/src/main/java/io/crysknife/generator/ProducesGenerator.java b/processor/src/main/java/io/crysknife/generator/ProducesGenerator.java index bbed6b54..66f56881 100644 --- a/processor/src/main/java/io/crysknife/generator/ProducesGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/ProducesGenerator.java @@ -14,40 +14,29 @@ package io.crysknife.generator; -import java.util.function.Supplier; - -import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.inject.Produces; -import javax.inject.Singleton; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; - import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.body.ConstructorDeclaration; import com.github.javaparser.ast.expr.AssignExpr; -import com.github.javaparser.ast.expr.BinaryExpr; -import com.github.javaparser.ast.expr.CastExpr; -import com.github.javaparser.ast.expr.EnclosedExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.FieldAccessExpr; import com.github.javaparser.ast.expr.LambdaExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; -import com.github.javaparser.ast.expr.NullLiteralExpr; import com.github.javaparser.ast.expr.ThisExpr; -import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.stmt.ExpressionStmt; -import com.github.javaparser.ast.stmt.IfStmt; -import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.ast.type.ClassOrInterfaceType; -import com.google.auto.common.MoreTypes; +import com.google.auto.common.MoreElements; import io.crysknife.annotation.Generator; -import io.crysknife.client.Instance; +import io.crysknife.client.BeanManager; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.ProducerDefinition; -import io.crysknife.generator.point.FieldPoint; -import io.crysknife.util.Utils; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.ProducesBeanDefinition; + +import javax.enterprise.inject.Instance; +import javax.enterprise.inject.Produces; +import javax.lang.model.element.TypeElement; +import java.util.function.Supplier; /** * @author Dmitrii Tikhomirov Created by treblereel 3/4/19 @@ -63,22 +52,36 @@ public ProducesGenerator(IOCContext iocContext) { @Override public void register() { - iocContext.register(Produces.class, WiringElementType.PRODUCER_ELEMENT, this); + iocContext.register(Produces.class, WiringElementType.METHOD_DECORATOR, this); } - @Override - public void generateDependantFieldDeclaration(ClassBuilder builder, BeanDefinition definition) { - if (definition instanceof ProducerDefinition) { - ProducerDefinition producesDefinition = (ProducerDefinition) definition; + // @Override + public void generateDependantFieldDeclaration2(ClassBuilder builder, BeanDefinition definition) { + if (definition instanceof ProducesBeanDefinition) { + ProducesBeanDefinition producesDefinition = (ProducesBeanDefinition) definition; builder.getClassCompilationUnit().addImport(Instance.class); builder.getClassCompilationUnit().addImport(Supplier.class); builder.getClassCompilationUnit() - .addImport(producesDefinition.getInstance().getQualifiedName().toString()); + .addImport(MoreElements.asType(producesDefinition.getMethod().getEnclosingElement()) + .getQualifiedName().toString()); builder.getClassCompilationUnit() .addImport(producesDefinition.getMethod().getReturnType().toString()); - TypeElement instance = producesDefinition.getInstance(); + + builder.addField(BeanManager.class.getSimpleName(), "beanManager", Modifier.Keyword.PRIVATE, + Modifier.Keyword.FINAL); + + ConstructorDeclaration constructorDeclaration = + builder.addConstructorDeclaration(Modifier.Keyword.PUBLIC); + constructorDeclaration.addAndGetParameter(BeanManager.class, "beanManager"); + + constructorDeclaration.getBody().addAndGetStatement( + new AssignExpr().setTarget(new FieldAccessExpr(new ThisExpr(), "beanManager")) + .setValue(new NameExpr("beanManager"))); + + TypeElement instance = + MoreElements.asType(producesDefinition.getMethod().getEnclosingElement()); Expression call = getBeanManagerCallExpr(instance); @@ -87,8 +90,7 @@ public void generateDependantFieldDeclaration(ClassBuilder builder, BeanDefiniti ClassOrInterfaceType type = new ClassOrInterfaceType(); type.setName(Instance.class.getSimpleName()); - type.setTypeArguments( - new ClassOrInterfaceType().setName(definition.getType().getQualifiedName().toString())); + type.setTypeArguments(new ClassOrInterfaceType().setName(instance.toString())); supplier.setTypeArguments(type); builder.addFieldWithInitializer(supplier, "producer", call, Modifier.Keyword.PRIVATE, @@ -107,57 +109,4 @@ private Expression getBeanManagerCallExpr(TypeElement instance) { return lambda; } - @Override - public void generateInstanceGetMethodReturn(ClassBuilder builder, BeanDefinition definition) { - if (definition instanceof ProducerDefinition) { - ExecutableElement method = ((ProducerDefinition) definition).getMethod(); - if (isSingleton(method)) { - builder.addField(MoreTypes.asTypeElement(method.getReturnType()).getSimpleName().toString(), - "holder", Modifier.Keyword.PRIVATE); - - IfStmt ifStmt = - new IfStmt().setCondition(new BinaryExpr(new FieldAccessExpr(new ThisExpr(), "holder"), - new NullLiteralExpr(), BinaryExpr.Operator.EQUALS)); - - ifStmt.setThenStmt(new BlockStmt().addAndGetStatement( - new AssignExpr().setTarget(new FieldAccessExpr(new ThisExpr(), "holder")) - .setValue(getMethodCallExpr((ProducerDefinition) definition)))); - - builder.getGetMethodDeclaration().getBody().get().addAndGetStatement(ifStmt); - - builder.getGetMethodDeclaration().getBody().get() - .addAndGetStatement(new ReturnStmt(new FieldAccessExpr(new ThisExpr(), "holder"))); - } else { - builder.getGetMethodDeclaration().getBody().ifPresent(body -> body.addAndGetStatement( - new ReturnStmt(getMethodCallExpr((ProducerDefinition) definition)))); - } - } - } - - @Override - public Expression generateBeanCall(ClassBuilder clazz, FieldPoint fieldPoint, - BeanDefinition beanDefinition) { - generateFactoryFieldDeclaration(clazz, fieldPoint); - generateFactoryConstructorDepsBuilder(clazz, beanDefinition); - TypeElement point = fieldPoint.isNamed() - ? iocContext.getQualifiers().get(fieldPoint.getType()).get(fieldPoint.getNamed()).getType() - : fieldPoint.getType(); - return new MethodCallExpr(new MethodCallExpr(new NameExpr(Utils.toVariableName(point)), "get"), - "get"); - } - - private boolean isSingleton(ExecutableElement method) { - return method.getAnnotation(ApplicationScoped.class) != null - || method.getAnnotation(Singleton.class) != null; - } - - private MethodCallExpr getMethodCallExpr(ProducerDefinition definition) { - CastExpr onCast = new CastExpr( - new ClassOrInterfaceType().setName(definition.getInstance().getSimpleName().toString()), - new MethodCallExpr( - new MethodCallExpr(new FieldAccessExpr(new ThisExpr(), "producer"), "get"), "get")); - - return new MethodCallExpr(new EnclosedExpr(onCast), - definition.getMethod().getSimpleName().toString()); - } } diff --git a/processor/src/main/java/io/crysknife/generator/ProxyGenerator.java b/processor/src/main/java/io/crysknife/generator/ProxyGenerator.java new file mode 100644 index 00000000..8e68f56a --- /dev/null +++ b/processor/src/main/java/io/crysknife/generator/ProxyGenerator.java @@ -0,0 +1,305 @@ +/* + * Copyright © 2021 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.generator; + +import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.ConstructorDeclaration; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.expr.AssignExpr; +import com.github.javaparser.ast.expr.BinaryExpr; +import com.github.javaparser.ast.expr.CastExpr; +import com.github.javaparser.ast.expr.EnclosedExpr; +import com.github.javaparser.ast.expr.Expression; +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.NullLiteralExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.ast.expr.ThisExpr; +import com.github.javaparser.ast.expr.VariableDeclarationExpr; +import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.github.javaparser.ast.stmt.IfStmt; +import com.github.javaparser.ast.stmt.ReturnStmt; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.google.auto.common.MoreTypes; +import io.crysknife.annotation.CircularDependency; +import io.crysknife.annotation.Generator; +import io.crysknife.client.Interceptor; +import io.crysknife.client.internal.CircularDependencyProxy; +import io.crysknife.client.internal.ProxyBeanFactory; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.definition.InjectionParameterDefinition; +import io.crysknife.generator.api.ClassBuilder; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.util.Utils; + +import javax.lang.model.element.ExecutableElement; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/30/21 + */ +@Generator +public class ProxyGenerator extends ScopedBeanGenerator { + + private static List OBJECT_METHODS = new ArrayList() { + { + add("wait"); + add("finalize"); + } + }; + private MethodDeclaration initDelegate; + + public ProxyGenerator(IOCContext iocContext) { + super(iocContext); + } + + @Override + public void register() { + iocContext.register(CircularDependency.class, WiringElementType.CLASS_DECORATOR, this); + } + + @Override + public void generate(ClassBuilder builder, BeanDefinition beanDefinition) { + initDelegate(builder, beanDefinition); + + createInstance(builder, beanDefinition); + getInstance(builder, beanDefinition); + setExtendsProxyBeanFactory(builder, beanDefinition); + addDependantBeanReadyMethod(builder, beanDefinition); + addDependantClassHolder(builder, beanDefinition); + generateProxy(builder, beanDefinition); + } + + private void initDelegate(ClassBuilder builder, BeanDefinition beanDefinition) { + initDelegate = builder.addMethod("initDelegate", Modifier.Keyword.PRIVATE); + + + } + + private void getInstance(ClassBuilder builder, BeanDefinition beanDefinition) { + BlockStmt body = new BlockStmt(); + BlockStmt ifBody = new BlockStmt(); + ifBody.addAndGetStatement(new MethodCallExpr("createInstance")); + ifBody.addAndGetStatement(new MethodCallExpr("initDelegate")); + body.addAndGetStatement(new IfStmt().setCondition( + new BinaryExpr(new NameExpr("instance"), new NullLiteralExpr(), BinaryExpr.Operator.EQUALS)) + .setThenStmt(ifBody)); + body.addAndGetStatement(new ReturnStmt(new NameExpr("instance"))); + + + builder.getClassDeclaration().getMethodsByName("getInstance").get(0).setBody(body); + } + + private void createInstance(ClassBuilder builder, BeanDefinition beanDefinition) { + + initDelegate.getBody().ifPresent(body -> { + + if (!(iocContext.getGenerationContext().isGwt2() + || iocContext.getGenerationContext().isJre())) { + ObjectCreationExpr newInstance = generateNewInstanceCreationExpr(beanDefinition); + Set params = beanDefinition.getConstructorParams(); + Iterator injectionPointDefinitionIterator = params.iterator(); + while (injectionPointDefinitionIterator.hasNext()) { + InjectableVariableDefinition argument = injectionPointDefinitionIterator.next(); + newInstance.addArgument( + getFieldAccessorExpression(builder, beanDefinition, argument, "constructor")); + } + FieldAccessExpr interceptor = new FieldAccessExpr(new ThisExpr(), "interceptor"); + + ObjectCreationExpr interceptorCreationExpr = new ObjectCreationExpr(); + interceptorCreationExpr.setType(Interceptor.class.getSimpleName()); + interceptorCreationExpr.addArgument(newInstance); + + body.addAndGetStatement( + new AssignExpr().setTarget(interceptor).setValue(interceptorCreationExpr)); + } + + + + body.addAndGetStatement(new VariableDeclarationExpr(new VariableDeclarator() + .setType(Utils.getSimpleClassName(beanDefinition.getType())).setName("delegate") + .setInitializer(generateInstanceInitializerNewObjectExpr(builder, beanDefinition)))); + + body.addAndGetStatement(new MethodCallExpr(new EnclosedExpr(new CastExpr( + new ClassOrInterfaceType() + .setName("Proxy" + Utils.getSimpleClassName(beanDefinition.getType())), + new NameExpr("instance"))), "setInstance").addArgument("delegate")); + + body.addAndGetStatement(new MethodCallExpr("doInitInstance")); + if (!iocContext.getGenerationContext().isJre()) { + beanDefinition.getFields().forEach(fieldPoint -> { + Expression expr = + getFieldAccessorExpression(builder, beanDefinition, fieldPoint, "field"); + body.addStatement(expr); + }); + } + }); + + BlockStmt body = new BlockStmt(); + + FieldAccessExpr instance = new FieldAccessExpr(new ThisExpr(), "instance"); + AssignExpr assignExpr = new AssignExpr().setTarget(instance); + assignExpr.setValue(new ObjectCreationExpr() + .setType("Proxy" + Utils.getSimpleClassName(beanDefinition.getType()))); + + body.addAndGetStatement(assignExpr); + MethodDeclaration existingCreateInstance = + builder.getClassDeclaration().getMethodsByName("createInstance").get(0); + existingCreateInstance.setBody(body); + } + + private void addDependantClassHolder(ClassBuilder builder, BeanDefinition beanDefinition) { + builder.getClassCompilationUnit().addImport(List.class); + builder.getClassCompilationUnit().addImport(ArrayList.class); + + ClassOrInterfaceType addDependantClass = new ClassOrInterfaceType(); + addDependantClass.setName(List.class.getCanonicalName()); + addDependantClass + .setTypeArguments(new ClassOrInterfaceType().setName(List.class.getSimpleName())); + + builder.addFieldWithInitializer(addDependantClass, "dependantBeans", + new ObjectCreationExpr() + .setType(new ClassOrInterfaceType().setName(ArrayList.class.getSimpleName())), + Modifier.Keyword.PRIVATE, Modifier.Keyword.FINAL); + + + // builder.addStatementToConstructor(new MethodCallExpr(new + // NameExpr("dependantBeans"),"add").addArgument()) + + } + + private void generateProxy(ClassBuilder builder, BeanDefinition beanDefinition) { + ClassOrInterfaceDeclaration wrapper = new ClassOrInterfaceDeclaration(); + wrapper.setName( + "Proxy" + MoreTypes.asTypeElement(beanDefinition.getType()).getSimpleName().toString()); + wrapper.addExtendedType(Utils.getSimpleClassName(beanDefinition.getType())); + + ClassOrInterfaceType implementsCircularDependencyProxy = new ClassOrInterfaceType(); + implementsCircularDependencyProxy.setName(CircularDependencyProxy.class.getCanonicalName()); + implementsCircularDependencyProxy.setTypeArguments( + new ClassOrInterfaceType().setName(Utils.getSimpleClassName(beanDefinition.getType()))); + wrapper.getImplementedTypes().add(implementsCircularDependencyProxy); + + wrapper.setModifier(com.github.javaparser.ast.Modifier.Keyword.FINAL, true); + + ConstructorDeclaration constructor = wrapper.addConstructor(Modifier.Keyword.PRIVATE); + MethodCallExpr _super = new MethodCallExpr("super"); + beanDefinition.getConstructorParams().forEach(param -> { + _super.addArgument(new CastExpr( + new ClassOrInterfaceType().setName(param.getVariableElement().asType().toString()), + new NullLiteralExpr())); + }); + + constructor.getBody().addAndGetStatement(_super); + + builder.getClassDeclaration().addMember(wrapper); + + wrapper.addField(Utils.getSimpleClassName(beanDefinition.getType()), "instance", + Modifier.Keyword.PRIVATE); + + Utils.getAllMethodsIn(elements, MoreTypes.asTypeElement(beanDefinition.getType())).stream() + .filter(elm -> !elm.getModifiers().contains(javax.lang.model.element.Modifier.PRIVATE)) + .filter(elm -> !elm.getModifiers().contains(javax.lang.model.element.Modifier.ABSTRACT)) + .filter(elm -> !elm.getModifiers().contains(javax.lang.model.element.Modifier.NATIVE)) + .filter(elm -> !elm.getModifiers().contains(javax.lang.model.element.Modifier.FINAL)) + .filter(elm -> !OBJECT_METHODS.contains(elm.getSimpleName().toString())).forEach(elm -> { + addMethod(wrapper, beanDefinition, elm); + }); + + addUnwrapMethod(wrapper, beanDefinition); + addSetInstance(wrapper, beanDefinition); + + } + + private void addSetInstance(ClassOrInterfaceDeclaration wrapper, BeanDefinition beanDefinition) { + MethodDeclaration setInstance = wrapper.addMethod("setInstance", Modifier.Keyword.PUBLIC); + setInstance.addAnnotation(Override.class); + Parameter parameter = new Parameter(); + parameter.setType(Utils.getSimpleClassName(beanDefinition.getType())); + parameter.setName("delegate"); + setInstance.addParameter(parameter); + + setInstance.getBody().get().addAndGetStatement( + new AssignExpr().setTarget(new NameExpr("instance")).setValue(new NameExpr("delegate"))); + } + + private void addUnwrapMethod(ClassOrInterfaceDeclaration wrapper, BeanDefinition beanDefinition) { + MethodDeclaration unwrapMethod = wrapper.addMethod("unwrap", Modifier.Keyword.PUBLIC); + unwrapMethod.addAnnotation(Override.class); + unwrapMethod.setType(Utils.getSimpleClassName(beanDefinition.getType())); + unwrapMethod.getBody().get().addAndGetStatement(new ReturnStmt(new NameExpr("instance"))); + } + + private void addMethod(ClassOrInterfaceDeclaration wrapper, BeanDefinition beanDefinition, + ExecutableElement elm) { + List modifierList = elm.getModifiers().stream() + .map(m -> Modifier.Keyword.valueOf(m.name())).collect(Collectors.toList()); + + MethodDeclaration methodDeclaration = wrapper.addMethod(elm.getSimpleName().toString(), + modifierList.toArray(new Modifier.Keyword[modifierList.size()])); + + methodDeclaration.setType(elm.getReturnType().toString()); + MethodCallExpr methodCallExpr = + new MethodCallExpr(new NameExpr("instance"), elm.getSimpleName().toString()); + + elm.getParameters().forEach(param -> { + Parameter parameter = new Parameter(); + parameter.setType(param.asType().toString()); + parameter.setName(param.getSimpleName().toString()); + + methodDeclaration.addParameter(parameter); + methodCallExpr.addArgument(param.getSimpleName().toString()); + }); + + ExpressionStmt call = new ExpressionStmt(methodCallExpr); + if (!elm.getReturnType().toString().equals("void")) { + methodDeclaration.getBody().get().addAndGetStatement(new ReturnStmt(call.getExpression())); + } else { + methodDeclaration.getBody().get().addAndGetStatement(call); + + } + } + + private void setExtendsProxyBeanFactory(ClassBuilder builder, BeanDefinition beanDefinition) { + builder.getClassCompilationUnit().addImport(ProxyBeanFactory.class); + + ClassOrInterfaceType factory = new ClassOrInterfaceType(); + factory.setName(ProxyBeanFactory.class.getSimpleName()); + factory.setTypeArguments( + new ClassOrInterfaceType().setName(Utils.getSimpleClassName(beanDefinition.getType()))); + NodeList extendsTypes = new NodeList<>(); + extendsTypes.add(factory); + + builder.getClassDeclaration().setExtendedTypes(extendsTypes); + } + + private void addDependantBeanReadyMethod(ClassBuilder builder, BeanDefinition beanDefinition) { + MethodDeclaration dependantBeanReadyMethod = + builder.addMethod("dependantBeanReady", Modifier.Keyword.PUBLIC); + dependantBeanReadyMethod.addAndGetParameter(Class.class, "clazz"); + } +} diff --git a/processor/src/main/java/io/crysknife/generator/ScopedBeanGenerator.java b/processor/src/main/java/io/crysknife/generator/ScopedBeanGenerator.java index 7d239d5d..cc958134 100644 --- a/processor/src/main/java/io/crysknife/generator/ScopedBeanGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/ScopedBeanGenerator.java @@ -14,40 +14,67 @@ package io.crysknife.generator; -import java.util.function.Supplier; - -import javax.inject.Provider; -import javax.lang.model.element.TypeElement; - import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.body.ConstructorDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.expr.AssignExpr; +import com.github.javaparser.ast.expr.BinaryExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.FieldAccessExpr; import com.github.javaparser.ast.expr.LambdaExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.ast.expr.NullLiteralExpr; import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.github.javaparser.ast.expr.ThisExpr; +import com.github.javaparser.ast.expr.UnaryExpr; +import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.github.javaparser.ast.stmt.IfStmt; import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.ast.type.ClassOrInterfaceType; -import io.crysknife.client.Instance; +import com.google.auto.common.MoreElements; +import com.google.auto.common.MoreTypes; +import io.crysknife.annotation.Generator; +import io.crysknife.client.BeanManager; +import io.crysknife.client.InstanceFactory; import io.crysknife.client.Interceptor; import io.crysknife.client.Reflect; -import io.crysknife.client.internal.Factory; +import io.crysknife.client.SyncBeanDef; +import io.crysknife.client.internal.BeanFactory; import io.crysknife.client.internal.OnFieldAccessed; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.definition.InjectionParameterDefinition; +import io.crysknife.definition.ProducesBeanDefinition; +import io.crysknife.exception.GenerationException; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.point.FieldPoint; import io.crysknife.util.Utils; +import javax.annotation.PostConstruct; +import javax.enterprise.context.Dependent; +import javax.inject.Provider; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static com.github.javaparser.ast.expr.UnaryExpr.Operator.LOGICAL_COMPLEMENT; + /** * @author Dmitrii Tikhomirov Created by treblereel 3/3/19 */ -public abstract class ScopedBeanGenerator extends BeanIOCGenerator { +public abstract class ScopedBeanGenerator extends BeanIOCGenerator { protected FieldAccessExpr instance; @@ -56,138 +83,221 @@ public ScopedBeanGenerator(IOCContext iocContext) { } @Override - public void generateBeanFactory(ClassBuilder clazz, Definition definition) { - if (definition instanceof BeanDefinition) { - - BeanDefinition beanDefinition = (BeanDefinition) definition; - - initClassBuilder(clazz, beanDefinition); - - if (!iocContext.getGenerationContext().isGwt2() - && !iocContext.getGenerationContext().isJre()) { - generateInterceptorFieldDeclaration(clazz); - } + public void generate(ClassBuilder clazz, BeanDefinition beanDefinition) { + initClassBuilder(clazz, beanDefinition); + generateDependantFields(clazz, beanDefinition); + generateInterceptorFieldDeclaration(clazz); + generateNewInstanceMethodBuilder(clazz); + generateInitInstanceMethodBuilder(clazz, beanDefinition); + generateInstanceGetMethodBuilder(clazz, beanDefinition); + generateDependantFieldDeclaration(clazz, beanDefinition); + generateInstanceGetFieldDecorators(clazz, beanDefinition); + generateInstanceGetMethodDecorators(clazz, beanDefinition); + generateInstanceGetMethodReturn(clazz, beanDefinition); + processPostConstructAnnotation(clazz, beanDefinition); + write(clazz, beanDefinition, iocContext.getGenerationContext()); + } - generateInstanceGetMethodBuilder(clazz, beanDefinition); + private void generateDependantFields(ClassBuilder classBuilder, BeanDefinition definition) { + Set params = definition.getConstructorParams(); + Iterator injectionPointDefinitionIterator = params.iterator(); + while (injectionPointDefinitionIterator.hasNext()) { + InjectableVariableDefinition argument = injectionPointDefinitionIterator.next(); + generateFactoryFieldDeclaration(classBuilder, definition, argument, "constructor"); + } - generateDependantFieldDeclaration(clazz, beanDefinition); + definition.getFields().forEach( + field -> generateFactoryFieldDeclaration(classBuilder, definition, field, "field")); - generateInstanceGetMethodDecorators(clazz, beanDefinition); + } - generateInstanceGetMethodReturn(clazz, beanDefinition); + protected void generateInitInstanceMethodBuilder(ClassBuilder classBuilder, + BeanDefinition beanDefinition) { + classBuilder.addInitInstanceMethod(); + } - generateFactoryCreateMethod(clazz, beanDefinition); + public void initClassBuilder(ClassBuilder clazz, BeanDefinition beanDefinition) { + String pkg = Utils.getPackageName(MoreTypes.asTypeElement(beanDefinition.getType())); + TypeElement asTypeElement = MoreTypes.asTypeElement(beanDefinition.getType()); - write(clazz, beanDefinition, iocContext.getGenerationContext()); + StringBuffer sb = new StringBuffer(); + if (asTypeElement.getEnclosingElement().getKind().isClass()) { + sb.append(MoreElements.asType(asTypeElement.getEnclosingElement()).getSimpleName()); + sb.append("_"); } - } + sb.append(MoreTypes.asTypeElement(beanDefinition.getType()).getSimpleName()); + sb.append("_Factory"); - public void initClassBuilder(ClassBuilder clazz, BeanDefinition beanDefinition) { - clazz.getClassCompilationUnit().setPackageDeclaration(beanDefinition.getPackageName()); - clazz.getClassCompilationUnit().addImport(Factory.class); + String classFactoryName = sb.toString(); + + clazz.getClassCompilationUnit().setPackageDeclaration(pkg); + clazz.getClassCompilationUnit().addImport(BeanFactory.class); + clazz.getClassCompilationUnit().addImport(SyncBeanDef.class); + clazz.getClassCompilationUnit().addImport(InstanceFactory.class); clazz.getClassCompilationUnit().addImport(Provider.class); clazz.getClassCompilationUnit().addImport(OnFieldAccessed.class); clazz.getClassCompilationUnit().addImport(Reflect.class); - clazz.setClassName(beanDefinition.getClassFactoryName()); + clazz.getClassCompilationUnit().addImport(Supplier.class); + clazz.getClassCompilationUnit().addImport(BeanManager.class); + clazz.getClassCompilationUnit().addImport(Dependent.class); + clazz.setClassName(classFactoryName); ClassOrInterfaceType factory = new ClassOrInterfaceType(); - factory.setName("Factory<" + beanDefinition.getClassName() + ">"); - clazz.getImplementedTypes().add(factory); + factory.setName(BeanFactory.class.getSimpleName()); + factory.setTypeArguments( + new ClassOrInterfaceType().setName(Utils.getSimpleClassName(beanDefinition.getType()))); + clazz.getExtendedTypes().add(factory); } private void generateInterceptorFieldDeclaration(ClassBuilder clazz) { - clazz.getClassCompilationUnit().addImport(Interceptor.class); - clazz.addField(Interceptor.class.getSimpleName(), "interceptor", Modifier.Keyword.PRIVATE); + if (!iocContext.getGenerationContext().isGwt2() && !iocContext.getGenerationContext().isJre()) { + clazz.getClassCompilationUnit().addImport(Interceptor.class); + clazz.addField(Interceptor.class.getSimpleName(), "interceptor", Modifier.Keyword.PRIVATE); + } + } + + public void generateNewInstanceMethodBuilder(ClassBuilder classBuilder) { + MethodDeclaration getMethodDeclaration = + classBuilder.addMethod("createInstance", Modifier.Keyword.PUBLIC); + + getMethodDeclaration.addAnnotation(Override.class); + getMethodDeclaration.setType(Utils.getSimpleClassName(classBuilder.beanDefinition.getType())); + classBuilder.setGetMethodDeclaration(getMethodDeclaration); } public void generateInstanceGetMethodBuilder(ClassBuilder classBuilder, BeanDefinition beanDefinition) { - MethodDeclaration getMethodDeclaration = classBuilder.addMethod("get", Modifier.Keyword.PUBLIC); + MethodDeclaration getMethodDeclaration = + classBuilder.addMethod("getInstance", Modifier.Keyword.PUBLIC); getMethodDeclaration.addAnnotation(Override.class); - getMethodDeclaration.setType(classBuilder.beanDefinition.getClassName()); - classBuilder.setGetMethodDeclaration(getMethodDeclaration); + getMethodDeclaration.setType(Utils.getSimpleClassName(classBuilder.beanDefinition.getType())); + + getMethodDeclaration.getBody().ifPresent(body -> { + + IfStmt ifStmt = new IfStmt().setCondition(new UnaryExpr( + new MethodCallExpr(new MethodCallExpr(new NameExpr("beanDef"), "getScope"), "equals") + .addArgument(new FieldAccessExpr(new NameExpr("Dependent"), "class")), + LOGICAL_COMPLEMENT)); + + body.addAndGetStatement(ifStmt); + BlockStmt blockStmt = new BlockStmt(); + + blockStmt.addAndGetStatement( + new IfStmt().setCondition(new BinaryExpr(new NameExpr("instance"), new NullLiteralExpr(), + BinaryExpr.Operator.NOT_EQUALS)).setThenStmt(new ReturnStmt("instance"))); + ifStmt.setThenStmt(blockStmt); + body.addAndGetStatement(new MethodCallExpr("createInstance")); + body.addAndGetStatement(new MethodCallExpr("initInstance")); + body.addAndGetStatement(new ReturnStmt(new NameExpr("instance"))); + }); } + public void generateDependantFieldDeclaration(ClassBuilder classBuilder, BeanDefinition beanDefinition) { - classBuilder.addConstructorDeclaration(Modifier.Keyword.PRIVATE); + + ConstructorDeclaration constructorDeclaration = + classBuilder.addConstructorDeclaration(Modifier.Keyword.PUBLIC); + constructorDeclaration.addAndGetParameter(BeanManager.class, "beanManager"); + + constructorDeclaration.getBody() + .addAndGetStatement(new MethodCallExpr("super").addArgument("beanManager")); + if (!iocContext.getGenerationContext().isJre()) { - beanDefinition.getFieldInjectionPoints().forEach(fieldPoint -> { - Expression expr = getFieldAccessorExpression(classBuilder, beanDefinition, fieldPoint); + beanDefinition.getFields().forEach(fieldPoint -> { + Expression expr = + getFieldAccessorExpression(classBuilder, beanDefinition, fieldPoint, "field"); classBuilder.getGetMethodDeclaration().getBody().get().addStatement(expr); }); } + + beanDefinition.getDecorators().stream() + .sorted( + Comparator.comparingInt(o -> o.getClass().getAnnotation(Generator.class).priority())) + .forEach(gen -> gen.generate(classBuilder, beanDefinition)); + } + + private void generateInstanceGetFieldDecorators(ClassBuilder clazz, + BeanDefinition beanDefinition) { + + Set points = new HashSet<>(beanDefinition.getFields()); + points.addAll(beanDefinition.getConstructorParams()); + + points.forEach(point -> { + point.getDecorators().stream() + .sorted( + Comparator.comparingInt(o -> o.getClass().getAnnotation(Generator.class).priority())) + .forEach(generator -> generator.generate(clazz, point)); + }); } private void generateInstanceGetMethodDecorators(ClassBuilder clazz, BeanDefinition beanDefinition) { - beanDefinition.generateDecorators(clazz); + + Set postConstruct = new LinkedHashSet<>(); + + beanDefinition.getMethods().stream().forEach(method -> { + method.getDecorators().stream() + .sorted( + Comparator.comparingInt(o -> o.getClass().getAnnotation(Generator.class).priority())) + .forEach(decorator -> { + // TODO PostConstruct hack + if (decorator instanceof PostConstructGenerator) { + postConstruct.add(decorator); + } else if (decorator instanceof ProducesGenerator) { + // TODO Produces + } else { + decorator.generate(clazz, method); + } + }); + }); } public void generateInstanceGetMethodReturn(ClassBuilder classBuilder, BeanDefinition beanDefinition) { classBuilder.getGetMethodDeclaration().getBody().get() - .addStatement(new ReturnStmt(new FieldAccessExpr(new ThisExpr(), "instance"))); + .addStatement(new ReturnStmt(new NameExpr("instance"))); } - public void generateFactoryCreateMethod(ClassBuilder classBuilder, + // TODO add validation + private void processPostConstructAnnotation(ClassBuilder classBuilder, BeanDefinition beanDefinition) { - MethodDeclaration methodDeclaration = - classBuilder.addMethod("create", Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC); - methodDeclaration.setType(beanDefinition.getClassFactoryName()); - ObjectCreationExpr newInstance = new ObjectCreationExpr(); - newInstance.setType(new ClassOrInterfaceType().setName(beanDefinition.getClassFactoryName())); - methodDeclaration.getBody() - .ifPresent(body -> body.getStatements().add(new ReturnStmt(newInstance))); - } - - protected Expression getFieldAccessorExpression(ClassBuilder classBuilder, - BeanDefinition beanDefinition, FieldPoint fieldPoint) { - if (iocContext.getGenerationContext().isGwt2()) { - return new MethodCallExpr(beanDefinition.getClassName() + "Info." + fieldPoint.getName()) - .addArgument(new FieldAccessExpr(new ThisExpr(), "instance")) - .addArgument(iocContext.getBeans().get(fieldPoint.getType()).generateBeanCall(iocContext, - classBuilder, fieldPoint)); + LinkedList postConstructs = Utils + .getAllMethodsIn(iocContext.getGenerationContext().getElements(), + MoreTypes.asTypeElement(beanDefinition.getType())) + .stream().filter(elm -> elm.getAnnotation(PostConstruct.class) != null) + .collect(Collectors.toCollection(LinkedList::new)); + + Iterator elm = postConstructs.descendingIterator(); + while (elm.hasNext()) { + FieldAccessExpr instance = new FieldAccessExpr(new ThisExpr(), "instance"); + MethodCallExpr method = new MethodCallExpr(instance, elm.next().getSimpleName().toString()); + classBuilder.getInitInstanceMethod().getBody().get().addAndGetStatement(method); } - - FieldAccessExpr fieldAccessExpr = new FieldAccessExpr(new ThisExpr(), "interceptor"); - - MethodCallExpr reflect = - new MethodCallExpr(new NameExpr(Reflect.class.getSimpleName()), "objectProperty") - .addArgument(beanDefinition.getClassName() + "Info." + fieldPoint.getName()) - .addArgument(new FieldAccessExpr(new ThisExpr(), "instance")); - - LambdaExpr lambda = new LambdaExpr(); - lambda.setEnclosingParameters(true); - lambda.setBody(new ExpressionStmt(iocContext.getBeans().get(fieldPoint.getType()) - .generateBeanCall(iocContext, classBuilder, fieldPoint))); - - ObjectCreationExpr onFieldAccessedCreationExpr = new ObjectCreationExpr(); - onFieldAccessedCreationExpr.setType(OnFieldAccessed.class.getSimpleName()); - onFieldAccessedCreationExpr.addArgument(lambda); - - return new MethodCallExpr(fieldAccessExpr, "addGetPropertyInterceptor").addArgument(reflect) - .addArgument(onFieldAccessedCreationExpr); } protected Expression generateInstanceInitializer(ClassBuilder classBuilder, BeanDefinition definition) { - instance = new FieldAccessExpr(new ThisExpr(), "instance"); - ObjectCreationExpr newInstance = generateNewInstanceCreationExpr(definition); + Expression instanceFieldAssignExpr = + generateInstanceInitializerNewObjectExpr(classBuilder, definition); + return new AssignExpr().setTarget(instance).setValue(instanceFieldAssignExpr); + } - // TODO refactoring - if (definition.getConstructorInjectionPoint() != null) { - classBuilder.addConstructorDeclaration(Modifier.Keyword.PRIVATE); - for (FieldPoint argument : definition.getConstructorInjectionPoint().getArguments()) { - generateFactoryFieldDeclaration(classBuilder, argument.getType()); - newInstance.addArgument(iocContext.getBeans().get(argument.getType()) - .generateBeanCall(iocContext, classBuilder, argument)); - } + protected Expression generateInstanceInitializerNewObjectExpr(ClassBuilder classBuilder, + BeanDefinition definition) { + ObjectCreationExpr newInstance = generateNewInstanceCreationExpr(definition); + Set params = definition.getConstructorParams(); + Iterator injectionPointDefinitionIterator = params.iterator(); + while (injectionPointDefinitionIterator.hasNext()) { + InjectableVariableDefinition argument = injectionPointDefinitionIterator.next(); + newInstance.addArgument( + getFieldAccessorExpression(classBuilder, definition, argument, "constructor")); } Expression instanceFieldAssignExpr; + if (iocContext.getGenerationContext().isGwt2() || iocContext.getGenerationContext().isJre()) { instanceFieldAssignExpr = newInstance; } else { @@ -199,80 +309,95 @@ protected Expression generateInstanceInitializer(ClassBuilder classBuilder, classBuilder.getGetMethodDeclaration().getBody().get().addAndGetStatement( new AssignExpr().setTarget(interceptor).setValue(interceptorCreationExpr)); + + instanceFieldAssignExpr = new MethodCallExpr(interceptor, "getProxy"); } + return instanceFieldAssignExpr; + } - return new AssignExpr().setTarget(instance).setValue(instanceFieldAssignExpr); + protected Expression getFieldAccessorExpression(ClassBuilder classBuilder, + BeanDefinition beanDefinition, InjectableVariableDefinition fieldPoint, String kind) { + + String varName = "_" + kind + "_" + fieldPoint.getVariableElement().getSimpleName().toString(); + + if (fieldPoint.getBeanDefinition() instanceof ProducesBeanDefinition) { + throw new Error(fieldPoint.getVariableElement().getSimpleName().toString()); + } + + + if (kind.equals("constructor")) { + return new MethodCallExpr( + new MethodCallExpr(new FieldAccessExpr(new ThisExpr(), varName), "get"), "getInstance"); + } + + + if (iocContext.getGenerationContext().isGwt2()) { + return new MethodCallExpr(Utils.getSimpleClassName(classBuilder.beanDefinition.getType()) + + "Info." + fieldPoint.getVariableElement().getSimpleName()) + .addArgument(new FieldAccessExpr(new ThisExpr(), "instance")) + .addArgument(new MethodCallExpr(new FieldAccessExpr(new ThisExpr(), varName), "get")); + } + + FieldAccessExpr fieldAccessExpr = new FieldAccessExpr(new ThisExpr(), "interceptor"); + String clazzName = MoreTypes.asTypeElement(beanDefinition.getType()).getSimpleName().toString(); + + MethodCallExpr reflect = + new MethodCallExpr(new NameExpr(Reflect.class.getSimpleName()), "objectProperty") + .addArgument(clazzName + "Info." + fieldPoint.getVariableElement().getSimpleName()) + .addArgument(new FieldAccessExpr(new ThisExpr(), "instance")); + + LambdaExpr lambda = new LambdaExpr(); + lambda.setEnclosingParameters(true); + lambda.setBody(new ExpressionStmt( + new MethodCallExpr(new FieldAccessExpr(new ThisExpr(), varName), "get"))); + + ObjectCreationExpr onFieldAccessedCreationExpr = new ObjectCreationExpr(); + onFieldAccessedCreationExpr.setType(OnFieldAccessed.class.getSimpleName()); + onFieldAccessedCreationExpr.addArgument(lambda); + + return new MethodCallExpr(fieldAccessExpr, "addGetPropertyInterceptor").addArgument(reflect) + .addArgument(onFieldAccessedCreationExpr); } protected ObjectCreationExpr generateNewInstanceCreationExpr(BeanDefinition definition) { ObjectCreationExpr newInstance = new ObjectCreationExpr(); - return newInstance.setType(definition.getClassName()); + return newInstance.setType(Utils.getSimpleClassName(definition.getType())); } protected void generateFactoryFieldDeclaration(ClassBuilder classBuilder, - TypeElement typeElement) { - String varName = Utils.toVariableName(typeElement); + BeanDefinition definition, InjectableVariableDefinition fieldPoint, String kind) { + String varName = "_" + kind + "_" + fieldPoint.getVariableElement().getSimpleName().toString(); + String typeQualifiedName = generationUtils.getActualQualifiedBeanName(fieldPoint); ClassOrInterfaceType supplier = new ClassOrInterfaceType().setName(Supplier.class.getSimpleName()); ClassOrInterfaceType type = new ClassOrInterfaceType(); - type.setName(Instance.class.getSimpleName()); - type.setTypeArguments( - new ClassOrInterfaceType().setName(typeElement.getQualifiedName().toString())); + type.setName(InstanceFactory.class.getSimpleName()); + type.setTypeArguments(new ClassOrInterfaceType().setName(typeQualifiedName)); supplier.setTypeArguments(type); - classBuilder.addField(supplier, varName, Modifier.Keyword.PRIVATE); - } - @Override - public Expression generateBeanCall(ClassBuilder clazz, FieldPoint fieldPoint, - BeanDefinition beanDefinition) { - generateFactoryFieldDeclaration(clazz, beanDefinition); - generateFactoryConstructorDepsBuilder(clazz, beanDefinition); - TypeElement point = fieldPoint.isNamed() - ? iocContext.getQualifiers().get(fieldPoint.getType()).get(fieldPoint.getNamed()).getType() - : fieldPoint.getType(); - return new MethodCallExpr(new MethodCallExpr(new NameExpr(Utils.toVariableName(point)), "get"), - "get"); - } - protected void generateFactoryFieldDeclaration(ClassBuilder classBuilder, - BeanDefinition beanDefinition) { - generateFactoryFieldDeclaration(classBuilder, beanDefinition.getType()); - } - - public void generateFactoryConstructorDepsBuilder(ClassBuilder classBuilder, - BeanDefinition beanDefinition) { - classBuilder.getClassCompilationUnit().addImport("io.crysknife.client.BeanManagerImpl"); - classBuilder.getClassCompilationUnit().addImport(Instance.class.getCanonicalName()); - classBuilder.getClassCompilationUnit().addImport(Supplier.class.getCanonicalName()); - addFactoryFieldInitialization(classBuilder, beanDefinition); - } - - public void addFactoryFieldInitialization(ClassBuilder classBuilder, - BeanDefinition beanDefinition) { - String varName = Utils.toVariableName(beanDefinition.getQualifiedName()); - ClassOrInterfaceType beanManager = new ClassOrInterfaceType().setName(getFactoryVariableName()); - MethodCallExpr callForBeanManagerImpl = - new MethodCallExpr(beanManager.getNameAsExpression(), "get"); + Expression beanCall; + if (fieldPoint.getImplementation().isPresent() + && fieldPoint.getImplementation().get().getIocGenerator().isPresent()) { + beanCall = fieldPoint.getImplementation().get().getIocGenerator().get() + .generateBeanLookupCall(classBuilder, fieldPoint); + } else if (fieldPoint.getGenerator().isPresent()) { + beanCall = fieldPoint.getGenerator().get().generateBeanLookupCall(classBuilder, fieldPoint); + } else { + beanCall = generateBeanLookupCall(classBuilder, fieldPoint); + } - MethodCallExpr callForProducer = new MethodCallExpr(callForBeanManagerImpl, "lookupBean") - .addArgument(new FieldAccessExpr(new NameExpr(beanDefinition.getQualifiedName()), "class")); - FieldAccessExpr field = new FieldAccessExpr(new ThisExpr(), varName); + if (beanCall == null) { + throw new GenerationException(); + } LambdaExpr lambda = new LambdaExpr().setEnclosingParameters(true); - lambda.setBody(new ExpressionStmt(callForProducer)); + lambda.setBody(new ExpressionStmt(beanCall)); - AssignExpr assign = new AssignExpr().setTarget(field).setValue(lambda); - - classBuilder.addStatementToConstructor(assign); + classBuilder.addFieldWithInitializer(supplier, varName, lambda, Modifier.Keyword.PRIVATE); } - public String getFactoryVariableName() { - return "BeanManagerImpl"; - } - protected void generateFactoryFieldDeclaration(ClassBuilder classBuilder, FieldPoint fieldPoint) { - generateFactoryFieldDeclaration(classBuilder, fieldPoint.getType()); - } } diff --git a/processor/src/main/java/io/crysknife/generator/SingletonGenerator.java b/processor/src/main/java/io/crysknife/generator/SingletonGenerator.java index aa66e64c..05a2d70f 100644 --- a/processor/src/main/java/io/crysknife/generator/SingletonGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/SingletonGenerator.java @@ -28,7 +28,8 @@ import io.crysknife.annotation.Generator; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.util.Utils; /** * @author Dmitrii Tikhomirov Created by treblereel 3/2/19 @@ -58,6 +59,7 @@ public void generateInstanceGetMethodBuilder(ClassBuilder builder, ifStmt.setThenStmt(new ReturnStmt(instance)); body.addAndGetStatement(ifStmt); body.addAndGetStatement(generateInstanceInitializer(builder, beanDefinition)); - builder.addField(beanDefinition.getClassName(), "instance", Modifier.Keyword.PRIVATE); + builder.addField(Utils.getSimpleClassName(beanDefinition.getType()), "instance", + Modifier.Keyword.PRIVATE); } } diff --git a/processor/src/main/java/io/crysknife/generator/WiringElementType.java b/processor/src/main/java/io/crysknife/generator/WiringElementType.java index e4182bc0..9475270f 100644 --- a/processor/src/main/java/io/crysknife/generator/WiringElementType.java +++ b/processor/src/main/java/io/crysknife/generator/WiringElementType.java @@ -18,5 +18,5 @@ * @author Dmitrii Tikhomirov Created by treblereel 3/4/19 */ public enum WiringElementType { - BEAN, METHOD_DECORATOR, CLASS_DECORATOR, PRODUCER_ELEMENT, FIELD_TYPE, PARAMETER, + BEAN, METHOD_DECORATOR, FIELD_DECORATOR, CLASS_DECORATOR, PRODUCER_ELEMENT, FIELD_TYPE, PARAMETER, } diff --git a/processor/src/main/java/io/crysknife/generator/api/ClassBuilder.java b/processor/src/main/java/io/crysknife/generator/api/ClassBuilder.java index 546bbd98..445aaddf 100644 --- a/processor/src/main/java/io/crysknife/generator/api/ClassBuilder.java +++ b/processor/src/main/java/io/crysknife/generator/api/ClassBuilder.java @@ -29,7 +29,7 @@ import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.Type; -import io.crysknife.generator.definition.BeanDefinition; +import io.crysknife.definition.BeanDefinition; /** * @author Dmitrii Tikhomirov Created by treblereel 3/3/19 @@ -37,10 +37,11 @@ public class ClassBuilder { public final BeanDefinition beanDefinition; - Set statementToConstructor = new HashSet<>(); + private Set statementToConstructor = new HashSet<>(); private CompilationUnit clazz = new CompilationUnit(); private ClassOrInterfaceDeclaration classDeclaration; private MethodDeclaration getGetMethodDeclaration; + private MethodDeclaration initMethodDeclaration; private ConstructorDeclaration constructorDeclaration; private HashMap fields = new HashMap<>(); @@ -49,7 +50,8 @@ public ClassBuilder(BeanDefinition beanDefinition) { } public void build() { - beanDefinition.generate(this); + beanDefinition.getIocGenerator() + .ifPresent(iocGenerator -> iocGenerator.generate(this, beanDefinition)); } public String toSourceCode() { @@ -78,7 +80,7 @@ public FieldDeclaration addField(Type type, String name, Modifier.Keyword... mod } FieldDeclaration fieldDeclaration = null; if (getClassDeclaration() != null) { - fieldDeclaration = getClassDeclaration().addField(type, name, modifiers); + fieldDeclaration = classDeclaration.addField(type, name, modifiers); fields.put(name, fieldDeclaration); } return fieldDeclaration; @@ -101,10 +103,11 @@ public NodeList getExtendedTypes() { return getClassDeclaration().getExtendedTypes(); } - public void addConstructorDeclaration(Modifier.Keyword... modifiers) { + public ConstructorDeclaration addConstructorDeclaration(Modifier.Keyword... modifiers) { if (constructorDeclaration == null) { this.constructorDeclaration = classDeclaration.addConstructor(modifiers); } + return constructorDeclaration; } public void addParametersToConstructor(Parameter p) { @@ -116,13 +119,18 @@ private ConstructorDeclaration getConstructorDeclaration() { } public void addStatementToConstructor(Expression expr) { - if (!statementToConstructor.contains(expr) && getConstructorDeclaration() != null) { + if (constructorDeclaration == null) { + this.constructorDeclaration = classDeclaration.addConstructor(Modifier.Keyword.PUBLIC); + } + + if (!statementToConstructor.contains(expr)) { getConstructorDeclaration().getBody().addStatement(expr); statementToConstructor.add(expr); } } public MethodDeclaration addMethod(String methodName, Modifier.Keyword... modifiers) { + return getClassDeclaration().addMethod(methodName, modifiers); } @@ -145,4 +153,13 @@ public FieldDeclaration addFieldWithInitializer(String type, String name, Expres fields.put(name, fieldDeclaration); return fieldDeclaration; } + + public MethodDeclaration addInitInstanceMethod() { + initMethodDeclaration = classDeclaration.addMethod("doInitInstance", Modifier.Keyword.PUBLIC); + return initMethodDeclaration; + } + + public MethodDeclaration getInitInstanceMethod() { + return initMethodDeclaration; + } } diff --git a/processor/src/main/java/io/crysknife/generator/context/GenerationContext.java b/processor/src/main/java/io/crysknife/generator/context/GenerationContext.java index c9a434af..bcd6a521 100644 --- a/processor/src/main/java/io/crysknife/generator/context/GenerationContext.java +++ b/processor/src/main/java/io/crysknife/generator/context/GenerationContext.java @@ -22,6 +22,8 @@ import io.crysknife.generator.context.oracle.ResourceOracle; import io.crysknife.generator.context.oracle.ResourceOracleImpl; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ScanResult; /** * @author Dmitrii Tikhomirov Created by treblereel 2/21/19 @@ -30,6 +32,7 @@ public class GenerationContext { private final RoundEnvironment roundEnvironment; private final ProcessingEnvironment processingEnvironment; + private final ScanResult scanResult = new ClassGraph().enableAllInfo().scan(); private final ResourceOracle resourceOracle = new ResourceOracleImpl(this); private boolean isGwt2 = false; private boolean isJre = false; @@ -85,4 +88,8 @@ public boolean isJre() { public ResourceOracle getResourceOracle() { return resourceOracle; } + + public ScanResult getScanResult() { + return scanResult; + } } diff --git a/processor/src/main/java/io/crysknife/generator/context/IOCContext.java b/processor/src/main/java/io/crysknife/generator/context/IOCContext.java index 3618d58a..2e07811b 100644 --- a/processor/src/main/java/io/crysknife/generator/context/IOCContext.java +++ b/processor/src/main/java/io/crysknife/generator/context/IOCContext.java @@ -14,33 +14,34 @@ package io.crysknife.generator.context; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.SetMultimap; +import io.crysknife.exception.GenerationException; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.IOCGenerator; +import io.crysknife.generator.WiringElementType; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.BeanDefinitionFactory; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ClassInfoList; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.util.Elements; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.SetMultimap; -import io.github.classgraph.ClassGraph; -import io.github.classgraph.ClassInfo; -import io.github.classgraph.ClassInfoList; -import io.github.classgraph.ScanResult; -import io.crysknife.exception.GenerationException; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.WiringElementType; -import io.crysknife.generator.definition.BeanDefinition; - /** * @author Dmitrii Tikhomirov Created by treblereel 3/2/19 */ @@ -48,20 +49,13 @@ public class IOCContext { private final SetMultimap generators = HashMultimap.create(); - private final Map beans = new HashMap<>(); - - private final Map> qualifiers = new HashMap<>(); + private final Map beans = new HashMap<>(); private final GenerationContext generationContext; - private final List orderedBeans = new LinkedList<>(); - - private final List blacklist = new ArrayList<>(); + private final List orderedBeans = new LinkedList<>(); - // TODO Temporary solution before ill find out why in j2cl-m-p apt get*AnnotatedWith isn't able to - // process - // annotations in external deps - private final ScanResult scanResult = new ClassGraph().enableAllInfo().scan(); + private final List buildIn = new ArrayList<>(); private final Map> classesByAnnotation = new HashMap<>(); @@ -71,8 +65,11 @@ public class IOCContext { private final Map> parametersByAnnotation = new HashMap<>(); + private final BeanDefinitionFactory beanDefinitionFactory; + public IOCContext(GenerationContext generationContext) { this.generationContext = generationContext; + this.beanDefinitionFactory = new BeanDefinitionFactory(this, null); } public void register(final Class annotation, final WiringElementType wiringElementType, @@ -87,53 +84,62 @@ public void register(final Class annotation, Class exactType, generators.put(new IOCGeneratorMeta(annotation.getCanonicalName(), type, wiringElementType), generator); if (!exactType.equals(Object.class)) { - BeanDefinition beanDefinition = getBeanDefinitionOrCreateAndReturn(type); - beanDefinition.setGenerator(generator); - getBeans().put(type, beanDefinition); + BeanDefinition beanDefinition = null; + try { + beanDefinition = getBeanDefinitionOrCreateAndReturn(type.asType()); + } catch (UnableToCompleteException e) { + e.printStackTrace(); + } + beanDefinition.setIocGenerator(generator); + getBeans().put(type.asType(), beanDefinition); + buildIn.add(exactType.getCanonicalName()); } } - public SetMultimap getGenerators() { - return generators; + public GenerationContext getGenerationContext() { + return generationContext; } - public Map getBeans() { - return beans; - } - public BeanDefinition getBean(TypeElement bean) { - if (beans.containsKey(bean)) { - return beans.get(bean); + public BeanDefinition getBeanDefinitionOrCreateAndReturn(TypeMirror typeElement) + throws UnableToCompleteException { + TypeMirror candidate = generationContext.getTypes().erasure(typeElement); + BeanDefinition beanDefinition = null; + if (beans.containsKey(candidate)) { + return beans.get(candidate); + } else { + beanDefinition = beanDefinitionFactory.of(candidate); + beans.put(candidate, beanDefinition); + // beanDefinition.processInjections(this); } - throw new GenerationException(bean.toString()); + + return beanDefinition; } - public GenerationContext getGenerationContext() { - return generationContext; + public Map getBeans() { + return beans; } - public Map> getQualifiers() { - return qualifiers; + public BeanDefinition getBean(TypeMirror type) { + TypeMirror erased = generationContext.getTypes().erasure(type); + + if (!beans.containsKey(erased)) { + throw new GenerationException("Unable to find Bean [" + erased + "], check scopes"); + } + + return beans.get(erased); } - public List getOrderedBeans() { - return orderedBeans; + public SetMultimap getGenerators() { + return generators; } - public List getBlacklist() { - return blacklist; + public List getOrderedBeans() { + return orderedBeans; } - public BeanDefinition getBeanDefinitionOrCreateAndReturn(TypeElement typeElement) { - BeanDefinition beanDefinition; - if (getBeans().containsKey(typeElement)) { - return getBeans().get(typeElement); - } else { - beanDefinition = BeanDefinition.of(typeElement, this); - getBeans().put(typeElement, beanDefinition); - beanDefinition.processInjections(this); - } - return beanDefinition; + public List getBuildIn() { + return buildIn; } // TODO j2cl-m-p workaround @@ -147,7 +153,8 @@ public Set getTypeElementsByAnnotation(String annotation) { getElementsByAnnotation(annotation).stream().filter(elm -> (elm instanceof TypeElement)) .map(element -> ((TypeElement) element)).collect(Collectors.toSet()); - ClassInfoList routeClassInfoList = scanResult.getClassesWithAnnotation(annotation); + ClassInfoList routeClassInfoList = + generationContext.getScanResult().getClassesWithAnnotation(annotation); for (ClassInfo routeClassInfo : routeClassInfoList) { TypeElement type = elements.getTypeElement(routeClassInfo.getName()); if (type != null) { @@ -175,7 +182,8 @@ public Set getMethodsByAnnotation(String annotation) { .filter(elm -> (elm instanceof ExecutableElement)) .map(element -> ((ExecutableElement) element)).collect(Collectors.toSet()); - ClassInfoList routeClassInfoList = scanResult.getClassesWithMethodAnnotation(annotation); + ClassInfoList routeClassInfoList = + generationContext.getScanResult().getClassesWithMethodAnnotation(annotation); for (ClassInfo routeClassInfo : routeClassInfoList) { if (!routeClassInfo.getDeclaredMethodInfo().asMap().isEmpty()) { TypeElement type = elements.getTypeElement(routeClassInfo.getName()); @@ -202,7 +210,7 @@ public Set getParametersByAnnotation(String annotation) { .map(element -> ((VariableElement) element)).collect(Collectors.toSet()); ClassInfoList routeClassInfoList = - scanResult.getClassesWithMethodParameterAnnotation(annotation); + generationContext.getScanResult().getClassesWithMethodParameterAnnotation(annotation); for (ClassInfo routeClassInfo : routeClassInfoList) { if (!routeClassInfo.getDeclaredMethodInfo().asMap().isEmpty()) { TypeElement type = elements.getTypeElement(routeClassInfo.getName()); @@ -222,24 +230,32 @@ public Set getParametersByAnnotation(String annotation) { return results; } + public TypeMirror getTypeMirror(Class clazz) { + return getTypeMirror(clazz.getCanonicalName()); + } + + public TypeMirror getTypeMirror(String clazz) { + return generationContext.getElements().getTypeElement(clazz).asType(); + } + public Set getFieldsByAnnotation(String annotation) { if (fieldsByAnnotation.containsKey(annotation)) { return fieldsByAnnotation.get(annotation); } - Elements elements = getGenerationContext().getElements(); Set results = getGenerationContext().getRoundEnvironment() .getElementsAnnotatedWith(elements.getTypeElement(annotation)).stream() .filter(elm -> (elm instanceof VariableElement)).map(element -> ((VariableElement) element)) .collect(Collectors.toSet()); - ClassInfoList routeClassInfoList = scanResult.getClassesWithMethodAnnotation(annotation); + ClassInfoList routeClassInfoList = + generationContext.getScanResult().getClassesWithMethodAnnotation(annotation); for (ClassInfo routeClassInfo : routeClassInfoList) { if (!routeClassInfo.getDeclaredFieldInfo().asMap().isEmpty()) { TypeElement type = elements.getTypeElement(routeClassInfo.getName()); if (type != null) { type.getEnclosedElements().stream().filter(elm -> (elm instanceof VariableElement)) - .filter(elm -> ((VariableElement) elm).getAnnotationMirrors().stream() + .filter(elm -> elm.getAnnotationMirrors().stream() .map(a -> a.getAnnotationType().toString()).filter(a -> a.equals(annotation)) .count() > 0) .map(method -> ((VariableElement) method)).forEach(results::add); @@ -250,6 +266,17 @@ public Set getFieldsByAnnotation(String annotation) { return results; } + public Optional getGenerator(String annotation, TypeElement type, + WiringElementType wiringElementType) { + IOCContext.IOCGeneratorMeta meta = + new IOCContext.IOCGeneratorMeta(annotation, type, wiringElementType); + Iterable generators = getGenerators().get(meta); + if (generators.iterator().hasNext()) { + return Optional.of(generators.iterator().next()); + } + return Optional.empty(); + } + public static class IOCGeneratorMeta { public final String annotation; @@ -264,9 +291,8 @@ public IOCGeneratorMeta(String annotation, TypeElement exactType, } @Override - public String toString() { - return "IOCGeneratorMeta{" + "annotation='" + annotation + '\'' + ", exactType=" + exactType - + ", wiringElementType=" + wiringElementType + '}'; + public int hashCode() { + return Objects.hash(annotation, exactType, wiringElementType); } @Override @@ -284,8 +310,9 @@ public boolean equals(Object o) { } @Override - public int hashCode() { - return Objects.hash(annotation, exactType, wiringElementType); + public String toString() { + return "IOCGeneratorMeta{" + "annotation='" + annotation + '\'' + ", exactType=" + exactType + + ", wiringElementType=" + wiringElementType + '}'; } } } 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 new file mode 100644 index 00000000..54da537b --- /dev/null +++ b/processor/src/main/java/io/crysknife/generator/context/oracle/BeanOracle.java @@ -0,0 +1,230 @@ +/* + * Copyright © 2021 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.generator.context.oracle; + +import com.google.auto.common.MoreTypes; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.UnscopedBeanDefinition; +import io.crysknife.util.Utils; + +import javax.enterprise.inject.Default; +import javax.enterprise.inject.Specializes; +import javax.enterprise.inject.Typed; +import javax.inject.Named; +import javax.inject.Qualifier; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.MirroredTypesException; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/5/21 + */ +public class BeanOracle { + + private final IOCContext context; + + public BeanOracle(IOCContext context) { + this.context = context; + } + + public BeanDefinition guess(InjectableVariableDefinition point) { + Named named = point.getVariableElement().getAnnotation(Named.class); + Set qualifiers = getAnnotationMirrors(point); + boolean isInterfaceOrAbstractClass = + isInterfaceOrAbstractClass(point.getVariableElement().asType()); + + TypeMirror beanTypeMirror = + context.getGenerationContext().getTypes().erasure(point.getVariableElement().asType()); + + if (isInterfaceOrAbstractClass) { + if (named != null) { + Optional candidate = processName(point, named); + if (candidate.isPresent()) { + return candidate.get(); + } + } + + if (!qualifiers.isEmpty()) { + Optional candidate = processQualifiers(point, qualifiers); + if (candidate.isPresent()) { + return candidate.get(); + } + } + + Optional candidate = + asInterfaceOrAbstractClass(point.getVariableElement().asType()); + if (candidate.isPresent()) { + return candidate.get(); + } + } + + // Case 2: simple injection case, known type + if (context.getBeans().containsKey(beanTypeMirror)) { + BeanDefinition simpleInjectionCaseCandidate = context.getBeans().get(beanTypeMirror); + if (simpleInjectionCaseCandidate.getIocGenerator().isPresent()) { + return simpleInjectionCaseCandidate; + } + } + + if (isUnscopedBean(beanTypeMirror)) { + return new UnscopedBeanDefinition(beanTypeMirror, context); + } + + return null; + } + + private boolean isUnscopedBean(TypeMirror beanTypeMirror) { + TypeElement type = MoreTypes.asTypeElement(beanTypeMirror); + + if (type.getKind().isClass() && !type.getModifiers().contains(Modifier.ABSTRACT) + && type.getModifiers().contains(Modifier.PUBLIC)) { + Set constructors = ElementFilter.methodsIn(type.getEnclosedElements()) + .stream().filter(elm -> elm.getKind().equals(ElementKind.CONSTRUCTOR)) + .collect(Collectors.toSet()); + if (constructors.isEmpty()) { + return true; + } + + if (constructors.stream().filter(elm -> elm.getParameters().isEmpty()) + .filter(elm -> elm.getModifiers().contains(Modifier.PUBLIC)).count() == 1) { + return true; + } + } + + return false; + } + + public Optional guessDefaultImpl(TypeMirror point) { + return asInterfaceOrAbstractClass(point); + } + + private Optional asInterfaceOrAbstractClass(TypeMirror point) { + Set subclasses = getSubClasses(point); + + Set types = subclasses.stream() + .filter(bean -> !isInterfaceOrAbstractClass(bean.getType())).collect(Collectors.toSet()); + // Case TheOnlyOneImpl + if (types.size() == 1) { + return types.stream().findFirst(); + } else if (types.size() > 1) { + // Case @Default + Set maybeDefault = types.stream() + .filter( + elm -> MoreTypes.asTypeElement(elm.getType()).getAnnotation(Default.class) != null) + .collect(Collectors.toSet()); + if (maybeDefault.size() == 1) { + return maybeDefault.stream().findFirst(); + } + // Case @Specializes + Set maybeSpecializes = types.stream().filter( + elm -> MoreTypes.asTypeElement(elm.getType()).getAnnotation(Specializes.class) != null) + .collect(Collectors.toSet()); + if (maybeSpecializes.size() == 1) { + return maybeSpecializes.stream().findFirst(); + } + // Case @Typed + Set maybeTyped = types.stream() + .filter(elm -> MoreTypes.asTypeElement(elm.getType()).getAnnotation(Typed.class) != null) + .collect(Collectors.toSet()); + if (!maybeTyped.isEmpty()) { + TypeMirror mirror = context.getGenerationContext().getTypes().erasure(point); + for (BeanDefinition typed : maybeTyped) { + Optional> annotations = getTypedAnnotationValues(typed.getType()); + if (annotations.isPresent()) { + if (annotations.get().contains(mirror)) { + return Optional.of(typed); + } + } + } + } + } + return Optional.empty(); + } + + private Optional> getTypedAnnotationValues(TypeMirror typeMirror) { + try { + MoreTypes.asTypeElement(typeMirror).getAnnotation(Typed.class).value(); + } catch (MirroredTypesException e) { + return Optional.of((List) e.getTypeMirrors()); + } + return Optional.empty(); + } + + private Optional processQualifiers(InjectableVariableDefinition point, + Set qualifiers) { + Set subclasses = getSubClasses(point.getVariableElement().asType()); + + List temp = + qualifiers.stream().map(a -> a.getAnnotationType().toString()).collect(Collectors.toList()); + String[] annotations = temp.toArray(new String[temp.size()]); + + return subclasses.stream().filter(bean -> !isInterfaceOrAbstractClass(bean.getType())) + .filter(q -> Utils.containsAnnotation(MoreTypes.asTypeElement(q.getType()), annotations)) + .findFirst(); + + } + + private Optional processName(InjectableVariableDefinition point, Named named) { + Set subclasses = getSubClasses(point.getVariableElement().asType()); + return subclasses.stream().filter(bean -> !isInterfaceOrAbstractClass(bean.getType())) + .filter(elm -> (MoreTypes.asTypeElement(elm.getType()).getAnnotation(Named.class) != null + && MoreTypes.asTypeElement(elm.getType()).getAnnotation(Named.class).value() + .equals(named.value()))) + .findFirst(); + } + + private Set getSubClasses(TypeMirror point) { + TypeMirror beanTypeMirror = context.getGenerationContext().getTypes().erasure(point); + BeanDefinition type = context.getBean(beanTypeMirror); + Set subclasses = new HashSet<>(type.getSubclasses()); + getAllSubtypes(type, subclasses); + type.getSubclasses().addAll(subclasses); + return subclasses; + } + + private Set getAllSubtypes(BeanDefinition beanDefinition, + Set subclasses) { + if (!beanDefinition.getSubclasses().isEmpty()) { + for (BeanDefinition subclass : beanDefinition.getSubclasses()) { + subclasses.add(subclass); + getAllSubtypes(subclass, subclasses); + } + } + return subclasses; + } + + private boolean isInterfaceOrAbstractClass(TypeMirror type) { + return MoreTypes.asTypeElement(type).getKind().isInterface() + || MoreTypes.asTypeElement(type).getModifiers().contains(Modifier.ABSTRACT); + } + + private Set getAnnotationMirrors(InjectableVariableDefinition point) { + return point.getVariableElement().getAnnotationMirrors().stream() + .filter(anno -> anno.getAnnotationType().asElement().getAnnotation(Qualifier.class) != null) + .collect(Collectors.toSet()); + } +} diff --git a/processor/src/main/java/io/crysknife/generator/context/oracle/ResourceOracle.java b/processor/src/main/java/io/crysknife/generator/context/oracle/ResourceOracle.java index ab21e348..8f5cd2fa 100644 --- a/processor/src/main/java/io/crysknife/generator/context/oracle/ResourceOracle.java +++ b/processor/src/main/java/io/crysknife/generator/context/oracle/ResourceOracle.java @@ -28,10 +28,10 @@ public interface ResourceOracle { /** Returns the resource for the given path name or null if there is no such resource. */ - URL[] findResources(CharSequence packageName, CharSequence[] pathName); + URL[] findResources(String packageName, String[] pathName); - URL findResource(CharSequence pkg, CharSequence relativeName); + URL findResource(String pkg, String relativeName); - URL findResource(CharSequence fullPath); + URL findResource(String fullPath); } diff --git a/processor/src/main/java/io/crysknife/generator/context/oracle/ResourceOracleImpl.java b/processor/src/main/java/io/crysknife/generator/context/oracle/ResourceOracleImpl.java index 294026c9..a469bf4b 100644 --- a/processor/src/main/java/io/crysknife/generator/context/oracle/ResourceOracleImpl.java +++ b/processor/src/main/java/io/crysknife/generator/context/oracle/ResourceOracleImpl.java @@ -18,6 +18,11 @@ import io.crysknife.exception.UnableToCompleteException; import io.crysknife.generator.context.GenerationContext; +import javax.annotation.processing.FilerException; +import javax.lang.model.element.ExecutableElement; +import javax.tools.FileObject; +import javax.tools.JavaFileManager.Location; +import javax.tools.StandardLocation; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; @@ -25,13 +30,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.annotation.processing.FilerException; -import javax.lang.model.element.ExecutableElement; -import javax.tools.FileObject; -import javax.tools.JavaFileManager.Location; -import javax.tools.StandardLocation; -/** @author Dmitrii Tikhomirov Created by treblereel on 10/8/18. */ +/** + * @author Dmitrii Tikhomirov Created by treblereel on 10/8/18. + */ public class ResourceOracleImpl implements ResourceOracle { private final GenerationContext aptContext; @@ -51,7 +53,7 @@ private URL[] getResourcesByExtensions(ExecutableElement method, String[] extens } @Override - public URL[] findResources(CharSequence packageName, CharSequence[] pathName) { + public URL[] findResources(String packageName, String[] pathName) { List result = new ArrayList<>(); for (int i = 0; i < pathName.length; i++) { URL resource = findResource(packageName, pathName[i]); @@ -78,11 +80,15 @@ public URL[] findResources(CharSequence packageName, CharSequence[] pathName) { * org/gwtproject/uibinder/example/view/SimpleFormView.ui.xml * * @return FileObject or null if file is not found. - * * @see #findResource(CharSequence, CharSequence) */ @Override - public URL findResource(CharSequence path) { + public URL findResource(String path) { + + URL resource = getUrlClassLoader(path); + if (resource != null) + return resource; + String packageName = ""; String relativeName = path.toString(); @@ -110,7 +116,11 @@ public URL findResource(CharSequence path) { * @return FileObject or null if file is not found. */ @Override - public URL findResource(CharSequence pkg, CharSequence relativeName) { + public URL findResource(String pkg, String relativeName) { + URL resource = getUrlClassLoader(pkg.replaceAll("\\.", "/") + relativeName); + if (resource != null) + return resource; + return findResource(Arrays.asList(StandardLocation.SOURCE_PATH, StandardLocation.SOURCE_OUTPUT, StandardLocation.CLASS_PATH, StandardLocation.CLASS_OUTPUT, StandardLocation.ANNOTATION_PROCESSOR_PATH), pkg, relativeName); @@ -152,7 +162,16 @@ private URL findResource(List searchLocations, CharSequence pkg, // ignored } } - // unable to locate, return null. + + return null; + } + + private URL getUrlClassLoader(String path) { + ClassLoader classLoader = getClass().getClassLoader(); + URL resource = classLoader.getResource(path); + if (resource != null) { + return resource; + } return null; } } diff --git a/processor/src/main/java/io/crysknife/generator/definition/BeanDefinition.java b/processor/src/main/java/io/crysknife/generator/definition/BeanDefinition.java deleted file mode 100644 index f6732f1b..00000000 --- a/processor/src/main/java/io/crysknife/generator/definition/BeanDefinition.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * 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.generator.definition; - -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Qualifier; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.util.Elements; -import javax.tools.Diagnostic; - -import com.github.javaparser.ast.expr.Expression; -import com.github.javaparser.ast.expr.ObjectCreationExpr; -import com.github.javaparser.ast.type.ClassOrInterfaceType; -import com.google.auto.common.MoreElements; -import com.google.auto.common.MoreTypes; -import io.crysknife.exception.GenerationException; -import io.crysknife.generator.BeanIOCGenerator; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.api.ClassBuilder; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.point.ConstructorPoint; -import io.crysknife.generator.point.FieldPoint; -import io.crysknife.util.Utils; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 2/20/19 - */ -public class BeanDefinition extends Definition { - - protected List fieldInjectionPoints = new LinkedList<>(); - protected ConstructorPoint constructorInjectionPoint; - protected String className; - protected String classFactoryName; - protected String packageName; - protected String qualifiedName; - protected TypeElement element; - protected Set types = new HashSet<>(); - - protected BeanDefinition(TypeElement element) { - this.element = element; - this.className = element.getSimpleName().toString(); - this.classFactoryName = Utils.getFactoryClassName(element); - this.packageName = Utils.getPackageName(element); - this.qualifiedName = Utils.getQualifiedName(element); - } - - public static BeanDefinition of(TypeElement element, IOCContext context) { - if (context.getBeans().containsKey(element)) { - return context.getBeans().get(element); - } - return new BeanDefinitionBuilder(element, context).build(); - } - - public void addExecutableDefinition(IOCGenerator generator, ExecutableDefinition definition) { - if (!executableDefinitions.containsKey(generator)) { - executableDefinitions.put(generator, new HashSet<>()); - } - executableDefinitions.get(generator).add(definition); - } - - public void setGenerator(IOCGenerator iocGenerator) { - if (iocGenerator == null) { - throw new GenerationException("Unable to set generator for " + this.toString()); - } else { - this.generator = Optional.of(iocGenerator); - } - } - - public void generateDecorators(ClassBuilder builder) { - super.generateDecorators(builder); - - executableDefinitions.forEach((gen, defs) -> defs.forEach(def -> { - gen.generateBeanFactory(builder, def); - })); - } - - public Expression generateBeanCall(IOCContext context, ClassBuilder builder, - FieldPoint fieldPoint) { - if (generator.isPresent()) { - IOCGenerator iocGenerator = generator.get(); - return ((BeanIOCGenerator) iocGenerator).generateBeanCall(builder, fieldPoint, this); - } else { - if (maybeProcessableAsCommonBean(fieldPoint.getType())) { - // we ll use direct object construction, lets ignore factory creation - context.getBlacklist().add(fieldPoint.getType().getQualifiedName().toString()); - context.getGenerationContext().getProcessingEnvironment().getMessager().printMessage( - Diagnostic.Kind.WARNING, - String.format( - "Unable to determine bean type for %s, it will be processed as common bean ", - fieldPoint.getType().getQualifiedName().toString())); - return new ObjectCreationExpr().setType( - new ClassOrInterfaceType().setName(fieldPoint.getType().getQualifiedName().toString())); - } else if (fieldPoint.isNamed()) { - TypeElement named = context.getQualifiers().get(element).get(fieldPoint.getNamed()).element; - return context.getBean(named).generateBeanCall(context, builder, fieldPoint); - } - throw new GenerationException("Unable to find generator for " + fieldPoint.getField() + " at " - + fieldPoint.getEnclosingElement()); - } - } - - private boolean maybeProcessableAsCommonBean(TypeElement candidate) { - if (candidate.getKind().isClass() && !candidate.getModifiers().contains(Modifier.ABSTRACT) - && candidate.getModifiers().contains(Modifier.PUBLIC)) { - long count = candidate.getEnclosedElements().stream() - .filter(elm -> elm.getKind().equals(ElementKind.CONSTRUCTOR)) - .filter(elm -> MoreElements.asExecutable(elm).getParameters().isEmpty()) - .filter(elm -> elm.getModifiers().contains(Modifier.PUBLIC)).count(); - if (count == 1) { - return true; - } - } - return false; - } - - public void processInjections(IOCContext context) { - Elements elements = context.getGenerationContext().getElements(); - elements.getAllMembers(element).forEach(mem -> { - if (mem.getAnnotation(Inject.class) != null && (mem.getKind().equals(ElementKind.CONSTRUCTOR) - || mem.getKind().equals(ElementKind.FIELD))) { - if (mem.getModifiers().contains(Modifier.STATIC)) { - throw new GenerationException( - String.format("Field [%s] in [%s] must not be STATIC \n", mem, getQualifiedName())); - } - if (mem.getKind().equals(ElementKind.CONSTRUCTOR)) { - ExecutableElement elms = MoreElements.asExecutable(mem); - constructorInjectionPoint = - new ConstructorPoint(element.getQualifiedName().toString(), element); - - for (int i = 0; i < elms.getParameters().size(); i++) { - FieldPoint field = parseField(elms.getParameters().get(i), context); - constructorInjectionPoint.addArgument(field); - } - } else if (mem.getKind().equals(ElementKind.FIELD)) { - FieldPoint fiend = parseField(mem, context); - fieldInjectionPoints.add(fiend); - } - } - }); - } - - public String getQualifiedName() { - return qualifiedName; - } - - // TODO refactoring needed here - private FieldPoint parseField(Element type, IOCContext context) { - - FieldPoint field = FieldPoint.of(MoreElements.asVariable(type)); - BeanDefinition bean = null; - - if (field.isNamed()) { - context.getTypeElementsByAnnotation(Named.class.getCanonicalName()).stream() - .filter(named -> named.getAnnotation(Named.class).value().equals(field.getNamed())) - .findAny() - .ifPresent(elm -> getDependsOn().add(context.getBeanDefinitionOrCreateAndReturn(elm))); - bean = context.getBeanDefinitionOrCreateAndReturn(field.getType()); - } else if (context.getQualifiers().containsKey(field.getType())) { - // TODO what if type has several qualifiers ??? - for (AnnotationMirror mirror : context.getGenerationContext().getElements() - .getAllAnnotationMirrors(type)) { - DeclaredType annotationType = mirror.getAnnotationType(); - Qualifier qualifier = annotationType.asElement().getAnnotation(Qualifier.class); - // exclude all annotations, except Qualifiers - if (qualifier != null) { - bean = context.getQualifiers().get(field.getType()) - .get(mirror.getAnnotationType().toString()); - break; - } - } - } else { - bean = context.getBeanDefinitionOrCreateAndReturn(field.getType()); - } - - if (bean != null) { - dependsOn.add(bean); - field.setType(bean.getType()); - } - return field; - } - - public Set getDependsOn() { - return dependsOn; - } - - public TypeElement getType() { - return element; - } - - @Override - public int hashCode() { - return Objects.hash(Utils.getQualifiedName(element)); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - BeanDefinition that = (BeanDefinition) o; - return Objects.equals(Utils.getQualifiedName(element), Utils.getQualifiedName(that.element)); - } - - @Override - public String toString() { - return "BeanDefinition {" + " generator = [ " - + (generator.isPresent() ? generator.get().getClass().getCanonicalName() : "") + " ]" - + " ] , element= [" + element + " ] , dependsOn= [ " - + dependsOn.stream().map(m -> Utils.getQualifiedName(m.element)) - .collect(Collectors.joining(", ")) - + " ] , executables= [ " + executableDefinitions.values().stream().map(Object::toString) - .collect(Collectors.joining(", ")) - + " ]}"; - } - - public String getClassName() { - return className; - } - - public String getPackageName() { - return packageName; - } - - public Map> getExecutableDefinitions() { - return executableDefinitions; - } - - public String getClassFactoryName() { - return classFactoryName; - } - - public List getFieldInjectionPoints() { - return fieldInjectionPoints; - } - - public Set getDeclaredTypes() { - return types; - } - - public ConstructorPoint getConstructorInjectionPoint() { - return constructorInjectionPoint; - } - - public void setConstructorInjectionPoint(ConstructorPoint constructorInjectionPoint) { - this.constructorInjectionPoint = constructorInjectionPoint; - } - - private static class BeanDefinitionBuilder { - - private BeanDefinition beanDefinition; - - private IOCContext context; - - BeanDefinitionBuilder(TypeElement element, IOCContext context) { - this.context = context; - this.beanDefinition = new BeanDefinition(element); - } - - public BeanDefinition build() { - return beanDefinition; - } - } -} diff --git a/processor/src/main/java/io/crysknife/generator/definition/Definition.java b/processor/src/main/java/io/crysknife/generator/definition/Definition.java deleted file mode 100644 index 7a71ccd7..00000000 --- a/processor/src/main/java/io/crysknife/generator/definition/Definition.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.generator.definition; - -import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.crysknife.annotation.Generator; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.api.ClassBuilder; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/3/19 - */ -public abstract class Definition { - - public static final Comparator iocGeneratorComparator = - Comparator.comparing(h -> h.getClass().getAnnotation(Generator.class).priority()); - - protected final Map> executableDefinitions = - new HashMap<>(); - - protected Set dependsOn = new LinkedHashSet<>(); - - protected Optional generator = Optional.empty(); - - protected Map decorators = new HashMap<>(); - - public void setGenerator(IOCGenerator generator) { - this.generator = Optional.of(generator); - } - - public void generate(ClassBuilder classBuilder) { - if (generator.isPresent()) { - generator.get().generateBeanFactory(classBuilder, this); - } - } - - public void generateDecorators(ClassBuilder builder) { - decorators.keySet().stream().sorted(iocGeneratorComparator) - .forEach(decorator -> (decorator).generateBeanFactory(builder, this)); - } - - public T addDecorator(IOCGenerator generator, Definition definition) { - decorators.put(generator, definition); - return (T) this; - } -} diff --git a/processor/src/main/java/io/crysknife/generator/definition/ExecutableDefinition.java b/processor/src/main/java/io/crysknife/generator/definition/ExecutableDefinition.java deleted file mode 100644 index 9fd928ea..00000000 --- a/processor/src/main/java/io/crysknife/generator/definition/ExecutableDefinition.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.generator.definition; - -import java.util.Objects; - -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/3/19 - */ -public class ExecutableDefinition extends Definition { - - private final ExecutableElement executableElement; - - private final TypeElement enclosingElement; - - private ExecutableDefinition(ExecutableElement executableElement, TypeElement enclosingElement) { - this.executableElement = executableElement; - this.enclosingElement = enclosingElement; - } - - public static ExecutableDefinition of(ExecutableElement executableElement, - TypeElement enclosingElement) { - return new ExecutableDefinition(executableElement, enclosingElement); - } - - @Override - public String toString() { - return "ExecutableDefinition{" + "executableElement=" + executableElement + " generator = [ " - + (generator.isPresent() ? generator.get().getClass().getCanonicalName() : "") + " ]" + '}'; - } - - public ExecutableElement getExecutableElement() { - return executableElement; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ExecutableDefinition that = (ExecutableDefinition) o; - return Objects.equals(executableElement, that.executableElement) - && Objects.equals(enclosingElement, that.enclosingElement); - } - - @Override - public int hashCode() { - return Objects.hash(executableElement, enclosingElement); - } -} diff --git a/processor/src/main/java/io/crysknife/generator/definition/ProducerDefinition.java b/processor/src/main/java/io/crysknife/generator/definition/ProducerDefinition.java deleted file mode 100644 index f32cd2c9..00000000 --- a/processor/src/main/java/io/crysknife/generator/definition/ProducerDefinition.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.generator.definition; - -import java.util.Objects; - -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; - -import com.google.auto.common.MoreElements; -import com.google.auto.common.MoreTypes; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/4/19 - */ -public class ProducerDefinition extends BeanDefinition { - - private final ExecutableElement method; - - private final TypeElement producer; - - private ProducerDefinition(ExecutableElement method, TypeElement producer) { - super(MoreElements.asType(MoreTypes.asElement(method.getReturnType()))); - this.method = method; - this.producer = producer; - } - - public static ProducerDefinition of(ExecutableElement method, TypeElement producer) { - return new ProducerDefinition(method, producer); - } - - @Override - public String toString() { - return "ProducerDefinition{" + " produces= " + element + " , producer= " + producer - + " , method= " + method + " , generator = " - + (generator.isPresent() ? generator.get().getClass().getSimpleName() : "") + '}'; - } - - public ExecutableElement getMethod() { - return method; - } - - public TypeElement getInstance() { - return producer; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ProducerDefinition that = (ProducerDefinition) o; - return Objects.equals(method, that.method) && Objects.equals(producer, that.producer); - } - - @Override - public int hashCode() { - return Objects.hash(method, producer); - } -} diff --git a/processor/src/main/java/io/crysknife/generator/info/AbstractBeanInfoGenerator.java b/processor/src/main/java/io/crysknife/generator/info/AbstractBeanInfoGenerator.java index b314d74b..dcc9bce7 100644 --- a/processor/src/main/java/io/crysknife/generator/info/AbstractBeanInfoGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/info/AbstractBeanInfoGenerator.java @@ -17,7 +17,7 @@ import java.io.IOException; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; +import io.crysknife.definition.BeanDefinition; /** * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 diff --git a/processor/src/main/java/io/crysknife/generator/info/BeanInfoGWT2GeneratorBuilder.java b/processor/src/main/java/io/crysknife/generator/info/BeanInfoGWT2GeneratorBuilder.java index 9b59dab8..2005b839 100644 --- a/processor/src/main/java/io/crysknife/generator/info/BeanInfoGWT2GeneratorBuilder.java +++ b/processor/src/main/java/io/crysknife/generator/info/BeanInfoGWT2GeneratorBuilder.java @@ -14,11 +14,13 @@ package io.crysknife.generator.info; -import java.io.IOException; - +import com.google.auto.common.MoreTypes; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.InjectableVariableDefinition; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.point.FieldPoint; +import io.crysknife.util.Utils; + +import java.io.IOException; /** * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 @@ -43,13 +45,18 @@ protected String build(BeanDefinition bean) throws IOException { } private void initClass() { - clazz.append("package ").append(bean.getPackageName()).append(";"); + String clazzName = MoreTypes.asTypeElement(bean.getType()).getSimpleName().toString(); + String pkg = Utils.getPackageName(MoreTypes.asTypeElement(bean.getType())); + + + clazz.append("package ").append(clazzName).append(";"); clazz.append(newLine); - clazz.append("class ").append(bean.getClassName()).append("Info").append(" {"); + clazz.append("class ").append(pkg).append("Info").append(" {"); } + private void addFields() { - for (FieldPoint fieldPoint : bean.getFieldInjectionPoints()) { + for (InjectableVariableDefinition fieldPoint : bean.getFields()) { clazz.append(newLine); makeSetter(fieldPoint); clazz.append(newLine); @@ -57,28 +64,35 @@ private void addFields() { } } - private void makeSetter(FieldPoint fieldPoint) { - clazz.append("static native void ").append(fieldPoint.getName()).append("("); - clazz.append(bean.getClassName()).append(" ").append(" instance").append(","); + private void makeSetter(InjectableVariableDefinition fieldPoint) { + clazz.append("static native void ").append(fieldPoint.getVariableElement().getSimpleName()) + .append("("); + clazz.append(MoreTypes.asTypeElement(bean.getType()).getQualifiedName()).append(" ") + .append(" instance").append(","); clazz.append("Object").append(" ").append(" value").append(")/*-{"); clazz.append(newLine); - clazz.append(" ").append("instance.@").append(bean.getQualifiedName()).append("::") - .append(fieldPoint.getName()).append("=").append("value;"); + clazz.append(" ").append("instance.@").append(bean.getQualifiedName()).append("::") + .append(fieldPoint.getVariableElement().getSimpleName()).append("=").append("value;"); clazz.append(newLine).append("}-*/;"); } - private void makeGetter(FieldPoint fieldPoint) { - clazz.append("static native ").append(fieldPoint.getType().getQualifiedName().toString()) - .append(" ").append(fieldPoint.getName()).append("("); - clazz.append(bean.getClassName()).append(" ").append(" instance"); + private void makeGetter(InjectableVariableDefinition fieldPoint) { + clazz.append("static native ") + .append( + MoreTypes.asTypeElement(fieldPoint.getVariableElement().asType()).getQualifiedName()) + .append(" ").append(fieldPoint.getVariableElement().getSimpleName()).append("("); + clazz.append(MoreTypes.asTypeElement(bean.getType()).getQualifiedName().toString()).append(" ") + .append(" instance"); clazz.append(")/*-{"); clazz.append(newLine); - clazz.append(" ").append("return instance.@").append(bean.getQualifiedName()).append("::") - .append(fieldPoint.getName()).append(";"); + clazz.append(" ").append("return instance.@").append(bean.getQualifiedName()).append("::") + .append(fieldPoint.getVariableElement().getSimpleName()).append(";"); clazz.append(newLine).append("}-*/;"); } + + } diff --git a/processor/src/main/java/io/crysknife/generator/info/BeanInfoGenerator.java b/processor/src/main/java/io/crysknife/generator/info/BeanInfoGenerator.java index 060878b3..0e2c68c5 100644 --- a/processor/src/main/java/io/crysknife/generator/info/BeanInfoGenerator.java +++ b/processor/src/main/java/io/crysknife/generator/info/BeanInfoGenerator.java @@ -14,21 +14,21 @@ package io.crysknife.generator.info; -import java.io.IOException; -import java.io.PrintWriter; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.task.Task; import javax.tools.JavaFileObject; - -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; +import java.io.IOException; +import java.io.PrintWriter; /** * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 */ -public class BeanInfoGenerator { +public class BeanInfoGenerator implements Task { private IOCContext iocContext; - private AbstractBeanInfoGenerator generator; public BeanInfoGenerator(IOCContext iocContext) { @@ -42,10 +42,12 @@ public BeanInfoGenerator(IOCContext iocContext) { } } - public void generate() { + public void execute() throws UnableToCompleteException { iocContext.getBeans().forEach((k, bean) -> { try { generate(bean); + } catch (javax.annotation.processing.FilerException e) { + // Attempt to recreate a file for type } catch (IOException e) { throw new Error(e); } @@ -53,7 +55,7 @@ public void generate() { } private void generate(BeanDefinition bean) throws IOException { - if (!bean.getFieldInjectionPoints().isEmpty()) { + if (!bean.getFields().isEmpty()) { JavaFileObject builderFile = iocContext.getGenerationContext().getProcessingEnvironment() .getFiler().createSourceFile(bean.getQualifiedName() + "Info"); try (PrintWriter out = new PrintWriter(builderFile.openWriter())) { diff --git a/processor/src/main/java/io/crysknife/generator/info/BeanInfoJ2CLGeneratorBuilder.java b/processor/src/main/java/io/crysknife/generator/info/BeanInfoJ2CLGeneratorBuilder.java index 294b8f20..cf09e637 100644 --- a/processor/src/main/java/io/crysknife/generator/info/BeanInfoJ2CLGeneratorBuilder.java +++ b/processor/src/main/java/io/crysknife/generator/info/BeanInfoJ2CLGeneratorBuilder.java @@ -18,10 +18,11 @@ import com.github.javaparser.ast.Modifier; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.expr.StringLiteralExpr; +import com.google.auto.common.MoreTypes; import io.crysknife.client.Reflect; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.InjectableVariableDefinition; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.point.FieldPoint; import io.crysknife.util.Utils; /** @@ -47,16 +48,23 @@ protected String build(BeanDefinition bean) { } private void initClass() { - clazz.setPackageDeclaration(bean.getPackageName()); - classDeclaration = clazz.addClass(bean.getClassName() + "Info"); + String clazzName = MoreTypes.asTypeElement(bean.getType()).getSimpleName().toString(); + String pkg = Utils.getPackageName(MoreTypes.asTypeElement(bean.getType())); + + + clazz.setPackageDeclaration(pkg); + classDeclaration = clazz.addClass(clazzName + "Info"); clazz.addImport(Reflect.class); } private void addFields() { - for (FieldPoint fieldPoint : bean.getFieldInjectionPoints()) { - classDeclaration.addFieldWithInitializer(String.class, fieldPoint.getName(), - new StringLiteralExpr(Utils.getJsFieldName(fieldPoint.getField())), + + for (InjectableVariableDefinition fieldPoint : bean.getFields()) { + classDeclaration.addFieldWithInitializer(String.class, + fieldPoint.getVariableElement().getSimpleName().toString(), + new StringLiteralExpr(Utils.getJsFieldName(fieldPoint.getVariableElement())), Modifier.Keyword.PUBLIC, Modifier.Keyword.FINAL, Modifier.Keyword.STATIC); } + } } diff --git a/processor/src/main/java/io/crysknife/generator/info/BeanInfoJREGeneratorBuilder.java b/processor/src/main/java/io/crysknife/generator/info/BeanInfoJREGeneratorBuilder.java index dd691662..ba49344b 100644 --- a/processor/src/main/java/io/crysknife/generator/info/BeanInfoJREGeneratorBuilder.java +++ b/processor/src/main/java/io/crysknife/generator/info/BeanInfoJREGeneratorBuilder.java @@ -14,18 +14,13 @@ package io.crysknife.generator.info; -import java.lang.reflect.Field; -import java.util.function.Supplier; - -import javax.lang.model.element.TypeElement; - import com.github.javaparser.ast.Modifier; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.expr.AssignExpr; import com.github.javaparser.ast.expr.BinaryExpr; +import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.FieldAccessExpr; -import com.github.javaparser.ast.expr.LambdaExpr; import com.github.javaparser.ast.expr.MemberValuePair; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.Name; @@ -37,17 +32,26 @@ import com.github.javaparser.ast.expr.VariableDeclarationExpr; import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.stmt.CatchClause; -import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.github.javaparser.ast.stmt.ForEachStmt; import com.github.javaparser.ast.stmt.IfStmt; import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.ast.stmt.ThrowStmt; import com.github.javaparser.ast.stmt.TryStmt; import com.github.javaparser.ast.type.ClassOrInterfaceType; -import io.crysknife.client.Instance; +import com.google.auto.common.MoreElements; +import com.google.auto.common.MoreTypes; +import io.crysknife.client.BeanManager; +import io.crysknife.definition.InjectableVariableDefinition; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.point.FieldPoint; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.util.GenerationUtils; +import io.crysknife.util.Utils; +import org.apache.commons.lang3.reflect.FieldUtils; + +import javax.enterprise.inject.Instance; +import java.lang.reflect.Field; +import java.util.function.Supplier; /** * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 @@ -56,9 +60,11 @@ public class BeanInfoJREGeneratorBuilder extends AbstractBeanInfoGenerator { private BeanDefinition bean; private ClassBuilder classBuilder; + private GenerationUtils generationUtils; BeanInfoJREGeneratorBuilder(IOCContext iocContext) { super(iocContext); + this.generationUtils = new GenerationUtils(iocContext); } @Override @@ -68,145 +74,215 @@ protected String build(BeanDefinition bean) { initClass(); addFields(); addOnInvoke(); + addGetField(); return classBuilder.toSourceCode(); } private void initClass() { - classBuilder.setClassName(bean.getClassName() + "Info"); - classBuilder.getClassCompilationUnit().setPackageDeclaration(bean.getPackageName()); + + classBuilder + .setClassName(MoreTypes.asTypeElement(bean.getType()).getSimpleName().toString() + "Info"); + classBuilder.getClassCompilationUnit() + .setPackageDeclaration(Utils.getPackageName(MoreTypes.asTypeElement(bean.getType()))); classBuilder.getClassDeclaration().getAnnotations() .add(new NormalAnnotationExpr().setName(new Name("Aspect"))); - classBuilder.getClassCompilationUnit().addImport("org.aspectj.lang.ProceedingJoinPoint"); - classBuilder.getClassCompilationUnit().addImport("org.aspectj.lang.annotation.Around"); + classBuilder.getClassCompilationUnit().addImport("org.aspectj.lang.JoinPoint"); + classBuilder.getClassCompilationUnit().addImport("org.aspectj.lang.annotation.Before"); classBuilder.getClassCompilationUnit().addImport("org.aspectj.lang.annotation.Aspect"); classBuilder.getClassCompilationUnit().addImport("io.crysknife.client.BeanManagerImpl"); classBuilder.getClassCompilationUnit().addImport(Field.class); classBuilder.getClassCompilationUnit().addImport(Supplier.class); + classBuilder.getClassCompilationUnit().addImport(FieldUtils.class); classBuilder.getClassCompilationUnit().addImport(Instance.class); + classBuilder.getClassCompilationUnit().addImport(BeanManager.class); + + classBuilder.addFieldWithInitializer(BeanManager.class.getSimpleName(), "beanManager", + new MethodCallExpr(new NameExpr(BeanManager.class.getCanonicalName() + "Impl"), "get"), + Modifier.Keyword.PRIVATE, Modifier.Keyword.FINAL); } private void addFields() { - for (FieldPoint fieldPoint : bean.getFieldInjectionPoints()) { - generateFactoryFieldDeclaration(fieldPoint); + + for (InjectableVariableDefinition fieldPoint : bean.getFields()) { + String methodName = + fieldPoint.getVariableElement().getEnclosingElement().toString().replaceAll("\\.", "_") + + "_" + fieldPoint.getVariableElement().getSimpleName(); + boolean isLocal = isLocal(bean, fieldPoint); + MethodDeclaration methodDeclaration = - classBuilder.addMethod(fieldPoint.getName(), Modifier.Keyword.PUBLIC); - methodDeclaration.setType(Object.class.getSimpleName()); - methodDeclaration.addParameter("ProceedingJoinPoint", "joinPoint"); - methodDeclaration.addThrownException(Throwable.class); + classBuilder.addMethod(methodName, Modifier.Keyword.PUBLIC); + methodDeclaration.addParameter("JoinPoint", "joinPoint"); + methodDeclaration.addThrownException(NoSuchFieldException.class); + methodDeclaration.addThrownException(IllegalAccessException.class); NormalAnnotationExpr annotationExpr = new NormalAnnotationExpr(); - annotationExpr.setName(new Name("Around")); - annotationExpr.getPairs().add( - new MemberValuePair().setName("value").setValue(getAnnotationValue(bean, fieldPoint))); + annotationExpr.setName(new Name("Before")); + annotationExpr.getPairs() + .add(new MemberValuePair().setName("value").setValue(getAnnotationValue(fieldPoint))); methodDeclaration.addAnnotation(annotationExpr); + Expression _beanCall; + if (fieldPoint.getImplementation().isPresent() + && fieldPoint.getImplementation().get().getIocGenerator().isPresent()) { + _beanCall = fieldPoint.getImplementation().get().getIocGenerator().get() + .generateBeanLookupCall(classBuilder, fieldPoint); + } else if (fieldPoint.getGenerator().isPresent()) { + _beanCall = + fieldPoint.getGenerator().get().generateBeanLookupCall(classBuilder, fieldPoint); + } else { + String name = generationUtils.getActualQualifiedBeanName(fieldPoint); + _beanCall = new MethodCallExpr(new NameExpr("beanManager"), "lookupBean") + .addArgument(new FieldAccessExpr(new NameExpr(name), "class")); + } + + Expression beanCall = new MethodCallExpr(_beanCall, "getInstance"); + + ThrowStmt throwStmt = new ThrowStmt(new ObjectCreationExpr() + .setType(new ClassOrInterfaceType().setName("Error")).addArgument("e")); + + TryStmt ts = new TryStmt(); + BlockStmt blockStmt = new BlockStmt(); + + blockStmt.addAndGetStatement(new AssignExpr() + .setTarget(new VariableDeclarationExpr( + new ClassOrInterfaceType().setName(String.class.getSimpleName()), "fieldName")) + .setValue( + new StringLiteralExpr(fieldPoint.getVariableElement().getSimpleName().toString()))); + + blockStmt.addAndGetStatement(new AssignExpr() + .setTarget(new VariableDeclarationExpr( + new ClassOrInterfaceType().setName(Field.class.getSimpleName()), "field")) + .setValue(new MethodCallExpr("getField") + .addArgument(new MethodCallExpr( + new MethodCallExpr(new NameExpr("joinPoint"), "getTarget"), "getClass")) + .addArgument(new NameExpr("fieldName")))); + + blockStmt.addAndGetStatement(new MethodCallExpr("onInvoke").addArgument("joinPoint") + .addArgument("field").addArgument(beanCall)); + + CatchClause catchClause1 = new CatchClause().setParameter(new Parameter() + .setType(new ClassOrInterfaceType().setName("NoSuchFieldException")).setName("e")); + catchClause1.getBody().addAndGetStatement(throwStmt); + + CatchClause catchClause2 = new CatchClause().setParameter(new Parameter() + .setType(new ClassOrInterfaceType().setName("IllegalAccessException")).setName("e")); + catchClause2.getBody().addAndGetStatement(throwStmt); + + ts.getCatchClauses().add(catchClause1); + ts.getCatchClauses().add(catchClause2); + + ts.setTryBlock(blockStmt); + methodDeclaration.getBody().ifPresent(body -> { - body.addAndGetStatement(new ReturnStmt(new MethodCallExpr("onInvoke") - .addArgument("joinPoint").addArgument(new StringLiteralExpr(fieldPoint.getName())) - .addArgument(new MethodCallExpr(new NameExpr(fieldPoint.getName()), "get")))); + body.addAndGetStatement(ts); }); } } + private boolean isLocal(BeanDefinition bean, InjectableVariableDefinition fieldPoint) { + return bean.getType() + .equals(MoreElements.asType(fieldPoint.getVariableElement().getEnclosingElement())); + } + + private StringLiteralExpr getAnnotationValue(InjectableVariableDefinition fieldPoint) { + StringBuffer sb = new StringBuffer(); + sb.append("get(").append("*").append(" ") + .append(fieldPoint.getVariableElement().getEnclosingElement()).append(".") + .append(fieldPoint.getVariableElement().getSimpleName()).append(")"); + return new StringLiteralExpr(sb.toString()); + } + private void addOnInvoke() { MethodDeclaration methodDeclaration = classBuilder.addMethod("onInvoke", Modifier.Keyword.PRIVATE); - methodDeclaration.setType(Object.class.getSimpleName()); - methodDeclaration.addParameter("ProceedingJoinPoint", "joinPoint"); - methodDeclaration.addParameter("String", "fieldName"); - methodDeclaration.addParameter("Instance", "instance"); - methodDeclaration.addThrownException(Throwable.class); + methodDeclaration.addParameter("JoinPoint", "joinPoint"); + methodDeclaration.addParameter("Field", "field"); + methodDeclaration.addParameter("Object", "instance"); - methodDeclaration.getBody().ifPresent(body -> { - body.addAndGetStatement(new VariableDeclarationExpr( - new ClassOrInterfaceType().setName(Field.class.getSimpleName()), "field")); - TryStmt ts = new TryStmt(); - body.addAndGetStatement(ts); - BlockStmt blockStmt = new BlockStmt(); - ts.setTryBlock(blockStmt); - - blockStmt.addAndGetStatement(new AssignExpr().setTarget(new NameExpr("field")) - .setValue(new MethodCallExpr( - new MethodCallExpr(new MethodCallExpr(new NameExpr("joinPoint"), "getTarget"), - "getClass"), - "getDeclaredField").addArgument(new NameExpr("fieldName")))); - ThrowStmt throwStmt = new ThrowStmt(new ObjectCreationExpr() - .setType(new ClassOrInterfaceType().setName("Error")).addArgument("e")); - CatchClause catchClause = new CatchClause().setParameter(new Parameter() - .setType(new ClassOrInterfaceType().setName("NoSuchFieldException")).setName("e")); - catchClause.getBody().addAndGetStatement(throwStmt); - ts.getCatchClauses().add(catchClause); + methodDeclaration.addThrownException(NoSuchFieldException.class); + methodDeclaration.addThrownException(IllegalAccessException.class); + methodDeclaration.getBody().ifPresent(body -> { body.addAndGetStatement( new MethodCallExpr(new NameExpr("field"), "setAccessible").addArgument("true")); - IfStmt ifStmt = new IfStmt().setCondition(new BinaryExpr( + BlockStmt thenStmt = new BlockStmt(); + + IfStmt ifStmtLocal = new IfStmt().setCondition(new BinaryExpr( new MethodCallExpr(new NameExpr("field"), "get") .addArgument(new MethodCallExpr(new NameExpr("joinPoint"), "getTarget")), - new NullLiteralExpr(), BinaryExpr.Operator.NOT_EQUALS)); - ifStmt.setThenStmt(new ReturnStmt(new MethodCallExpr(new NameExpr("joinPoint"), "proceed"))); - body.addAndGetStatement(ifStmt); - - ts = new TryStmt(); - body.addAndGetStatement(ts); - blockStmt = new BlockStmt(); - ts.setTryBlock(blockStmt); + new NullLiteralExpr(), BinaryExpr.Operator.EQUALS)).setThenStmt(thenStmt); - blockStmt.addAndGetStatement(new MethodCallExpr(new NameExpr("field"), "set") + thenStmt.addAndGetStatement(new MethodCallExpr(new NameExpr("field"), "set") .addArgument(new MethodCallExpr(new NameExpr("joinPoint"), "getTarget")) - .addArgument(new MethodCallExpr(new NameExpr("instance"), "get"))); - throwStmt = new ThrowStmt(new ObjectCreationExpr() - .setType(new ClassOrInterfaceType().setName("Error")).addArgument("e")); - catchClause = new CatchClause().setParameter(new Parameter() - .setType(new ClassOrInterfaceType().setName("IllegalAccessException")).setName("e")); - catchClause.getBody().addAndGetStatement(throwStmt); - ts.getCatchClauses().add(catchClause); - - body.addAndGetStatement( - new ReturnStmt(new MethodCallExpr(new NameExpr("joinPoint"), "proceed"))); + .addArgument(new NameExpr("instance"))); + body.addAndGetStatement(ifStmtLocal); }); } - private void generateFactoryFieldDeclaration(FieldPoint fieldPoint) { - ClassOrInterfaceType supplier = - new ClassOrInterfaceType().setName(Supplier.class.getSimpleName()); + private void addGetField() { - ClassOrInterfaceType type = new ClassOrInterfaceType(); - type.setName(Instance.class.getSimpleName()); - type.setTypeArguments( - new ClassOrInterfaceType().setName(fieldPoint.getType().getQualifiedName().toString())); - supplier.setTypeArguments(type); + MethodDeclaration methodDeclaration = + classBuilder.addMethod("getField", Modifier.Keyword.PRIVATE); + methodDeclaration.addParameter("Class", "clazz"); + methodDeclaration.addParameter("String", "name"); + methodDeclaration.setType(Field.class); - ClassOrInterfaceType beanManager = new ClassOrInterfaceType().setName("BeanManagerImpl"); - MethodCallExpr callForBeanManagerImpl = - new MethodCallExpr(beanManager.getNameAsExpression(), "get"); + methodDeclaration.getBody().ifPresent(body -> { - TypeElement typeElement; - if (fieldPoint.isNamed()) { - typeElement = - iocContext.getQualifiers().get(fieldPoint.getType()).get(fieldPoint.getNamed()).getType(); - } else { - typeElement = fieldPoint.getType(); - } + ClassOrInterfaceType consumerClassDecloration = + new ClassOrInterfaceType().setName(Field.class.getCanonicalName()); + VariableDeclarationExpr variableDeclarationExpr = + new VariableDeclarationExpr(consumerClassDecloration, "field"); - MethodCallExpr callForProducer = - new MethodCallExpr(callForBeanManagerImpl, "lookupBean").addArgument( - new FieldAccessExpr(new NameExpr(typeElement.getQualifiedName().toString()), "class")); - LambdaExpr lambda = new LambdaExpr().setEnclosingParameters(true); - lambda.setBody(new ExpressionStmt(callForProducer)); + ForEachStmt forStmt = new ForEachStmt(); + forStmt.setVariable(variableDeclarationExpr); + forStmt.setIterable( + new MethodCallExpr(new NameExpr("FieldUtils"), "getAllFields").addArgument("clazz")); - classBuilder.addFieldWithInitializer(supplier, fieldPoint.getName(), lambda, - Modifier.Keyword.PRIVATE); - } + IfStmt ifStmt = new IfStmt().setCondition( + new MethodCallExpr(new MethodCallExpr(new NameExpr("field"), "getName"), "equals") + .addArgument("name")); + ifStmt.setThenStmt(new BlockStmt().addAndGetStatement(new ReturnStmt(new NameExpr("field")))); + + BlockStmt blockStmt = new BlockStmt(); + blockStmt.addAndGetStatement(ifStmt); + + forStmt.setBody(blockStmt); + + body.addAndGetStatement(forStmt); + + /* + * TryStmt ts = new TryStmt(); BlockStmt blockStmt = new BlockStmt(); + * ts.setTryBlock(blockStmt); + * + * blockStmt.addAndGetStatement(new ReturnStmt( new MethodCallExpr(new NameExpr("clazz"), + * "getField").addArgument("name"))); + * + * CatchClause catchClause1 = new CatchClause().setParameter(new Parameter() .setType(new + * ClassOrInterfaceType().setName("NoSuchFieldException")).setName("e")); + * ts.getCatchClauses().add(catchClause1); body.addAndGetStatement(ts); + * + * TryStmt ts1 = new TryStmt(); BlockStmt blockStmt1 = new BlockStmt(); + * ts1.setTryBlock(blockStmt1); + * + * blockStmt1.addAndGetStatement(new ReturnStmt( new MethodCallExpr(new NameExpr("clazz"), + * "getDeclaredField").addArgument("name"))); + * + * CatchClause catchClause2 = new CatchClause().setParameter(new Parameter() .setType(new + * ClassOrInterfaceType().setName("NoSuchFieldException")).setName("e")); + * ts1.getCatchClauses().add(catchClause2); body.addAndGetStatement(ts1); + */ + + ThrowStmt throwStmt = new ThrowStmt( + new ObjectCreationExpr().setType(new ClassOrInterfaceType().setName("Error")) + .addArgument("\"Error: no field named '\" + name + \"' at \" + clazz + \" at \"")); + body.addAndGetStatement(throwStmt); + + }); - private StringLiteralExpr getAnnotationValue(BeanDefinition bean, FieldPoint fieldPoint) { - StringBuffer sb = new StringBuffer(); - sb.append("get(").append("*") - // .append(fieldPoint.getType()) - .append(" ").append(bean.getQualifiedName()).append(".").append(fieldPoint.getName()) - .append(")"); - return new StringLiteralExpr(sb.toString()); } + } diff --git a/processor/src/main/java/io/crysknife/generator/point/ConstructorPoint.java b/processor/src/main/java/io/crysknife/generator/point/ConstructorPoint.java deleted file mode 100644 index 1263f2bf..00000000 --- a/processor/src/main/java/io/crysknife/generator/point/ConstructorPoint.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.generator.point; - -import java.util.LinkedList; -import java.util.List; - -import javax.lang.model.element.TypeElement; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/3/19 - */ -public class ConstructorPoint extends Point { - - private final List arguments = new LinkedList<>(); - - public ConstructorPoint(String name, TypeElement type) { - super(type, name); - } - - public void addArgument(FieldPoint arg) { - arguments.add(arg); - } - - public List getArguments() { - return arguments; - } - - @Override - public String toString() { - return "ConstructorPoint{" + "arguments=" + arguments + ", name='" + name + '\'' + ", type=" - + type + '}'; - } -} diff --git a/processor/src/main/java/io/crysknife/generator/point/FieldPoint.java b/processor/src/main/java/io/crysknife/generator/point/FieldPoint.java deleted file mode 100644 index 6445f866..00000000 --- a/processor/src/main/java/io/crysknife/generator/point/FieldPoint.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.generator.point; - -import java.util.Objects; - -import javax.inject.Named; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; - -import com.google.auto.common.MoreElements; -import com.google.auto.common.MoreTypes; -import io.crysknife.annotation.Lazy; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/3/19 - */ -public class FieldPoint extends Point { - - private VariableElement field; - - private boolean isLazy; - - private FieldPoint(String name, TypeElement injection, VariableElement field) { - super(injection, name); - this.field = field; - this.isLazy = field.getAnnotation(Lazy.class) != null; - } - - public static FieldPoint of(VariableElement injection) { - TypeElement type = MoreElements.asType(MoreTypes.asElement(injection.asType())); - return new FieldPoint(injection.getSimpleName().toString(), type, injection); - } - - public VariableElement getField() { - return field; - } - - public TypeElement getEnclosingElement() { - if (field.getEnclosingElement().getKind().isClass()) { - return MoreElements.asType(field.getEnclosingElement()); - } else { - return MoreElements.asType(field.getEnclosingElement().getEnclosingElement()); - } - } - - public boolean isQualified() { - throw new UnsupportedOperationException(); - } - - public String getNamed() { - return field.getAnnotation(Named.class).value(); - } - - @Override - public int hashCode() { - return Objects.hash(type); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - FieldPoint that = (FieldPoint) o; - return Objects.equals(type, that.type); - } - - @Override - public String toString() { - return "FieldPoint{" + "field=" + field + ", name='" + name + '\'' + ", type=" + type - + ", isLazy=" + isLazy + '}'; - } - - public boolean isNamed() { - return field.getAnnotation(Named.class) != null; - } - - public boolean isLazy() { - return isLazy; - } - - public void setLazy(boolean lazy) { - isLazy = lazy; - } -} diff --git a/processor/src/main/java/io/crysknife/generator/scanner/ComponentInjectionResolverScanner.java b/processor/src/main/java/io/crysknife/generator/scanner/ComponentInjectionResolverScanner.java deleted file mode 100644 index 2bdf9934..00000000 --- a/processor/src/main/java/io/crysknife/generator/scanner/ComponentInjectionResolverScanner.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.generator.scanner; - -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.enterprise.context.Dependent; -import javax.enterprise.inject.Default; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.Types; - -import io.crysknife.exception.GenerationException; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.WiringElementType; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.point.FieldPoint; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/5/19 - */ -public class ComponentInjectionResolverScanner { - - private final IOCContext iocContext; - - private Set dependentBeans = new HashSet<>(); - - public ComponentInjectionResolverScanner(IOCContext iocContext) { - this.iocContext = iocContext; - } - - public void scan() { - - Set annotations = iocContext.getGenerators().entries().stream() - .filter(elm -> elm.getKey().wiringElementType.equals(WiringElementType.BEAN)) - .map(elm -> elm.getKey().annotation).collect(Collectors.toSet()); - - annotations.forEach(annotation -> iocContext.getTypeElementsByAnnotation(annotation) - .forEach(bean -> iocContext.getBeanDefinitionOrCreateAndReturn(bean))); - - iocContext.getBeans().forEach((type, bean) -> { - for (FieldPoint field : bean.getFieldInjectionPoints()) { - processFieldInjectionPoint(field, bean); - } - if (bean.getConstructorInjectionPoint() != null) { - bean.getConstructorInjectionPoint().getArguments() - .forEach(field -> processFieldInjectionPoint(field, bean)); - } - }); - - addUnmanagedBeans(); - } - - // Process as Dependent Beans //TODO - private void addUnmanagedBeans() { - TypeElement type = iocContext.getGenerationContext().getElements() - .getTypeElement(Object.class.getCanonicalName()); - - IOCContext.IOCGeneratorMeta meta = new IOCContext.IOCGeneratorMeta( - Dependent.class.getCanonicalName(), type, WiringElementType.BEAN); - - dependentBeans.forEach(bean -> { - BeanDefinition beanDefinition = iocContext.getBeanDefinitionOrCreateAndReturn(bean); - if (iocContext.getGenerators().get(meta).stream().findFirst().isPresent()) { - IOCGenerator gen = iocContext.getGenerators().get(meta).stream().findFirst().get(); - beanDefinition.setGenerator(gen); - iocContext.getBeans().put(bean, beanDefinition); - } else { - throw new GenerationException("Unable to find generator based on meta " + meta.toString()); - } - }); - } - - private void processFieldInjectionPoint(FieldPoint field, BeanDefinition definition) { - BeanDefinition beanDefinition = null; - if (field.isNamed()) { - beanDefinition = iocContext.getBeans().get(field.getType()); - } else if (iocContext.getQualifiers().containsKey(field.getType())) { - beanDefinition = - getTypeQualifierValue(field.getField(), iocContext.getQualifiers().get(field.getType())); - } else if (field.getType().getKind().isInterface()) { - TypeMirror beanType = field.getType().asType(); - Types types = iocContext.getGenerationContext().getTypes(); - Optional result = iocContext.getBeans().keySet().stream() - .filter(bean -> types.isSubtype(bean.asType(), beanType)) - .filter(elm -> elm.getKind().equals(ElementKind.CLASS)).findFirst(); - if (result.isPresent()) { - beanDefinition = iocContext.getBeans().get(result.get()); - } - } - - if (beanDefinition != null) { - definition.getDependsOn().add(beanDefinition); - field.setType(beanDefinition.getType()); - } - if (!iocContext.getBeans().containsKey(field.getType())) { - dependentBeans.add(field.getType()); - } - } - - private BeanDefinition getTypeQualifierValue(VariableElement element, - Map qualifiers) { - - for (AnnotationMirror annotation : iocContext.getGenerationContext().getElements() - .getAllAnnotationMirrors(element)) { - if (qualifiers.containsKey(annotation.toString())) { - return qualifiers.get(annotation.toString()); - } - } - return qualifiers.get(Default.class.getCanonicalName()); - } -} diff --git a/processor/src/main/java/io/crysknife/generator/scanner/ComponentScanner.java b/processor/src/main/java/io/crysknife/generator/scanner/ComponentScanner.java deleted file mode 100644 index 47d8ba6a..00000000 --- a/processor/src/main/java/io/crysknife/generator/scanner/ComponentScanner.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.generator.scanner; - -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; - -import com.google.auto.common.MoreElements; -import io.crysknife.annotation.Generator; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.WiringElementType; -import io.crysknife.generator.context.GenerationContext; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.processor.TypeProcessorFactory; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/2/19 - */ -public class ComponentScanner { - - private final IOCContext iocContext; - private final GenerationContext context; - - public ComponentScanner(IOCContext iocContext, GenerationContext context) { - this.iocContext = iocContext; - this.context = context; - } - - public void scan() { - Map> elements = new HashMap<>(); - - iocContext.getGenerators().keySet().stream() - .sorted(Comparator.comparing(h -> iocContext.getGenerators().get(h).stream().findFirst() - .get().getClass().getAnnotation(Generator.class).priority())) - .forEach(meta -> { - TypeElement annotation = context.getElements().getTypeElement(meta.annotation); - - if (!elements.containsKey(annotation)) { - elements.put(annotation, new HashSet<>()); - } - // TODO replace by suppliers or not :) - if (meta.wiringElementType.equals(WiringElementType.BEAN)) { - elements.get(annotation) - .addAll(iocContext.getTypeElementsByAnnotation(meta.annotation)); - } else if (meta.wiringElementType.equals(WiringElementType.FIELD_TYPE)) { - elements.get(annotation).addAll(iocContext.getFieldsByAnnotation(meta.annotation)); - } else if (meta.wiringElementType.equals(WiringElementType.METHOD_DECORATOR)) { - elements.get(annotation).addAll(iocContext.getMethodsByAnnotation(meta.annotation)); - } else if (meta.wiringElementType.equals(WiringElementType.PRODUCER_ELEMENT)) { - elements.get(annotation).addAll(iocContext.getMethodsByAnnotation(meta.annotation)); - } else if (meta.wiringElementType.equals(WiringElementType.CLASS_DECORATOR)) { - elements.get(annotation) - .addAll(iocContext.getTypeElementsByAnnotation(meta.annotation)); - } else if (meta.wiringElementType.equals(WiringElementType.PARAMETER)) { - elements.get(annotation).addAll(iocContext.getParametersByAnnotation(meta.annotation)); - } - }); - - TypeElement object = iocContext.getGenerationContext().getElements() - .getTypeElement(Object.class.getCanonicalName()); - - // all types - elements - .forEach((annotation, points) -> iocContext.getGenerators().keySet().stream() - .filter(meta -> (meta.annotation.equals(annotation.getQualifiedName().toString()) - && meta.exactType.equals(object))) - .forEach(meta -> points.stream().forEach(point -> { - IOCGenerator generator = - iocContext.getGenerators().get(meta).stream().findFirst().get(); - TypeProcessorFactory.getTypeProcessor(meta, generator, point) - .ifPresent(processor -> processor.process(iocContext, point)); - }))); - - // exactly on type - Set metas = iocContext.getGenerators().keySet().stream() - .filter(meta -> !meta.exactType.equals(object)).collect(Collectors.toSet()); - - metas.forEach(meta -> { - TypeElement annotation = iocContext.getGenerationContext().getProcessingEnvironment() - .getElementUtils().getTypeElement(meta.annotation); - elements.get(annotation).stream() - .filter(e -> (e.getKind().isField() || e.getKind().isClass())) - .filter(elm -> (elm.getKind().isField() ? MoreElements.asVariable(elm).asType() - : elm.asType()).equals(meta.exactType.asType())) - .forEach(elm -> TypeProcessorFactory - .getTypeProcessor(meta, - iocContext.getGenerators().get(meta).stream().findFirst().get(), elm) - .ifPresent(processor -> processor.process(iocContext, elm))); - }); - - } -} diff --git a/processor/src/main/java/io/crysknife/generator/scanner/ProducersScan.java b/processor/src/main/java/io/crysknife/generator/scanner/ProducersScan.java deleted file mode 100644 index 4f549258..00000000 --- a/processor/src/main/java/io/crysknife/generator/scanner/ProducersScan.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.generator.scanner; - -import javax.enterprise.inject.Produces; -import javax.lang.model.element.TypeElement; - -import com.google.auto.common.MoreElements; -import com.google.auto.common.MoreTypes; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/8/20 - */ -public class ProducersScan { - - private IOCContext iocContext; - - public ProducersScan(IOCContext iocContext) { - this.iocContext = iocContext; - } - - public void scan() { - iocContext.getMethodsByAnnotation(Produces.class.getCanonicalName()).forEach(producer -> { - TypeElement parent = MoreElements.asType(producer.getEnclosingElement()); - TypeElement target = MoreTypes.asTypeElement(producer.getReturnType()); - BeanDefinition targetBeanDefinition = iocContext.getBeanDefinitionOrCreateAndReturn(target); - targetBeanDefinition.getDependsOn() - .add(iocContext.getBeanDefinitionOrCreateAndReturn(parent)); - }); - } -} diff --git a/processor/src/main/java/io/crysknife/generator/scanner/QualifiersScan.java b/processor/src/main/java/io/crysknife/generator/scanner/QualifiersScan.java deleted file mode 100644 index a95cb290..00000000 --- a/processor/src/main/java/io/crysknife/generator/scanner/QualifiersScan.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.generator.scanner; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; - -import javax.enterprise.inject.Default; -import javax.inject.Named; -import javax.inject.Qualifier; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; - -import com.google.auto.common.MoreElements; -import com.google.auto.common.MoreTypes; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/12/19 - */ -public class QualifiersScan { - - private final IOCContext iocContext; - - private final Set points = new HashSet<>(); - - public QualifiersScan(IOCContext iocContext) { - this.iocContext = iocContext; - } - - public void process() { - processQualifierAnnotation(); - processNamedAnnotation(); - processDefaultAnnotation(); - } - - private void processNamedAnnotation() { - iocContext.getTypeElementsByAnnotation(Named.class.getCanonicalName()) - .forEach(named -> named.getInterfaces().forEach(parent -> { - BeanDefinition iface = - iocContext.getBeanDefinitionOrCreateAndReturn(MoreTypes.asTypeElement(parent)); - if (!iocContext.getQualifiers().containsKey(iface.getType())) { - iocContext.getQualifiers().put(iface.getType(), new HashMap<>()); - } - iocContext.getQualifiers().get(iface.getType()).put( - named.getAnnotation(Named.class).value(), - iocContext.getBeanDefinitionOrCreateAndReturn(named)); - })); - } - - private void processQualifierAnnotation() { - iocContext.getTypeElementsByAnnotation(Qualifier.class.getCanonicalName()) - .forEach(qualified -> { - iocContext.getFieldsByAnnotation(qualified.getQualifiedName().toString()) - .forEach(candidate -> processAnnotation(candidate, qualified)); - iocContext.getTypeElementsByAnnotation(qualified.getQualifiedName().toString()) - .forEach(candidate -> processAnnotation(candidate, qualified)); - }); - } - - private void processDefaultAnnotation() { - Element qualified = iocContext.getGenerationContext().getProcessingEnvironment() - .getElementUtils().getTypeElement(Default.class.getCanonicalName()); - - iocContext.getGenerationContext().getRoundEnvironment().getElementsAnnotatedWith(Default.class) - .forEach(annotated -> processAnnotation(annotated, qualified)); - } - - private void processAnnotation(Element element, Element qualified) { - if (element.getKind().isField()) { - points.add(MoreElements.asVariable(element)); - } else if (element.getKind().isClass()) { - processQualifier(MoreElements.asType(element), qualified); - } - } - - private void processQualifier(TypeElement qualifier, Element annotation) { - qualifier.getInterfaces().forEach(parent -> { - BeanDefinition iface = - iocContext.getBeanDefinitionOrCreateAndReturn(MoreTypes.asTypeElement(parent)); - if (!iocContext.getQualifiers().containsKey(iface.getType())) { - iocContext.getQualifiers().put(iface.getType(), new HashMap<>()); - } - iocContext.getQualifiers().get(iface.getType()).put(annotation.toString(), - iocContext.getBeanDefinitionOrCreateAndReturn(qualifier)); - }); - } -} diff --git a/processor/src/main/java/io/crysknife/processor/ClassDecoratorTypeProcessor.java b/processor/src/main/java/io/crysknife/processor/ClassDecoratorTypeProcessor.java deleted file mode 100644 index c8b5a6a5..00000000 --- a/processor/src/main/java/io/crysknife/processor/ClassDecoratorTypeProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.processor; - -import javax.lang.model.element.Element; - -import com.google.auto.common.MoreElements; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/7/19 - */ -public class ClassDecoratorTypeProcessor extends TypeProcessor { - - protected ClassDecoratorTypeProcessor(IOCGenerator generator) { - super(generator); - } - - @Override - public void process(IOCContext context, Element element) { - if (MoreElements.isType(element)) { - BeanDefinition beanDefinition = - context.getBeanDefinitionOrCreateAndReturn(MoreElements.asType(element)); - context.getBeans().get(MoreElements.asType(element)).addDecorator(generator, beanDefinition); - } - } -} diff --git a/processor/src/main/java/io/crysknife/processor/ConstructorInjectionPointProcessor.java b/processor/src/main/java/io/crysknife/processor/ConstructorInjectionPointProcessor.java new file mode 100644 index 00000000..98267924 --- /dev/null +++ b/processor/src/main/java/io/crysknife/processor/ConstructorInjectionPointProcessor.java @@ -0,0 +1,71 @@ +/* + * Copyright © 2021 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.processor; + +import com.google.auto.common.MoreElements; +import com.google.auto.common.MoreTypes; +import io.crysknife.definition.InjectionParameterDefinition; +import io.crysknife.exception.GenerationException; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; +import io.crysknife.definition.BeanDefinition; + +import javax.inject.Inject; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/4/21 + */ +public class ConstructorInjectionPointProcessor extends InjectionPointProcessor { + + + public ConstructorInjectionPointProcessor(IOCContext context, TreeLogger logger) { + super(context, logger); + } + + @Override + public void process(BeanDefinition bean) throws UnableToCompleteException { + List constructors = context.getGenerationContext().getElements() + .getAllMembers(MoreTypes.asTypeElement(bean.getType())).stream() + .filter(field -> field.getKind().equals(ElementKind.CONSTRUCTOR)) + .filter(elm -> elm.getAnnotation(Inject.class) != null) + .map(elm -> MoreElements.asExecutable(elm)).collect(Collectors.toList()); + + if (constructors.isEmpty()) { + return; + } + + if (constructors.size() > 1) { + throw new GenerationException( + bean.getType() + "must contain only one constructor annotated with @Inject"); + } + ExecutableElement constructor = constructors.iterator().next(); + for (int i = 0; i < constructor.getParameters().size(); i++) { + process(bean, constructor.getParameters().get(i)); + + } + } + + @Override + protected void process(BeanDefinition bean, VariableElement field) + throws UnableToCompleteException { + bean.getConstructorParams().add(new InjectionParameterDefinition(bean, field)); + } +} diff --git a/processor/src/main/java/io/crysknife/processor/DependentTypeProcessor.java b/processor/src/main/java/io/crysknife/processor/DependentTypeProcessor.java deleted file mode 100644 index e6b8f0f9..00000000 --- a/processor/src/main/java/io/crysknife/processor/DependentTypeProcessor.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.processor; - -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; - -import com.google.auto.common.MoreElements; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.IOCGenerator; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/4/19 - */ -public class DependentTypeProcessor extends TypeProcessor { - - protected DependentTypeProcessor(IOCGenerator generator) { - super(generator); - } - - @Override - public void process(IOCContext context, Element element) { - if (MoreElements.isType(element)) { - TypeElement typeElement = MoreElements.asType(element); - BeanDefinition beanDefinition = context.getBeanDefinitionOrCreateAndReturn(typeElement); - beanDefinition.setGenerator(generator); - } - } - -} diff --git a/processor/src/main/java/io/crysknife/processor/ExactTypeProcessor.java b/processor/src/main/java/io/crysknife/processor/ExactTypeProcessor.java deleted file mode 100644 index af7ec5bb..00000000 --- a/processor/src/main/java/io/crysknife/processor/ExactTypeProcessor.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.processor; - -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.TypeMirror; - -import com.google.auto.common.MoreElements; -import com.google.auto.common.MoreTypes; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/31/19 - */ -public class ExactTypeProcessor extends TypeProcessor { - - protected ExactTypeProcessor(IOCGenerator generator) { - super(generator); - } - - @Override - public void process(IOCContext context, Element element) { - if (element.getKind().isField() || element.getKind().isClass()) { - TypeMirror mirror = (element.getKind().isField() ? MoreElements.asVariable(element).asType() - : element.asType()); - TypeElement typeElement = MoreTypes.asTypeElement(mirror); - BeanDefinition beanDefinition = context.getBeanDefinitionOrCreateAndReturn(typeElement); - if (!typeElement.getTypeParameters().isEmpty()) { - TypeMirror type = element.asType(); - beanDefinition.getDeclaredTypes().add(MoreTypes.asDeclared(type)); - } - beanDefinition.setGenerator(generator); - } - } -} diff --git a/processor/src/main/java/io/crysknife/processor/FieldProcessor.java b/processor/src/main/java/io/crysknife/processor/FieldProcessor.java new file mode 100644 index 00000000..574b975e --- /dev/null +++ b/processor/src/main/java/io/crysknife/processor/FieldProcessor.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2021 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.processor; + +import com.google.auto.common.MoreElements; +import com.google.auto.common.MoreTypes; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.util.Utils; + +import javax.inject.Inject; +import javax.lang.model.element.VariableElement; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/4/21 + */ +public class FieldProcessor extends InjectionPointProcessor { + + public FieldProcessor(IOCContext context, TreeLogger logger) { + super(context, logger); + } + + @Override + public void process(BeanDefinition bean) throws UnableToCompleteException { + Set fields = Utils + .getAllFieldsIn(context.getGenerationContext().getElements(), + MoreTypes.asTypeElement(bean.getType())) + .stream().filter(field -> field.getKind().isField()) + .filter(elm -> elm.getAnnotation(Inject.class) != null) + .map(elm -> MoreElements.asVariable(elm)).collect(Collectors.toSet()); + + process(bean, fields); + } + + @Override + protected void process(BeanDefinition bean, VariableElement field) + throws UnableToCompleteException { + bean.getFields().add(new InjectableVariableDefinition(bean, field)); + } +} diff --git a/processor/src/main/java/io/crysknife/processor/InjectionPointProcessor.java b/processor/src/main/java/io/crysknife/processor/InjectionPointProcessor.java new file mode 100644 index 00000000..9e616506 --- /dev/null +++ b/processor/src/main/java/io/crysknife/processor/InjectionPointProcessor.java @@ -0,0 +1,71 @@ +/* + * Copyright © 2021 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.processor; + +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.validation.InjectionPointValidator; + +import javax.lang.model.element.VariableElement; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/4/21 + */ +public abstract class InjectionPointProcessor { + + protected final IOCContext context; + protected final TreeLogger logger; + + public InjectionPointProcessor(IOCContext context, TreeLogger logger) { + this.context = context; + this.logger = logger; + } + + public abstract void process(BeanDefinition bean) throws UnableToCompleteException; + + protected void process(BeanDefinition bean, Set points) + throws UnableToCompleteException { + + Set errors = new HashSet<>(); + + for (VariableElement field : points) { + try { + new InjectionPointValidator(context, field.getEnclosingElement()).validate(field); + process(bean, field); + } catch (UnableToCompleteException e) { + errors.add(e); + } + } + + if (!errors.isEmpty()) { + TreeLogger logger = + this.logger.branch(TreeLogger.ERROR, "Unable to process bean: " + bean.getType()); + for (UnableToCompleteException error : errors) { + logger.log(TreeLogger.ERROR, error.getMessage()); + } + throw new UnableToCompleteException(); + } + } + + + protected abstract void process(BeanDefinition bean, VariableElement field) + throws UnableToCompleteException; + + +} diff --git a/processor/src/main/java/io/crysknife/processor/MethodDecoratorTypeProcessor.java b/processor/src/main/java/io/crysknife/processor/MethodDecoratorTypeProcessor.java deleted file mode 100644 index 1749c349..00000000 --- a/processor/src/main/java/io/crysknife/processor/MethodDecoratorTypeProcessor.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.processor; - -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; - -import com.google.auto.common.MoreElements; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.ExecutableDefinition; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/4/19 - */ -public class MethodDecoratorTypeProcessor extends TypeProcessor { - - protected MethodDecoratorTypeProcessor(IOCGenerator generator) { - super(generator); - } - - @Override - public void process(IOCContext context, Element element) { - if (element.getKind().equals(ElementKind.METHOD)) { - ExecutableElement method = MoreElements.asExecutable(element); - TypeElement enclosingElement = MoreElements.asType(method.getEnclosingElement()); - BeanDefinition beanDefinition = context.getBeanDefinitionOrCreateAndReturn(enclosingElement); - beanDefinition.addExecutableDefinition(generator, - ExecutableDefinition.of(method, enclosingElement)); - } - } -} diff --git a/processor/src/main/java/io/crysknife/processor/ParameterTypeProcessor.java b/processor/src/main/java/io/crysknife/processor/ParameterTypeProcessor.java deleted file mode 100644 index ed5a1318..00000000 --- a/processor/src/main/java/io/crysknife/processor/ParameterTypeProcessor.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.processor; - -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; - -import com.google.auto.common.MoreElements; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.ExecutableDefinition; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/5/19 - */ -public class ParameterTypeProcessor extends TypeProcessor { - - protected ParameterTypeProcessor(IOCGenerator generator) { - super(generator); - } - - @Override - public void process(IOCContext context, Element element) { - if (element.getKind().equals(ElementKind.PARAMETER)) { - VariableElement parameter = MoreElements.asVariable(element); - ExecutableElement method = MoreElements.asExecutable(parameter.getEnclosingElement()); - - TypeElement enclosingElement = MoreElements.asType(method.getEnclosingElement()); - BeanDefinition beanDefinition = context.getBeanDefinitionOrCreateAndReturn(enclosingElement); - beanDefinition.addExecutableDefinition(generator, - ExecutableDefinition.of(method, enclosingElement)); - } - } -} diff --git a/processor/src/main/java/io/crysknife/processor/ProducerTypeProcessor.java b/processor/src/main/java/io/crysknife/processor/ProducerTypeProcessor.java deleted file mode 100644 index 235061d4..00000000 --- a/processor/src/main/java/io/crysknife/processor/ProducerTypeProcessor.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.processor; - -import javax.inject.Singleton; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; - -import com.google.auto.common.MoreElements; -import com.google.auto.common.MoreTypes; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.WiringElementType; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.ProducerDefinition; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/4/19 - */ - -public class ProducerTypeProcessor extends TypeProcessor { - - protected ProducerTypeProcessor(IOCGenerator generator) { - super(generator); - } - - @Override - public void process(IOCContext context, Element element) { - if (element.getKind().equals(ElementKind.METHOD)) { - ExecutableElement method = MoreElements.asExecutable(element); - Element theReturn = MoreTypes.asElement(method.getReturnType()); - - ProducerDefinition producerDefinition = - ProducerDefinition.of(method, MoreElements.asType(method.getEnclosingElement())); - producerDefinition.setGenerator(generator); - context.getBeans().put(MoreElements.asType(theReturn), producerDefinition); - - BeanDefinition bean = context - .getBeanDefinitionOrCreateAndReturn(MoreElements.asType(method.getEnclosingElement())); - - TypeElement obj = context.getGenerationContext().getElements() - .getTypeElement(Object.class.getCanonicalName()); - - IOCContext.IOCGeneratorMeta meta = new IOCContext.IOCGeneratorMeta( - Singleton.class.getCanonicalName(), obj, WiringElementType.BEAN); - - bean.setGenerator(context.getGenerators().get(meta).stream().findFirst().get()); - context.getBeans().put(MoreElements.asType(method.getEnclosingElement()), bean); - } - } -} diff --git a/processor/src/main/java/io/crysknife/processor/ProducesProcessor.java b/processor/src/main/java/io/crysknife/processor/ProducesProcessor.java new file mode 100644 index 00000000..704aab2a --- /dev/null +++ b/processor/src/main/java/io/crysknife/processor/ProducesProcessor.java @@ -0,0 +1,88 @@ +/* + * Copyright © 2021 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.processor; + +import com.google.auto.common.MoreTypes; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.IOCGenerator; +import io.crysknife.generator.WiringElementType; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.BeanDefinitionFactory; +import io.crysknife.definition.ProducesBeanDefinition; +import io.crysknife.validation.ProducesValidator; + +import javax.enterprise.inject.Produces; +import javax.inject.Singleton; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.TypeMirror; +import java.util.Optional; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/8/21 + */ +public class ProducesProcessor { + + private final IOCContext iocContext; + private final ProducesValidator validator; + private final TreeLogger logger; + private final BeanDefinitionFactory beanDefinitionFactory; + private final TypeMirror objectTypeMirror; + + + + public ProducesProcessor(IOCContext iocContext, TreeLogger logger) { + this.iocContext = iocContext; + this.logger = logger; + this.validator = new ProducesValidator(iocContext); + this.beanDefinitionFactory = new BeanDefinitionFactory(iocContext, logger); + this.objectTypeMirror = iocContext.getGenerationContext().getElements() + .getTypeElement(Object.class.getCanonicalName()).asType(); + } + + public void process(Element produce) throws UnableToCompleteException { + + validator.validate(produce); + ExecutableElement method = (ExecutableElement) produce; + TypeMirror parent = + iocContext.getGenerationContext().getTypes().erasure(method.getEnclosingElement().asType()); + + if (!iocContext.getBeans().containsKey(parent)) { + BeanDefinition bean = beanDefinitionFactory.of(parent); + iocContext.getBeans().put(parent, bean); + + Optional generator = iocContext.getGenerator(Singleton.class.getCanonicalName(), + MoreTypes.asTypeElement(objectTypeMirror), WiringElementType.BEAN); + generator.ifPresent(bean::setIocGenerator); + iocContext.getBeans().put(parent, bean); + } + + Optional generator = iocContext.getGenerator(Produces.class.getCanonicalName(), + MoreTypes.asTypeElement(objectTypeMirror), WiringElementType.METHOD_DECORATOR); + + if (generator.isPresent()) { + ProducesBeanDefinition beanDefinition = beanDefinitionFactory.of(method); + beanDefinition.setIocGenerator(generator.get()); + TypeMirror beanTypeMirror = + iocContext.getGenerationContext().getTypes().erasure(method.getReturnType()); + iocContext.getBeans().put(beanTypeMirror, beanDefinition); + } + + } + + +} diff --git a/processor/src/main/java/io/crysknife/processor/TypeProcessorFactory.java b/processor/src/main/java/io/crysknife/processor/TypeProcessorFactory.java deleted file mode 100644 index 159f34c5..00000000 --- a/processor/src/main/java/io/crysknife/processor/TypeProcessorFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.processor; - -import java.util.Optional; - -import javax.lang.model.element.Element; -import javax.lang.model.type.TypeMirror; - -import com.google.auto.common.MoreElements; -import io.crysknife.generator.IOCGenerator; -import io.crysknife.generator.context.IOCContext; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/4/19 - */ -public class TypeProcessorFactory { - - private TypeProcessorFactory() { - - } - - public static Optional getTypeProcessor(IOCContext.IOCGeneratorMeta meta, - IOCGenerator generator, Element element) { - if (element.getKind().isField() || element.getKind().isClass()) { - TypeMirror type = (element.getKind().isField() ? MoreElements.asVariable(element).asType() - : element.asType()); - if (type.equals(meta.exactType.asType())) { - return Optional.of(new ExactTypeProcessor(generator)); - } - } - - switch (meta.wiringElementType) { - case BEAN: - return Optional.of(new DependentTypeProcessor(generator)); - case PRODUCER_ELEMENT: - return Optional.of(new ProducerTypeProcessor(generator)); - case CLASS_DECORATOR: - return Optional.of(new ClassDecoratorTypeProcessor(generator)); - case METHOD_DECORATOR: - return Optional.of(new MethodDecoratorTypeProcessor(generator)); - case PARAMETER: - return Optional.of(new ParameterTypeProcessor(generator)); - default: - return Optional.empty(); - } - } -} diff --git a/processor/src/main/java/io/crysknife/task/BeanProcessorTask.java b/processor/src/main/java/io/crysknife/task/BeanProcessorTask.java new file mode 100644 index 00000000..d38b52e8 --- /dev/null +++ b/processor/src/main/java/io/crysknife/task/BeanProcessorTask.java @@ -0,0 +1,387 @@ +/* + * Copyright © 2021 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.task; + +import com.google.auto.common.MoreElements; +import com.google.auto.common.MoreTypes; +import io.crysknife.annotation.Application; +import io.crysknife.annotation.Generator; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.BeanDefinitionFactory; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.definition.MethodDefinition; +import io.crysknife.definition.MethodDefinitionFactory; +import io.crysknife.definition.ProducesBeanDefinition; +import io.crysknife.definition.VariableDefinition; +import io.crysknife.exception.GenerationException; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.IOCGenerator; +import io.crysknife.generator.WiringElementType; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.generator.context.oracle.BeanOracle; +import io.crysknife.logger.TreeLogger; +import io.crysknife.processor.ProducesProcessor; +import io.crysknife.util.Utils; + +import javax.enterprise.context.Dependent; +import javax.enterprise.inject.Produces; +import javax.inject.Inject; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/3/21 + */ +public class BeanProcessorTask implements Task { + + private final IOCContext iocContext; + private final TreeLogger logger; + private final TypeMirror objectTypeMirror; + private final Types types; + private final BeanDefinitionFactory beanDefinitionFactory; + private final MethodDefinitionFactory methodDefinitionFactory; + private final Set scoped; + private final BeanOracle oracle; + private final Set buildin = new HashSet<>(); + + public BeanProcessorTask(IOCContext iocContext, TreeLogger logger) { + this.iocContext = iocContext; + this.logger = logger; + this.oracle = new BeanOracle(iocContext); + this.beanDefinitionFactory = new BeanDefinitionFactory(iocContext, logger); + this.methodDefinitionFactory = new MethodDefinitionFactory(iocContext, logger); + this.objectTypeMirror = iocContext.getGenerationContext().getElements() + .getTypeElement(Object.class.getCanonicalName()).asType(); + + types = iocContext.getGenerationContext().getTypes(); + + scoped = iocContext.getGenerators().entries().stream() + .sorted(Comparator + .comparingInt(o -> o.getValue().getClass().getAnnotation(Generator.class).priority())) + .filter(gen -> gen.getKey().wiringElementType.equals(WiringElementType.BEAN)) + .map(v -> v.getKey().annotation).collect(Collectors.toSet()); + } + + public void execute() { + findInjectionPoints(); + processInjectionPointsInUnscopedBeans(); + findProduces(); + + processTypes(); + processTypeDecorators(); + processFieldDecorators(); + processMethodDecorators(); + processMethodParamDecorators(); + + logger.log(TreeLogger.INFO, "beans registered " + iocContext.getBeans().size()); + + long count = iocContext.getBeans().values().stream().map(BeanDefinition::getFields) + .flatMap(Collection::stream).count(); + count = count + iocContext.getBeans().values().stream() + .map(BeanDefinition::getConstructorParams).flatMap(Collection::stream).count(); + + + logger.log(TreeLogger.INFO, "fields registered " + count); + } + + // TODO annotated field could be non-injectable + private void processFieldDecorators() { + iocContext.getGenerators().asMap().entrySet().stream() + .filter(iocGeneratorMetaCollectionEntry -> iocGeneratorMetaCollectionEntry + + .getKey().wiringElementType.equals(WiringElementType.FIELD_DECORATOR)) + .forEach(iocGeneratorMetaCollectionEntry -> { + iocGeneratorMetaCollectionEntry.getValue().forEach(gen -> { + + TypeElement annotation = iocContext.getGenerationContext().getElements() + .getTypeElement(iocGeneratorMetaCollectionEntry.getKey().annotation); + + Set elements = iocContext.getGenerationContext().getRoundEnvironment() + .getElementsAnnotatedWith(annotation).stream() + .filter(elm -> elm.getKind().isField()).map(field -> MoreElements.asVariable(field)) + .collect(Collectors.toSet()); + + elements.addAll(iocContext + .getFieldsByAnnotation(iocGeneratorMetaCollectionEntry.getKey().annotation)); + + elements.stream().forEach(field -> { + TypeMirror erased = iocContext.getGenerationContext().getTypes() + .erasure(field.getEnclosingElement().asType()); + BeanDefinition bean = iocContext.getBeans().get(erased); + bean.getFields().stream().filter(f -> f.getVariableElement().equals(field)) + .forEach(f -> f.getDecorators() + .addAll(iocGeneratorMetaCollectionEntry.getValue().stream() + .map(em -> (IOCGenerator) em) + .collect(Collectors.toSet()))); + }); + }); + }); + } + + private void processMethodParamDecorators() { + iocContext.getGenerators().asMap().entrySet().stream() + .filter(iocGeneratorMetaCollectionEntry -> iocGeneratorMetaCollectionEntry + .getKey().wiringElementType.equals(WiringElementType.PARAMETER)) + .forEach(iocGeneratorMetaCollectionEntry -> { + iocGeneratorMetaCollectionEntry.getValue().forEach(gen -> { + + TypeElement annotation = iocContext.getGenerationContext().getElements() + .getTypeElement(iocGeneratorMetaCollectionEntry.getKey().annotation); + Set elements = iocContext.getGenerationContext() + .getRoundEnvironment().getElementsAnnotatedWith(annotation).stream() + .filter(elm -> elm.getKind().equals(ElementKind.PARAMETER)) + .map(elm -> MoreElements.asVariable(elm)) + .map(elm -> MoreElements.asExecutable(elm.getEnclosingElement())) + .map(elm -> MoreElements.asExecutable(elm)).collect(Collectors.toSet()); + + elements.stream().forEach(e -> { + TypeMirror erased = iocContext.getGenerationContext().getTypes() + .erasure(e.getEnclosingElement().asType()); + BeanDefinition bean = iocContext.getBeans().get(erased); + ExecutableType methodType = (ExecutableType) e.asType(); + bean.getMethods().stream() + .filter(mmethod -> mmethod.getExecutableElement().equals(methodType)).findFirst() + .orElse(methodDefinitionFactory.of(bean, e)).getDecorators() + .addAll(iocGeneratorMetaCollectionEntry.getValue().stream() + .map(em -> (IOCGenerator) em).collect(Collectors.toSet())); + }); + }); + }); + } + + private void processTypeDecorators() { + iocContext.getGenerators().asMap().entrySet().stream() + .filter(iocGeneratorMetaCollectionEntry -> iocGeneratorMetaCollectionEntry + .getKey().wiringElementType.equals(WiringElementType.CLASS_DECORATOR)) + .forEach(iocGeneratorMetaCollectionEntry -> { + iocContext + .getTypeElementsByAnnotation(iocGeneratorMetaCollectionEntry.getKey().annotation) + .stream().map(e -> iocContext.getGenerationContext().getTypes().erasure(e.asType())) + .forEach(type -> iocContext.getBean(type).getDecorators() + .addAll(iocGeneratorMetaCollectionEntry.getValue().stream() + .map(em -> (IOCGenerator) em).collect(Collectors.toSet()))); + }); + } + + private void processMethodDecorators() { + iocContext.getGenerators().asMap().entrySet().stream() + .filter(iocGeneratorMetaCollectionEntry -> iocGeneratorMetaCollectionEntry + .getKey().wiringElementType.equals(WiringElementType.METHOD_DECORATOR)) + .forEach(iocGeneratorMetaCollectionEntry -> iocGeneratorMetaCollectionEntry.getValue() + .forEach(gen -> { + TypeElement annotation = iocContext.getGenerationContext().getElements() + .getTypeElement(iocGeneratorMetaCollectionEntry.getKey().annotation); + + Set elements = iocContext.getGenerationContext() + .getRoundEnvironment().getElementsAnnotatedWith(annotation).stream() + .filter(elm -> elm.getKind().equals(ElementKind.METHOD)) + .map(elm -> MoreElements.asExecutable(elm)).collect(Collectors.toSet()); + + elements.stream().forEach(e -> { + TypeMirror erased = iocContext.getGenerationContext().getTypes() + .erasure(e.getEnclosingElement().asType()); + BeanDefinition bean = iocContext.getBean(erased); + ExecutableType methodType = (ExecutableType) e.asType(); + bean.getMethods().stream() + .filter(mmethod -> mmethod.getExecutableElement().equals(methodType)) + .findFirst().orElse(methodDefinitionFactory.of(bean, e)).getDecorators() + .addAll(iocGeneratorMetaCollectionEntry.getValue().stream() + .map(em -> (IOCGenerator) em) + .collect(Collectors.toSet())); + }); + })); + } + + private void findProduces() { + ProducesProcessor producesProcessor = new ProducesProcessor(iocContext, logger); + + Set produces = (Set) iocContext.getGenerationContext().getRoundEnvironment() + .getElementsAnnotatedWith(Produces.class); + + produces.addAll(iocContext.getMethodsByAnnotation(Produces.class.getCanonicalName())); + List errors = new ArrayList<>(); + + for (Element produce : produces) { + try { + producesProcessor.process(produce); + } catch (UnableToCompleteException e) { + errors.add(e); + } + } + + if (!errors.isEmpty()) { + for (UnableToCompleteException error : errors) { + logger.log(TreeLogger.Type.ERROR, error.getMessage()); + } + throw new GenerationException(); + } + } + + private void processTypes() { + iocContext.getBeans().forEach((type, definition) -> { + Set dependencies = new HashSet<>(); + dependencies.addAll(definition.getFields()); + dependencies.addAll(definition.getConstructorParams()); + + for (InjectableVariableDefinition point : dependencies) { + checkIfGeneric(point.getVariableElement()); + + TypeMirror beanTypeMirror = iocContext.getGenerationContext().getTypes() + .erasure(point.getVariableElement().asType()); + TypeElement beanTypeElement = MoreTypes.asTypeElement(beanTypeMirror); + + Optional candidate = iocContext.getGenerator(Inject.class.getCanonicalName(), + beanTypeElement, WiringElementType.FIELD_TYPE); + + // Case 1: buildin type + if (candidate.isPresent()) { + point.setGenerator(candidate.get()); + } else if (iocContext.getBeans().get(beanTypeMirror) instanceof ProducesBeanDefinition) { + // TODO + } else { + BeanDefinition implementation = oracle.guess(point); + if (implementation != null) { + point.setImplementation(implementation); + definition.getDependencies().add(implementation); + } + } + } + }); + } + + private void checkIfGeneric(VariableElement variableElement) {} + + private void findInjectionPoints() { + // TreeLogger logger = this.logger.branch(TreeLogger.INFO, "find Injection Points"); + + iocContext.getGenerators().entries().stream().map(gen -> gen.getKey().exactType) + .filter(elm -> !types.isSameType(elm.asType(), objectTypeMirror)).map(TypeElement::asType) + .forEach(buildin::add); + + + Set annotatedScopedBean = scoped.stream().map(sc -> { + TypeElement annotation = iocContext.getGenerationContext().getElements().getTypeElement(sc); + return iocContext.getGenerationContext().getRoundEnvironment() + .getElementsAnnotatedWith(annotation); + }).flatMap(Collection::stream).filter(elm -> elm.getKind().isClass()).map(MoreElements::asType) + .sorted(Comparator.comparing(o -> o.getQualifiedName().toString())) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + scoped.stream() + .map(sc -> iocContext.getGenerationContext().getScanResult().getClassesWithAnnotation(sc)) + .flatMap(Collection::stream) + .map(elm -> iocContext.getGenerationContext().getElements().getTypeElement(elm.getName())) + .filter(elm -> elm != null).forEach(annotatedScopedBean::add); + + processBeans(annotatedScopedBean); + } + + private void processInjectionPointsInUnscopedBeans() { + String[] annotations = scoped.toArray(new String[scoped.size()]); + + Set unscoped = iocContext.getGenerationContext().getRoundEnvironment() + .getElementsAnnotatedWith(Inject.class).stream() + .map(p -> MoreElements.asType(p.getEnclosingElement())) + .filter(type -> type.getAnnotation(Application.class) == null) // TODO + .filter( + type -> type.getKind().isClass() && !type.getModifiers().contains(Modifier.ABSTRACT)) + .filter(point -> !Utils.containsAnnotation(point, annotations)) + .map(elm -> iocContext.getGenerationContext().getTypes().erasure(elm.asType())) + .filter(type -> !iocContext.getBeans().containsKey(type)).collect(Collectors.toSet()); + + IOCGenerator dependentGenerator = iocContext.getGenerator(Dependent.class.getCanonicalName(), + MoreTypes.asTypeElement(objectTypeMirror), WiringElementType.BEAN).get(); + + for (TypeMirror typeMirror : unscoped) { + TypeElement typeElement = MoreTypes.asTypeElement(typeMirror); + try { + processBean(typeElement).ifPresent(bean -> bean.setIocGenerator(dependentGenerator)); + } catch (UnableToCompleteException e) { + throw new GenerationException(e); + } + + } + } + + + private void processBeans(Set annotatedScopedBean) { + List errors = new ArrayList<>(); + for (TypeElement typeElement : annotatedScopedBean) { + try { + processBean(typeElement); + } catch (UnableToCompleteException e) { + errors.add(e); + } + } + + if (!errors.isEmpty()) { + for (UnableToCompleteException error : errors) { + logger.log(TreeLogger.Type.ERROR, error.getMessage()); + } + throw new GenerationException(); + } + } + + private Optional processBean(TypeElement type) throws UnableToCompleteException { + TypeMirror key = types.erasure(type.asType()); + if (!iocContext.getBeans().containsKey(key)) { + BeanDefinition bean = beanDefinitionFactory.of(key); + setBeanDefinitionGenerator(bean); + + for (TypeMirror supr : types.directSupertypes(key)) { + if (!types.isSameType(objectTypeMirror, supr)) { + TypeMirror parent = types.erasure(supr); + Optional candidate = processBean(MoreTypes.asTypeElement(parent)); + candidate.ifPresent(can -> can.getSubclasses().add(bean)); + } + } + iocContext.getBeans().put(key, bean); + return Optional.of(bean); + } else { + return Optional.of(iocContext.getBeans().get(key)); + } + } + + private void setBeanDefinitionGenerator(BeanDefinition bean) { + Set annotations = bean.getAnnotationMirrors().stream() + .map(anno -> anno.getAnnotationType().toString()).collect(Collectors.toSet()); + + Set intersection = new HashSet<>(annotations); + intersection.retainAll(scoped); + + if (!intersection.isEmpty()) { + String annotation = intersection.iterator().next(); + Optional generator = iocContext.getGenerator(annotation, + MoreTypes.asTypeElement(objectTypeMirror), WiringElementType.BEAN); + generator.ifPresent(bean::setIocGenerator); + } + } +} diff --git a/processor/src/main/java/io/crysknife/task/CheckCyclesTask.java b/processor/src/main/java/io/crysknife/task/CheckCyclesTask.java new file mode 100644 index 00000000..4df275ab --- /dev/null +++ b/processor/src/main/java/io/crysknife/task/CheckCyclesTask.java @@ -0,0 +1,165 @@ +/* + * Copyright © 2021 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.task; + +import io.crysknife.definition.BeanDefinition; +import io.crysknife.exception.GenerationException; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import javax.lang.model.type.TypeMirror; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/16/21 + */ +public class CheckCyclesTask implements Task { + + private final IOCContext context; + private final TreeLogger logger; + + public CheckCyclesTask(IOCContext iocContext, TreeLogger logger) { + this.context = iocContext; + this.logger = logger; + } + + @Override + public void execute() throws UnableToCompleteException { + Map vertexes = new HashMap<>(); + Graph graph = new Graph(); + + for (Map.Entry entry : context.getBeans().entrySet()) { + Vertex vertex = new Vertex(entry.getValue()); + graph.addVertex(vertex); + vertexes.put(entry.getKey(), vertex); + } + + for (Map.Entry entry : context.getBeans().entrySet()) { + entry.getValue().getDependencies().forEach(dep -> { + Vertex from = vertexes.get(entry.getKey()); + Vertex to = vertexes.get(dep.getType()); + // check, if unscoped bean + if (to != null) { + graph.addEdge(from, to); + } + }); + } + + if (graph.hasCycle()) { + System.out.println("Graph contains cyclic deps [" + + graph.pair.get().getKey().beanDefinition.getQualifiedName() + " <-> " + + graph.pair.get().getValue().beanDefinition.getQualifiedName() + "]"); + } + + } + + + private static class Graph { + + private List vertices; + + public Optional> pair = Optional.empty(); + + public Graph() { + this.vertices = new ArrayList<>(); + } + + public void addVertex(Vertex vertex) { + this.vertices.add(vertex); + } + + public void addEdge(Vertex from, Vertex to) { + from.addNeighbour(to); + } + + public boolean hasCycle() { + for (Vertex vertex : vertices) { + if (!vertex.isVisited() && hasCycle(vertex)) { + return true; + } + } + return false; + } + + public boolean hasCycle(Vertex sourceVertex) { + sourceVertex.setBeingVisited(true); + for (Vertex neighbour : sourceVertex.getAdjacencyList()) { + if (neighbour.isBeingVisited()) { + pair = Optional.of(new ImmutablePair<>(sourceVertex, neighbour)); + return true; + } else if (!neighbour.isVisited() && hasCycle(neighbour)) { + return true; + } + } + sourceVertex.setBeingVisited(false); + sourceVertex.setVisited(true); + return false; + } + + } + + private static class Vertex { + + private BeanDefinition beanDefinition; + + private boolean visited; + + private boolean beingVisited; + + private List adjacencyList; + + public Vertex(BeanDefinition beanDefinition) { + this.beanDefinition = beanDefinition; + this.adjacencyList = new ArrayList<>(); + } + + public BeanDefinition get() { + return beanDefinition; + } + + public boolean isVisited() { + return visited; + } + + public void setVisited(boolean visited) { + this.visited = visited; + } + + public boolean isBeingVisited() { + return beingVisited; + } + + public void setBeingVisited(boolean beingVisited) { + this.beingVisited = beingVisited; + } + + public List getAdjacencyList() { + return adjacencyList; + } + + public void addNeighbour(Vertex adjacent) { + this.adjacencyList.add(adjacent); + } + + } + +} diff --git a/processor/src/main/java/io/crysknife/task/FireAfterTask.java b/processor/src/main/java/io/crysknife/task/FireAfterTask.java new file mode 100644 index 00000000..350ff914 --- /dev/null +++ b/processor/src/main/java/io/crysknife/task/FireAfterTask.java @@ -0,0 +1,38 @@ +/* + * Copyright © 2021 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.task; + +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/10/21 + */ +public class FireAfterTask implements Task { + + private IOCContext context; + private TreeLogger logger; + + public FireAfterTask(IOCContext iocContext, TreeLogger logger) { + this.context = iocContext; + this.logger = logger; + } + + @Override + public void execute() throws UnableToCompleteException { + context.getGenerators().forEach((meta, generator) -> generator.after()); + } +} diff --git a/processor/src/main/java/io/crysknife/task/FireBeforeTask.java b/processor/src/main/java/io/crysknife/task/FireBeforeTask.java new file mode 100644 index 00000000..da0fcd76 --- /dev/null +++ b/processor/src/main/java/io/crysknife/task/FireBeforeTask.java @@ -0,0 +1,38 @@ +/* + * Copyright © 2021 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.task; + +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/10/21 + */ +public class FireBeforeTask implements Task { + + private IOCContext context; + private TreeLogger logger; + + public FireBeforeTask(IOCContext context, TreeLogger logger) { + this.context = context; + this.logger = logger; + } + + @Override + public void execute() throws UnableToCompleteException { + context.getGenerators().forEach((meta, generator) -> generator.before()); + } +} diff --git a/processor/src/main/java/io/crysknife/task/FlatSubclassesTask.java b/processor/src/main/java/io/crysknife/task/FlatSubclassesTask.java new file mode 100644 index 00000000..27fbe76c --- /dev/null +++ b/processor/src/main/java/io/crysknife/task/FlatSubclassesTask.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2021 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.task; + +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; +import io.crysknife.definition.BeanDefinition; + +import java.util.stream.Stream; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/9/21 + */ +public class FlatSubclassesTask implements Task { + + private IOCContext context; + private TreeLogger logger; + + public FlatSubclassesTask(IOCContext context, TreeLogger logger) { + this.context = context; + this.logger = logger; + } + + @Override + public void execute() throws UnableToCompleteException { + /* + * context.getBeans().values().forEach(bean -> { Set flattened = + * bean.getSubclasses().stream().flatMap(Helper::flatten).collect(Collectors.toSet()); + * bean.getSubclasses().addAll(flattened); }); + */ + } + + private static class Helper { + + private Helper() {} + + public static Stream flatten(BeanDefinition order) { + return Stream.concat(Stream.of(order), + order.getSubclasses().stream().flatMap(Helper::flatten)); + } + } +} diff --git a/processor/src/main/java/io/crysknife/task/InitAndRegisterGeneratorsTask.java b/processor/src/main/java/io/crysknife/task/InitAndRegisterGeneratorsTask.java new file mode 100644 index 00000000..d8b45e5e --- /dev/null +++ b/processor/src/main/java/io/crysknife/task/InitAndRegisterGeneratorsTask.java @@ -0,0 +1,60 @@ +/* + * Copyright © 2021 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.task; + +import io.crysknife.annotation.Generator; +import io.crysknife.exception.GenerationException; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.IOCGenerator; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ClassInfoList; +import io.github.classgraph.ScanResult; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/9/21 + */ +public class InitAndRegisterGeneratorsTask implements Task { + + private IOCContext context; + private TreeLogger logger; + + public InitAndRegisterGeneratorsTask(IOCContext context, TreeLogger logger) { + this.context = context; + this.logger = logger; + } + + @Override + public void execute() throws UnableToCompleteException { + try (ScanResult scanResult = new ClassGraph().enableAllInfo().scan()) { + ClassInfoList routeClassInfoList = + scanResult.getClassesWithAnnotation(Generator.class.getCanonicalName()); + for (ClassInfo routeClassInfo : routeClassInfoList) { + try { + Constructor c = Class.forName(routeClassInfo.getName()).getConstructor(IOCContext.class); + ((IOCGenerator) c.newInstance(context)).register(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException + | NoSuchMethodException | InvocationTargetException e) { + throw new GenerationException(e); + } + } + } + } +} diff --git a/processor/src/main/java/io/crysknife/task/ProcessComponentScanAnnotationTask.java b/processor/src/main/java/io/crysknife/task/ProcessComponentScanAnnotationTask.java new file mode 100644 index 00000000..d4980aca --- /dev/null +++ b/processor/src/main/java/io/crysknife/task/ProcessComponentScanAnnotationTask.java @@ -0,0 +1,60 @@ +/* + * Copyright © 2021 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.task; + +import com.google.auto.common.MoreElements; +import io.crysknife.annotation.ComponentScan; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; + +import javax.lang.model.element.TypeElement; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/10/21 + */ +public class ProcessComponentScanAnnotationTask implements Task { + + private IOCContext context; + private TreeLogger logger; + private TypeElement application; + + private Set packages; + + public ProcessComponentScanAnnotationTask(IOCContext context, TreeLogger logger, + TypeElement application) { + this.context = context; + this.logger = logger; + this.application = application; + } + + @Override + public void execute() throws UnableToCompleteException { + packages = new HashSet<>(); + context.getGenerationContext().getRoundEnvironment() + .getElementsAnnotatedWith(ComponentScan.class).forEach(componentScan -> { + String[] values = componentScan.getAnnotation(ComponentScan.class).value(); + for (String aPackage : values) { + packages.add(aPackage); + } + }); + + if (packages.isEmpty()) { + packages.add(MoreElements.getPackage(application).getQualifiedName().toString()); + } + } +} diff --git a/processor/src/main/java/io/crysknife/generator/graph/Graph.java b/processor/src/main/java/io/crysknife/task/ProcessGraphTask.java similarity index 59% rename from processor/src/main/java/io/crysknife/generator/graph/Graph.java rename to processor/src/main/java/io/crysknife/task/ProcessGraphTask.java index c4ef7afc..6f4d8d05 100644 --- a/processor/src/main/java/io/crysknife/generator/graph/Graph.java +++ b/processor/src/main/java/io/crysknife/task/ProcessGraphTask.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,46 +12,52 @@ * the License. */ -package io.crysknife.generator.graph; - -import java.util.HashSet; -import java.util.Set; -import java.util.Stack; - -import javax.lang.model.element.TypeElement; +package io.crysknife.task; import com.google.common.graph.GraphBuilder; import com.google.common.graph.MutableGraph; import com.google.common.graph.Traverser; +import io.crysknife.exception.UnableToCompleteException; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; +import io.crysknife.logger.TreeLogger; +import io.crysknife.definition.BeanDefinition; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import java.util.HashSet; +import java.util.Set; +import java.util.Stack; /** - * @author Dmitrii Tikhomirov Created by treblereel 3/5/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/10/21 */ -public class Graph { - - private final IOCContext context; +public class ProcessGraphTask implements Task { - private final MutableGraph graph = + private final MutableGraph graph = GraphBuilder.directed().allowsSelfLoops(false).build(); + private IOCContext context; + private TreeLogger logger; + private TypeElement application; - public Graph(IOCContext context) { + public ProcessGraphTask(IOCContext context, TreeLogger logger, TypeElement application) { this.context = context; + this.logger = logger; + this.application = application; } - public void process(TypeElement application) { - Set state = new HashSet<>(); - Stack stack = new Stack<>(); - stack.push(application); + @Override + public void execute() throws UnableToCompleteException { + Set state = new HashSet<>(); + Stack stack = new Stack<>(); + stack.push(application.asType()); while (!stack.isEmpty()) { - TypeElement scan = stack.pop(); - BeanDefinition parent = context.getBeans().get(scan); + TypeMirror scan = stack.pop(); + BeanDefinition parent = context.getBean(scan); graph.addNode(scan); if (parent == null) { continue; } - parent.getDependsOn().forEach(deps -> { + parent.getDependencies().forEach(deps -> { if (!deps.getType().equals(scan)) { graph.putEdge(scan, deps.getType()); } @@ -63,7 +69,7 @@ public void process(TypeElement application) { }); } - Traverser.forGraph(graph).depthFirstPostOrder(application) + Traverser.forGraph(graph).depthFirstPostOrder(application.asType()) .forEach(bean -> context.getOrderedBeans().add(bean)); context.getBeans().forEach((bean, definition) -> { diff --git a/processor/src/main/java/io/crysknife/task/ProcessSubClassesTask.java b/processor/src/main/java/io/crysknife/task/ProcessSubClassesTask.java new file mode 100644 index 00000000..adc71bd0 --- /dev/null +++ b/processor/src/main/java/io/crysknife/task/ProcessSubClassesTask.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2021 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.task; + +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.logger.TreeLogger; +import io.crysknife.definition.BeanDefinition; + +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/10/21 + */ +public class ProcessSubClassesTask implements Task { + + private IOCContext context; + private TreeLogger logger; + + public ProcessSubClassesTask(IOCContext context, TreeLogger logger) { + this.context = context; + this.logger = logger; + } + + @Override + public void execute() throws UnableToCompleteException { + context.getBeans().values().forEach(bean -> { + Set flattened = + bean.getSubclasses().stream().flatMap(Helper::flatten).collect(Collectors.toSet()); + bean.getSubclasses().addAll(flattened); + }); + } + + private static class Helper { + + private Helper() {} + + public static Stream flatten(BeanDefinition order) { + return Stream.concat(Stream.of(order), + order.getSubclasses().stream().flatMap(Helper::flatten)); + } + } +} diff --git a/processor/src/main/java/io/crysknife/task/Task.java b/processor/src/main/java/io/crysknife/task/Task.java new file mode 100644 index 00000000..ec46c2a5 --- /dev/null +++ b/processor/src/main/java/io/crysknife/task/Task.java @@ -0,0 +1,25 @@ +/* + * Copyright © 2021 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.task; + +import io.crysknife.exception.UnableToCompleteException; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/9/21 + */ +public interface Task { + + void execute() throws UnableToCompleteException; +} diff --git a/processor/src/main/java/io/crysknife/task/TaskGroup.java b/processor/src/main/java/io/crysknife/task/TaskGroup.java new file mode 100644 index 00000000..cfdfe21c --- /dev/null +++ b/processor/src/main/java/io/crysknife/task/TaskGroup.java @@ -0,0 +1,63 @@ +/* + * Copyright © 2021 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.task; + +import io.crysknife.exception.GenerationException; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.logger.TreeLogger; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/9/21 + */ +public class TaskGroup implements Task { + + private final Set tasks = new LinkedHashSet<>(); + private final TreeLogger logger; + + public TaskGroup(TreeLogger logger) { + this.logger = logger; + } + + @Override + public void execute() { + Set errors = new LinkedHashSet<>(); + for (Task task : tasks) { + try { + task.execute(); + } catch (UnableToCompleteException e) { + errors.add(e); + } + } + if (!errors.isEmpty()) { + for (UnableToCompleteException error : errors) { + if (error.errors != null) { + for (UnableToCompleteException unableToCompleteException : error.errors) { + logger.log(TreeLogger.ERROR, unableToCompleteException.getMessage()); + } + } else { + logger.log(TreeLogger.ERROR, error.getMessage()); + } + } + throw new GenerationException(); + } + } + + public void addTask(Task task) { + tasks.add(task); + } +} diff --git a/processor/src/main/java/io/crysknife/util/GenerationUtils.java b/processor/src/main/java/io/crysknife/util/GenerationUtils.java new file mode 100644 index 00000000..fd5060c7 --- /dev/null +++ b/processor/src/main/java/io/crysknife/util/GenerationUtils.java @@ -0,0 +1,188 @@ +/* + * Copyright © 2021 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.util; + +import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.FieldAccessExpr; +import com.github.javaparser.ast.expr.LambdaExpr; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.ast.expr.StringLiteralExpr; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.github.javaparser.ast.stmt.ReturnStmt; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.google.auto.common.MoreTypes; +import io.crysknife.client.Reflect; +import io.crysknife.client.internal.InstanceImpl; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.generator.api.ClassBuilder; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.definition.BeanDefinition; +import jsinterop.base.Js; + +import javax.inject.Named; +import javax.inject.Qualifier; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import java.util.List; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/19/21 + */ +public class GenerationUtils { + + private final IOCContext context; + private final TypeMirror qualifier; + + public GenerationUtils(IOCContext context) { + this.context = context; + qualifier = context.getGenerationContext().getElements() + .getTypeElement(Qualifier.class.getCanonicalName()).asType(); + + } + + public String getActualQualifiedBeanName(InjectableVariableDefinition fieldPoint) { + String typeQualifiedName; + if (!MoreTypes.asTypeElement(fieldPoint.getVariableElement().asType()).getTypeParameters() + .isEmpty()) { + List params = + MoreTypes.asTypeElement(fieldPoint.getVariableElement().asType()).getTypeParameters(); + + + typeQualifiedName = context.getGenerationContext().getTypes() + .erasure(fieldPoint.getVariableElement().asType()).toString(); + if (fieldPoint.getImplementation().isPresent()) { + if (params.get(0).getKind().equals(ElementKind.TYPE_PARAMETER)) { + typeQualifiedName = fieldPoint.getImplementation().get().getQualifiedName(); + } + } + } else if (context.getGenerationContext().getTypes().isSameType( + fieldPoint.getVariableElement().asType(), + fieldPoint.getImplementation().orElse(fieldPoint.getBeanDefinition()).getType())) { + typeQualifiedName = fieldPoint.getVariableElement().asType().toString(); + } else { + if (fieldPoint.getImplementation().isPresent()) { + typeQualifiedName = fieldPoint.getImplementation().get().getQualifiedName(); + } else { + typeQualifiedName = fieldPoint.getVariableElement().asType().toString(); + } + } + return typeQualifiedName; + } + + + public MethodCallExpr getFieldAccessCallExpr(BeanDefinition beanDefinition, + VariableElement field) { + if (context.getGenerationContext().isGwt2()) { + return new MethodCallExpr(new NameExpr(beanDefinition.getType() + "Info"), + field.getSimpleName().toString()).addArgument("instance"); + } + + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Js.class.getSimpleName()), "asPropertyMap") + .addArgument("instance"), + "get").addArgument( + new MethodCallExpr(new NameExpr(Reflect.class.getSimpleName()), "objectProperty") + .addArgument(new StringLiteralExpr(Utils.getJsFieldName(field))) + .addArgument("instance")); + } + + public Expression beanManagerLookupBeanCall(InjectableVariableDefinition fieldPoint) { + MethodCallExpr callForProducer = new MethodCallExpr(new NameExpr("beanManager"), "lookupBean") + .addArgument(new FieldAccessExpr(new NameExpr(MoreTypes + .asTypeElement(fieldPoint.getVariableElement().asType()).getQualifiedName().toString()), + "class")); + + maybeAddQualifiers(context, callForProducer, fieldPoint); + return callForProducer; + } + + public void maybeAddQualifiers(IOCContext context, MethodCallExpr call, + InjectableVariableDefinition field) { + + String annotationName = null; + + if (field.getVariableElement().getAnnotation(Named.class) != null) { + annotationName = Named.class.getCanonicalName(); + } else if (isQualifier(field) != null) { + annotationName = isQualifier(field); + } + + if (annotationName != null) { + ObjectCreationExpr annotation = new ObjectCreationExpr(); + annotation.setType(new ClassOrInterfaceType().setName(annotationName)); + NodeList> anonymousClassBody = new NodeList<>(); + + MethodDeclaration annotationType = new MethodDeclaration(); + annotationType.setModifiers(Modifier.Keyword.PUBLIC); + annotationType.setName("annotationType"); + annotationType.setType( + new ClassOrInterfaceType().setName("Class")); + annotationType.getBody().get() + .addAndGetStatement(new ReturnStmt(new NameExpr(annotationName + ".class"))); + anonymousClassBody.add(annotationType); + + if (field.getVariableElement().getAnnotation(Named.class) != null) { + MethodDeclaration value = new MethodDeclaration(); + value.setModifiers(Modifier.Keyword.PUBLIC); + value.setName("value"); + value.setType(new ClassOrInterfaceType().setName("String")); + value.getBody().get().addAndGetStatement(new ReturnStmt( + new StringLiteralExpr(field.getVariableElement().getAnnotation(Named.class).value()))); + anonymousClassBody.add(value); + } + + annotation.setAnonymousClassBody(anonymousClassBody); + + call.addArgument(annotation); + + + } + } + + + public String isQualifier(InjectableVariableDefinition field) { + for (AnnotationMirror ann : field.getVariableElement().getAnnotationMirrors()) { + for (AnnotationMirror e : context.getGenerationContext().getProcessingEnvironment() + .getElementUtils() + .getAllAnnotationMirrors(MoreTypes.asElement(ann.getAnnotationType()))) { + boolean same = + context.getGenerationContext().getTypes().isSameType(e.getAnnotationType(), qualifier); + if (same) { + return ann.getAnnotationType().toString(); + } + } + } + return null; + } + + public Expression wrapCallInstanceImpl(ClassBuilder classBuilder, Expression call) { + classBuilder.getClassCompilationUnit().addImport(InstanceImpl.class); + LambdaExpr lambda = new LambdaExpr(); + lambda.setEnclosingParameters(true); + lambda.setBody(new ExpressionStmt(call)); + + return new ObjectCreationExpr().setType(InstanceImpl.class).addArgument(call); + } +} diff --git a/processor/src/main/java/io/crysknife/util/Utils.java b/processor/src/main/java/io/crysknife/util/Utils.java index 111162b9..a7f35cf1 100644 --- a/processor/src/main/java/io/crysknife/util/Utils.java +++ b/processor/src/main/java/io/crysknife/util/Utils.java @@ -15,19 +15,39 @@ package io.crysknife.util; import java.lang.annotation.Annotation; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import javax.enterprise.inject.Default; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; import com.google.auto.common.MoreElements; +import com.google.auto.common.MoreTypes; +import io.crysknife.generator.context.IOCContext; import jsinterop.annotations.JsProperty; import io.crysknife.exception.GenerationException; @@ -40,6 +60,10 @@ private Utils() { } + public static String getQualifiedFactoryName(TypeMirror bean) { + return getQualifiedFactoryName(MoreTypes.asTypeElement(bean)); + } + public static String getQualifiedFactoryName(TypeElement bean) { return getPackageName(bean) + "." + getFactoryClassName(bean); } @@ -49,7 +73,18 @@ public static String getPackageName(TypeElement singleton) { } public static String getFactoryClassName(TypeElement bean) { - return bean.getSimpleName().toString() + "_Factory"; + return (bean.getEnclosingElement().getKind().equals(ElementKind.PACKAGE) ? "" + : (bean.getEnclosingElement().getSimpleName() + "_")) + bean.getSimpleName().toString() + + "_Factory"; + } + + public static String getSimpleClassName(TypeMirror bean) { + return getSimpleClassName(MoreTypes.asTypeElement(bean)); + } + + public static String getSimpleClassName(TypeElement bean) { + return (bean.getEnclosingElement().getKind().equals(ElementKind.PACKAGE) ? "" + : (bean.getEnclosingElement().getSimpleName() + ".")) + bean.getSimpleName().toString(); } public static String getJsFieldName(VariableElement field) { @@ -102,4 +137,176 @@ public static String getQualifiedName(Element elm) { } throw new GenerationException("Unable to process bean " + elm.toString()); } + + public static List getAllElementQualifierAnnotations(IOCContext context, + Element element) { + List result = new ArrayList<>(); + for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { + if (isAnnotationMirrorOfType(annotationMirror, javax.inject.Named.class.getCanonicalName())) { + continue; + } + if (isAnnotationMirrorOfType(annotationMirror, Default.class.getCanonicalName())) { + continue; + } + for (AnnotationMirror allAnnotationMirror : context.getGenerationContext().getElements() + .getAllAnnotationMirrors(annotationMirror.getAnnotationType().asElement())) { + if (isAnnotationMirrorOfType(allAnnotationMirror, + javax.inject.Qualifier.class.getCanonicalName())) { + result.add(annotationMirror); + } + } + } + return result; + } + + /** + * see: typetools/checker-framework Return all methods declared in the given type or any + * superclass/interface. Note that no constructors will be returned. TODO: should this use + * javax.lang.model.util.Elements.getAllMembers(TypeElement) instead of our own getSuperTypes? + */ + public static Collection getAllFieldsIn(Elements elements, TypeElement type) { + Map fields = new LinkedHashMap<>(); + ElementFilter.fieldsIn(type.getEnclosedElements()) + .forEach(field -> fields.put(field.getSimpleName().toString(), field)); + + List alltypes = getSuperTypes(elements, type); + for (TypeElement atype : alltypes) { + ElementFilter.fieldsIn(atype.getEnclosedElements()).stream() + .filter(field -> !fields.containsKey(field.getSimpleName().toString())) + .forEach(field -> fields.put(field.getSimpleName().toString(), field)); + } + return fields.values(); + } + + public static Collection getAllTypedMethodsIn(Elements elements, Types types, + TypeMirror type) { + return getAllMethodsIn(elements, MoreTypes.asTypeElement(type)).stream() + .map(e -> types.asMemberOf(MoreTypes.asDeclared(type), e)).map(e -> (ExecutableType) e) + .collect(Collectors.toSet()); + } + + public static Collection getAllMethodsIn(Elements elements, TypeElement type) { + Map methods = new LinkedHashMap<>(); + ElementFilter.methodsIn(type.getEnclosedElements()) + .forEach(method -> methods.put(method.getSimpleName().toString(), method)); + + List alltypes = getSuperTypes(elements, type); + for (TypeElement atype : alltypes) { + ElementFilter.methodsIn(atype.getEnclosedElements()).stream() + .filter(method -> !methods.containsKey(method.getSimpleName().toString())) + .forEach(method -> methods.put(method.getSimpleName().toString(), method)); + } + return methods.values(); + } + + /** + * see: typetools/checker-framework Determine all type elements for the classes and interfaces + * referenced in the extends/implements clauses of the given type element. TODO: can we learn from + * the implementation of com.sun.tools.javac.model.JavacElements.getAllMembers(TypeElement)? + */ + public static List getSuperTypes(Elements elements, TypeElement type) { + + List superelems = new ArrayList<>(); + if (type == null) { + return superelems; + } + + // Set up a stack containing type, which is our starting point. + Deque stack = new ArrayDeque<>(); + stack.push(type); + + while (!stack.isEmpty()) { + TypeElement current = stack.pop(); + + // For each direct supertype of the current type element, if it + // hasn't already been visited, push it onto the stack and + // add it to our superelems set. + TypeMirror supertypecls = current.getSuperclass(); + if (supertypecls.getKind() != TypeKind.NONE) { + TypeElement supercls = (TypeElement) ((DeclaredType) supertypecls).asElement(); + if (!superelems.contains(supercls)) { + stack.push(supercls); + superelems.add(supercls); + } + } + for (TypeMirror supertypeitf : current.getInterfaces()) { + TypeElement superitf = (TypeElement) ((DeclaredType) supertypeitf).asElement(); + if (!superelems.contains(superitf)) { + stack.push(superitf); + superelems.add(superitf); + } + } + } + + // Include java.lang.Object as implicit superclass for all classes and interfaces. + TypeElement jlobject = elements.getTypeElement(Object.class.getCanonicalName()); + if (!superelems.contains(jlobject)) { + superelems.add(jlobject); + } + + return Collections.unmodifiableList(superelems); + } + + + /** + * @url {https://github.com/hibernate/hibernate-metamodelgen/blob/master/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java} + */ + public static boolean containsAnnotation(Element element, String... annotations) { + assert element != null; + assert annotations != null; + + List annotationClassNames = new ArrayList<>(); + Collections.addAll(annotationClassNames, annotations); + + List annotationMirrors = element.getAnnotationMirrors(); + for (AnnotationMirror mirror : annotationMirrors) { + if (annotationClassNames.contains(mirror.getAnnotationType().toString())) { + return true; + } + } + return false; + } + + /** + * + * @url {https://github.com/hibernate/hibernate-metamodelgen/blob/master/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java} + * + * Returns {@code true} if the provided annotation type is of the same type as the provided + * class, {@code false} otherwise. This method uses the string class names for comparison. + * See also getting-class-values-from-annotations. + * + * @param annotationMirror The annotation mirror + * @param fqcn the fully qualified class name to check against + * + * @return {@code true} if the provided annotation type is of the same type as the provided class, + * {@code false} otherwise. + */ + public static boolean isAnnotationMirrorOfType(AnnotationMirror annotationMirror, String fqcn) { + assert annotationMirror != null; + assert fqcn != null; + String annotationClassName = annotationMirror.getAnnotationType().toString(); + + return annotationClassName.equals(fqcn); + } + + /** + * @url {https://github.com/hibernate/hibernate-metamodelgen/blob/master/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java} + */ + public static Object getAnnotationValue(AnnotationMirror annotationMirror, + String parameterValue) { + assert annotationMirror != null; + assert parameterValue != null; + + Object returnValue = null; + for (Map.Entry entry : annotationMirror + .getElementValues().entrySet()) { + if (parameterValue.equals(entry.getKey().getSimpleName().toString())) { + returnValue = entry.getValue().getValue(); + break; + } + } + return returnValue; + } + } diff --git a/processor/src/main/java/io/crysknife/validation/InjectionPointValidator.java b/processor/src/main/java/io/crysknife/validation/InjectionPointValidator.java new file mode 100644 index 00000000..9653e6a1 --- /dev/null +++ b/processor/src/main/java/io/crysknife/validation/InjectionPointValidator.java @@ -0,0 +1,151 @@ +/* + * 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.validation; + +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.util.Utils; + +import javax.inject.Named; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.VariableElement; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/3/21 + */ +public class InjectionPointValidator { + + private FieldValidator fieldValidator; + private IOCContext context; + + private Set checks = new HashSet() { + { + add(new Check() { + @Override + public void check(VariableElement variableElement) throws UnableToCompleteException { + if (variableElement.getModifiers().contains(Modifier.ABSTRACT)) { + log(variableElement, "Field injection point must not be abstract"); + } + } + }); + + add(new Check() { + @Override + public void check(VariableElement variableElement) throws UnableToCompleteException { + List qualifiers = + Utils.getAllElementQualifierAnnotations(context, variableElement); + if (qualifiers.size() > 1) { + log(variableElement, + "Injection point must be annotated with only one @Qualifier, but there is " + + qualifiers.size()); + } + Named named = variableElement.getAnnotation(Named.class); + if (named != null && !qualifiers.isEmpty()) { + log(variableElement, + "Injection point must be annotated with @Named or @Qualifier, but not both at the same time"); + } + } + }); + } + }; + + + public InjectionPointValidator(IOCContext context, Element parent) { + this.context = context; + if (parent.getKind().equals(ElementKind.CLASS)) { + fieldValidator = new InjectionPointFieldValidator(this); + } else if (parent.getKind().equals(ElementKind.CONSTRUCTOR)) { + fieldValidator = new InjectionPointConstructorValidator(this); + } + } + + public void validate(VariableElement variableElement) throws UnableToCompleteException { + fieldValidator.validate(variableElement); + } + + private interface FieldValidator { + + void validate(VariableElement variableElement) throws UnableToCompleteException; + } + + private interface Check { + + void check(VariableElement variableElement) throws UnableToCompleteException; + + default void log(VariableElement variableElement, String msg) throws UnableToCompleteException { + StringBuffer sb = new StringBuffer(); + sb.append("Error at ").append(variableElement.getEnclosingElement()).append(".") + .append(variableElement.getSimpleName()).append(" : ").append(msg); + throw new UnableToCompleteException(sb.toString()); + } + } + + private static class InjectionPointFieldValidator implements FieldValidator { + + private Set checks = new HashSet<>(); + + private InjectionPointFieldValidator(InjectionPointValidator validator) { + checks.addAll(validator.checks); + + checks.add(new Check() { + @Override + public void check(VariableElement variableElement) throws UnableToCompleteException { + if (variableElement.getModifiers().contains(Modifier.FINAL)) { + log(variableElement, "Field injection point must not be final"); + } + } + }); + + checks.add(new Check() { + @Override + public void check(VariableElement variableElement) throws UnableToCompleteException { + if (variableElement.getModifiers().contains(Modifier.FINAL)) { + log(variableElement, "Field injection point must not be final"); + } + } + }); + + } + + @Override + public void validate(VariableElement variableElement) throws UnableToCompleteException { + for (Check check : checks) { + check.check(variableElement); + } + } + } + + private static class InjectionPointConstructorValidator implements FieldValidator { + + private Set checks = new HashSet<>(); + + private InjectionPointConstructorValidator(InjectionPointValidator validator) { + checks.addAll(validator.checks); + } + + @Override + public void validate(VariableElement variableElement) throws UnableToCompleteException { + for (Check check : checks) { + check.check(variableElement); + } + } + } +} diff --git a/processor/src/main/java/io/crysknife/validation/ProducesValidator.java b/processor/src/main/java/io/crysknife/validation/ProducesValidator.java new file mode 100644 index 00000000..c813b133 --- /dev/null +++ b/processor/src/main/java/io/crysknife/validation/ProducesValidator.java @@ -0,0 +1,96 @@ +/* + * 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.validation; + +import com.google.auto.common.MoreElements; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.context.IOCContext; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.VariableElement; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/6/21 + */ +public class ProducesValidator { + + private final IOCContext context; + + private Set checks = new HashSet() { + { + add(new Check() { + @Override + public void check(ExecutableElement variableElement) throws UnableToCompleteException { + if (variableElement.getModifiers().contains(Modifier.ABSTRACT)) { + log(variableElement, "@Produces method must not be abstract"); + } + } + }); + + add(new Check() { + @Override + public void check(ExecutableElement variableElement) throws UnableToCompleteException { + if (!variableElement.getModifiers().contains(Modifier.PUBLIC)) { + log(variableElement, "@Produces method must be public"); + } + } + }); + + add(new Check() { + @Override + public void check(ExecutableElement variableElement) throws UnableToCompleteException { + if (!variableElement.getParameters().isEmpty()) { + log(variableElement, "@Produces method must have no args"); + } + } + }); + } + }; + + public ProducesValidator(IOCContext context) { + this.context = context; + } + + public void validate(Element element) throws UnableToCompleteException { + if (element.getKind().isField()) { + VariableElement field = MoreElements.asVariable(element); + StringBuffer sb = new StringBuffer(); + sb.append("Error at ").append(field.getEnclosingElement()).append(".") + .append(field.getSimpleName()).append(" : ") + .append(" Only method can be annotated with @Produces"); + throw new UnableToCompleteException(sb.toString()); + } + + for (Check check : checks) { + check.check(MoreElements.asExecutable(element)); + } + } + + private interface Check { + + void check(ExecutableElement variableElement) throws UnableToCompleteException; + + default void log(Element variableElement, String msg) throws UnableToCompleteException { + StringBuffer sb = new StringBuffer(); + sb.append("Error at ").append(variableElement.getEnclosingElement()).append(".") + .append(variableElement.getSimpleName()).append(" : ").append(msg); + throw new UnableToCompleteException(sb.toString()); + } + } +} diff --git a/tests/src/main/java/org/treblereel/produces/qualifier/QualifierBean.java b/processor/src/main/java/io/crysknife/validation/ScopedBeanValidator.java similarity index 79% rename from tests/src/main/java/org/treblereel/produces/qualifier/QualifierBean.java rename to processor/src/main/java/io/crysknife/validation/ScopedBeanValidator.java index 37ec071a..b037b328 100644 --- a/tests/src/main/java/org/treblereel/produces/qualifier/QualifierBean.java +++ b/processor/src/main/java/io/crysknife/validation/ScopedBeanValidator.java @@ -12,12 +12,10 @@ * the License. */ -package org.treblereel.produces.qualifier; +package io.crysknife.validation; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/13/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/5/21 */ -public interface QualifierBean { - - String say(); +public class ScopedBeanValidator { } diff --git a/processor/src/test/java/io/crysknife/client/internal/Graph.java b/processor/src/test/java/io/crysknife/client/internal/Graph.java new file mode 100644 index 00000000..3cf8488f --- /dev/null +++ b/processor/src/test/java/io/crysknife/client/internal/Graph.java @@ -0,0 +1,81 @@ +/* + * 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 java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class Graph { + + private List vertices; + + public Optional> pair = Optional.empty(); + + public Graph() { + this.vertices = new ArrayList<>(); + } + + public Graph(List vertices) { + this.vertices = vertices; + } + + public void addVertex(Vertex vertex) { + this.vertices.add(vertex); + } + + public void addEdge(Vertex from, Vertex to) { + from.addNeighbour(to); + } + + public boolean hasCycle() { + for (Vertex vertex : vertices) { + if (!vertex.isVisited() && hasCycle(vertex)) { + return true; + } + } + return false; + } + + public boolean hasCycle(Vertex sourceVertex) { + sourceVertex.setBeingVisited(true); + + for (Vertex neighbour : sourceVertex.getAdjacencyList()) { + if (neighbour.isBeingVisited()) { + pair = Optional.of(new Pair<>(sourceVertex, neighbour)); + // backward edge exists + return true; + } else if (!neighbour.isVisited() && hasCycle(neighbour)) { + return true; + } + } + + sourceVertex.setBeingVisited(false); + sourceVertex.setVisited(true); + return false; + } + + public static class Pair { + T a; + T b; + + Pair(T a, T b) { + this.a = a; + this.b = b; + } + + } + +} diff --git a/processor/src/test/java/io/crysknife/client/internal/GraphCycleTest.java b/processor/src/test/java/io/crysknife/client/internal/GraphCycleTest.java new file mode 100644 index 00000000..8c323ee1 --- /dev/null +++ b/processor/src/test/java/io/crysknife/client/internal/GraphCycleTest.java @@ -0,0 +1,84 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class GraphCycleTest { + + @Test + public void test() { + + Vertex vertex0 = new Vertex("0"); + Vertex vertexA = new Vertex("A"); + Vertex vertexB = new Vertex("B"); + Vertex vertexC = new Vertex("C"); + Vertex vertexD = new Vertex("D"); + Vertex vertexE = new Vertex("E"); + Vertex vertexF = new Vertex("F"); + Vertex vertexG = new Vertex("G"); + + Graph graph = new Graph(); + graph.addVertex(vertex0); + graph.addVertex(vertexA); + graph.addVertex(vertexB); + graph.addVertex(vertexC); + graph.addVertex(vertexD); + + graph.addEdge(vertexA, vertexB); + graph.addEdge(vertexA, vertexG); + graph.addEdge(vertexB, vertexC); + graph.addEdge(vertexC, vertexD); + graph.addEdge(vertexD, vertexE); + graph.addEdge(vertexE, vertexA); + graph.addEdge(vertexE, vertexF); + + + graph.addEdge(vertexE, vertexF); + graph.addEdge(vertexF, vertexG); + graph.addEdge(vertexG, vertexE); + graph.addEdge(vertexG, vertex0); + + assertTrue(graph.hasCycle()); + assertEquals(vertexE, graph.pair.get().a); + assertEquals(vertexA, graph.pair.get().b); + } + + @Test + public void negative() { + + Vertex vertexA = new Vertex("A"); + Vertex vertexB = new Vertex("B"); + Vertex vertexC = new Vertex("C"); + Vertex vertexD = new Vertex("D"); + + Graph graph = new Graph(); + graph.addVertex(vertexA); + graph.addVertex(vertexB); + graph.addVertex(vertexC); + graph.addVertex(vertexD); + + graph.addEdge(vertexA, vertexB); + graph.addEdge(vertexB, vertexC); + graph.addEdge(vertexA, vertexC); + graph.addEdge(vertexD, vertexC); + + assertFalse(graph.hasCycle()); + } +} diff --git a/processor/src/test/java/org/treblereel/gwt/crysknife/client/internal/GraphTest.java b/processor/src/test/java/io/crysknife/client/internal/GraphTest.java similarity index 90% rename from processor/src/test/java/org/treblereel/gwt/crysknife/client/internal/GraphTest.java rename to processor/src/test/java/io/crysknife/client/internal/GraphTest.java index 3e6b4de3..655cdd36 100644 --- a/processor/src/test/java/org/treblereel/gwt/crysknife/client/internal/GraphTest.java +++ b/processor/src/test/java/io/crysknife/client/internal/GraphTest.java @@ -19,7 +19,7 @@ import com.google.common.graph.Traverser; import org.junit.Test; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; /** * @author Dmitrii Tikhomirov Created by treblereel 2/21/19 @@ -28,6 +28,7 @@ public class GraphTest { @Test public void testGraph() { + MutableGraph graph = GraphBuilder.directed().build(); graph.addNode("A"); graph.addNode("B"); @@ -43,10 +44,12 @@ public void testGraph() { graph.putEdge("D", "E"); graph.putEdge("E", "F"); + StringBuffer sb = new StringBuffer(); + Traverser.forGraph(graph).depthFirstPostOrder("A").forEach(n -> { - System.out.println(n); + sb.append(n); }); - assertTrue(true); + assertEquals("FEDCBA", sb.toString()); } } diff --git a/processor/src/test/java/io/crysknife/client/internal/Vertex.java b/processor/src/test/java/io/crysknife/client/internal/Vertex.java new file mode 100644 index 00000000..e4c7a050 --- /dev/null +++ b/processor/src/test/java/io/crysknife/client/internal/Vertex.java @@ -0,0 +1,70 @@ +/* + * 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 java.util.ArrayList; +import java.util.List; + +public class Vertex { + + private String label; + + private boolean visited; + + private boolean beingVisited; + + private List adjacencyList; + + public Vertex(String label) { + this.label = label; + this.adjacencyList = new ArrayList<>(); + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public boolean isVisited() { + return visited; + } + + public void setVisited(boolean visited) { + this.visited = visited; + } + + public boolean isBeingVisited() { + return beingVisited; + } + + public void setBeingVisited(boolean beingVisited) { + this.beingVisited = beingVisited; + } + + public List getAdjacencyList() { + return adjacencyList; + } + + public void setAdjacencyList(List adjacencyList) { + this.adjacencyList = adjacencyList; + } + + public void addNeighbour(Vertex adjacent) { + this.adjacencyList.add(adjacent); + } +} diff --git a/tests/j2cl-tests/pom.xml b/tests/j2cl-tests/pom.xml deleted file mode 100644 index 25343ec9..00000000 --- a/tests/j2cl-tests/pom.xml +++ /dev/null @@ -1,140 +0,0 @@ - - - 4.0.0 - - j2cl-tests - io.crysknife - 0.3-SNAPSHOT - jar - - - UTF-8 - 1.8 - 1.8 - - ${project.build.directory}/webapp - ${webappdir}/WEB-INF/lib - - 3.8.0 - 1.0.0 - true - 0.17-SNAPSHOT - 3.0.0-M1 - 3.0.0-M1 - - 4.13.1 - - https://repo.vertispan.com/j2cl/ - 0.9-SNAPSHOT - - - - - - io.crysknife - crysknife-processor - ${project.version} - provided - - - - io.crysknife - crysknife-core - ${project.version} - - - - com.vertispan.j2cl - junit-annotations - ${j2cl.version} - test - - - com.vertispan.j2cl - gwttestcase-emul - ${j2cl.version} - sources - test - - - com.vertispan.j2cl - junit-emul - ${j2cl.version} - test - - - junit - junit - ${junit.version} - test - - - - - - - src/main/resources - - - - - maven-compiler-plugin - ${maven.compiler.plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - - - - com.vertispan.j2cl - j2cl-maven-plugin - ${maven.j2cl.plugin} - - chrome - ADVANCED - - - - j2cl-test - test - - test - - - - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven.surfire.plugin} - - true - - - - org.apache.maven.plugins - maven-deploy-plugin - ${maven.deploy.plugin} - - true - - - - - - - - ${vertispan.j2cl.repo.id} - ${vertispan.j2cl.repo.name} - ${vertispan.j2cl.repo.url} - - - - - - vertispan-releases - Vertispan hosted artifacts-releases - ${vertispan.j2cl.repo.url} - - - diff --git a/tests/j2cl-tests/src/test/java/org/treblereel/SimpleBeanTest.java b/tests/j2cl-tests/src/test/java/org/treblereel/SimpleBeanTest.java deleted file mode 100644 index c131796c..00000000 --- a/tests/j2cl-tests/src/test/java/org/treblereel/SimpleBeanTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 org.treblereel; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.google.j2cl.junit.apt.J2clTestInput; -import org.junit.Before; -import org.junit.Test; -import org.treblereel.managedinstance.ComponentIface; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 9/10/19 - */ -@J2clTestInput(SimpleBeanTest.class) -public class SimpleBeanTest { - private final App app = new App(); - - @Before - public void init() { - new org.treblereel.AppBootstrap(app).initialize(); - } - - @Test - public void testAppSimpleBean() { - assertTrue(app.initialized); - assertNotNull(app.getComponentIfaces()); - } - - @Test - public void testManagedInstance() { - assertTrue(app.initialized); - assertNotNull(app.getComponentIfaces().get().getComponentName()); - - List actualList = new ArrayList<>(); - Iterator iter = app.getComponentIfaces().iterator(); - while (iter.hasNext()) { - actualList.add(iter.next()); - } - - assertEquals(3, actualList.size()); - assertEquals("ComponentDefault", app.getComponentIfaces().get().getComponentName()); - } -} diff --git a/tests/jre-tests/pom.xml b/tests/jre-tests/pom.xml index 3039594f..bc52a87d 100644 --- a/tests/jre-tests/pom.xml +++ b/tests/jre-tests/pom.xml @@ -59,6 +59,7 @@ + org.apache.maven.plugins maven-compiler-plugin ${maven.compiler.plugin.version} diff --git a/tests/jre-tests/src/main/java/org/treblereel/App.java b/tests/jre-tests/src/main/java/org/treblereel/App.java index bd41ac4c..8755000e 100644 --- a/tests/jre-tests/src/main/java/org/treblereel/App.java +++ b/tests/jre-tests/src/main/java/org/treblereel/App.java @@ -22,12 +22,18 @@ import org.treblereel.injection.applicationscoped.SimpleBeanApplicationScoped; import org.treblereel.injection.dependent.SimpleBeanDependent; import org.treblereel.injection.dependent.SimpleDependentTest; +import org.treblereel.injection.inheritance.InheritanceBean; import org.treblereel.injection.managedinstance.ManagedInstanceBean; import org.treblereel.injection.named.NamedTestBean; import org.treblereel.injection.qualifiers.QualifierConstructorInjection; import org.treblereel.injection.qualifiers.QualifierFieldInjection; +import org.treblereel.injection.qualifiers.controls.NodeBuilderControl; +import org.treblereel.injection.qualifiers.specializes.SpecializesBeanHolder; import org.treblereel.injection.singleton.SimpleBeanSingleton; import org.treblereel.injection.singleton.SimpleSingletonTest; +import org.treblereel.postconstruct.Child; +import org.treblereel.postconstruct.ChildTwo; +import org.treblereel.postconstruct.PostConstructs; import org.treblereel.produces.SimpleBeanProducerTest; import org.treblereel.produces.qualifier.QualifierBeanProducerTest; @@ -65,7 +71,19 @@ public class App { private ManagedInstanceBean managedInstanceBean; @Inject - protected BeanManager beanManager; + public BeanManager beanManager; + + @Inject + protected PostConstructs postConstructs; + + @Inject + public InheritanceBean inheritanceBean; + + @Inject + public NodeBuilderControl nodeBuilderControl; + + @Inject + public SpecializesBeanHolder specializesBeanHolder; public void onModuleLoad() { new AppBootstrap(this).initialize(); diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AbstractRegistryFactory.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AbstractRegistryFactory.java new file mode 100644 index 00000000..2f5fb24b --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AbstractRegistryFactory.java @@ -0,0 +1,36 @@ +/* + * Copyright © 2021 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.injection.cycle; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/15/21 + */ +public abstract class AbstractRegistryFactory implements RegistryFactory { + + public AdapterManager adapterManager; + + protected AbstractRegistryFactory() {} + + public AbstractRegistryFactory(final AdapterManager adapterManager) { + this.adapterManager = adapterManager; + } + + @Override + public AdapterRegistry newAdapterRegistry() { + return new AdapterRegistryImpl(); + } + + +} diff --git a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentIface.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterManager.java similarity index 78% rename from tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentIface.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterManager.java index 0aecdd61..ab7769b4 100644 --- a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentIface.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterManager.java @@ -12,14 +12,13 @@ * the License. */ -package org.treblereel.managedinstance; +package org.treblereel.injection.cycle; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 + * @author Dmitrii Tikhomirov Created by treblereel 9/15/21 */ -public interface ComponentIface { +public interface AdapterManager { - - String getComponentName(); + AdapterRegistry registry(); } diff --git a/tests/j2cl-tests/src/main/java/org/treblereel/App.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterManagerImpl.java similarity index 51% rename from tests/j2cl-tests/src/main/java/org/treblereel/App.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterManagerImpl.java index e465cc86..ef86d903 100644 --- a/tests/j2cl-tests/src/main/java/org/treblereel/App.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterManagerImpl.java @@ -12,37 +12,38 @@ * the License. */ -package org.treblereel; +package org.treblereel.injection.cycle; + +import io.crysknife.annotation.CircularDependency; +import io.crysknife.client.ManagedInstance; import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; -import elemental2.dom.DomGlobal; -import io.crysknife.annotation.Application; -import io.crysknife.annotation.ComponentScan; -import io.crysknife.client.ManagedInstance; -import org.treblereel.managedinstance.ComponentIface; - /** - * @author Dmitrii Tikhomirov - * Created by treblereel 4/27/21 + * @author Dmitrii Tikhomirov Created by treblereel 9/15/21 */ -@Application -@ComponentScan("io.crysknife") -public class App { +@CircularDependency +@ApplicationScoped +public class AdapterManagerImpl implements AdapterManager { + + public AdapterRegistry registry; - boolean initialized = false; + @Inject + public RegistryFactory registryFactory; - @Inject - private ManagedInstance componentIfaces; + @Inject + public AdapterManagerImpl(RegistryFactory registryFactory) { + this(new AdapterRegistryImpl()); + } - @PostConstruct - public void init () { - assert componentIfaces != null; - initialized = true; - } + AdapterManagerImpl(final AdapterRegistry registry) { + this.registry = registry; + } - public ManagedInstance getComponentIfaces() { - return componentIfaces; - } + @Override + public AdapterRegistry registry() { + return registry; + } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterRegistry.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterRegistry.java new file mode 100644 index 00000000..2f38f0fb --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterRegistry.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2021 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.injection.cycle; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/15/21 + */ +public interface AdapterRegistry { +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterRegistryImpl.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterRegistryImpl.java new file mode 100644 index 00000000..139fb568 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/AdapterRegistryImpl.java @@ -0,0 +1,22 @@ +/* + * Copyright © 2021 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.injection.cycle; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/15/21 + */ +public class AdapterRegistryImpl implements AdapterRegistry { + +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/ClientRegistryFactory.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/ClientRegistryFactory.java new file mode 100644 index 00000000..a1c332ac --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/ClientRegistryFactory.java @@ -0,0 +1,22 @@ +/* + * Copyright © 2021 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.injection.cycle; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/15/21 + */ +public interface ClientRegistryFactory extends RegistryFactory { + +} diff --git a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ManagedInstanceBean.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/ClientRegistryFactoryImpl.java similarity index 62% rename from tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ManagedInstanceBean.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/cycle/ClientRegistryFactoryImpl.java index bcd83db5..d5661646 100644 --- a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ManagedInstanceBean.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/ClientRegistryFactoryImpl.java @@ -12,34 +12,26 @@ * the License. */ -package org.treblereel.managedinstance; +package org.treblereel.injection.cycle; + +import io.crysknife.annotation.CircularDependency; +import io.crysknife.client.ManagedInstance; -import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; -import io.crysknife.client.BeanManager; -import io.crysknife.client.ManagedInstance; - /** - * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 + * @author Dmitrii Tikhomirov Created by treblereel 9/15/21 */ @ApplicationScoped -public class ManagedInstanceBean { +@CircularDependency +public class ClientRegistryFactoryImpl extends AbstractRegistryFactory + implements ClientRegistryFactory { - @Inject - private BeanManager beanManager; + protected ClientRegistryFactoryImpl() {} @Inject - private ManagedInstance managedInstanceBean; - - @PostConstruct - void init() { - + public ClientRegistryFactoryImpl(final AdapterManager adapterManager) { + super(adapterManager); } - - public ManagedInstance getManagedInstanceBean() { - return managedInstanceBean; - } - } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/RegistryFactory.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/RegistryFactory.java new file mode 100644 index 00000000..e0911672 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/RegistryFactory.java @@ -0,0 +1,23 @@ +/* + * Copyright © 2021 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.injection.cycle; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/15/21 + */ +public interface RegistryFactory { + + AdapterRegistry newAdapterRegistry(); +} diff --git a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentTwo.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/FieldInjectBean.java similarity index 75% rename from tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentTwo.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/FieldInjectBean.java index 0653daff..dba115ac 100644 --- a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentTwo.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/FieldInjectBean.java @@ -12,19 +12,17 @@ * the License. */ -package org.treblereel.managedinstance; +package org.treblereel.injection.cycle.simple; import javax.enterprise.context.ApplicationScoped; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 + * @author Dmitrii Tikhomirov Created by treblereel 10/4/21 */ @ApplicationScoped -@ComponentQualifierTwo -public class ComponentTwo implements ComponentIface { +public class FieldInjectBean { - @Override - public String getComponentName() { + public String hello() { return getClass().getSimpleName(); } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanOne.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanOne.java new file mode 100644 index 00000000..56768fc6 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanOne.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2021 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.injection.cycle.simple; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/26/21 + */ +public interface SimpleBeanOne { + + String whoAmI(); + + String whoIsDep(); + + String getPostConstruct(); + +} diff --git a/tests/src/main/java/org/treblereel/injection/applicationscoped/SimpleBeanApplicationScoped.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanOneImpl.java similarity index 51% rename from tests/src/main/java/org/treblereel/injection/applicationscoped/SimpleBeanApplicationScoped.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanOneImpl.java index 52514e38..9a8c6199 100644 --- a/tests/src/main/java/org/treblereel/injection/applicationscoped/SimpleBeanApplicationScoped.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanOneImpl.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,28 +12,48 @@ * the License. */ -package org.treblereel.injection.applicationscoped; +package org.treblereel.injection.cycle.simple; + +import io.crysknife.annotation.CircularDependency; import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; /** - * @author Dmitrii Tikhomirov Created by treblereel 3/21/20 + * @author Dmitrii Tikhomirov Created by treblereel 9/26/21 */ @ApplicationScoped -public class SimpleBeanApplicationScoped { +@CircularDependency +public class SimpleBeanOneImpl implements SimpleBeanOne { + + private SimpleBeanTwoImpl simpleBeanTwo; - private String postConstruct; + @Inject + public FieldInjectBean fieldInjectBean; - public String getName() { - return this.getClass().getSimpleName(); + public String postConstruct; + + @Inject + public SimpleBeanOneImpl(SimpleBeanTwoImpl simpleBeanTwo) { + this.simpleBeanTwo = simpleBeanTwo; } @PostConstruct public void init() { - postConstruct = "done"; + postConstruct = getClass().getSimpleName() + ".init"; + } + + @Override + public String whoAmI() { + return getClass().getSimpleName(); + } + + public String whoIsDep() { + return simpleBeanTwo.whoAmI(); } + @Override public String getPostConstruct() { return postConstruct; } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanTwo.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanTwo.java new file mode 100644 index 00000000..4ffe33ff --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanTwo.java @@ -0,0 +1,27 @@ +/* + * Copyright © 2021 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.injection.cycle.simple; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/26/21 + */ +public interface SimpleBeanTwo { + + String whoAmI(); + + String whoIsDep(); + + String getPostConstruct(); +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanTwoImpl.java b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanTwoImpl.java new file mode 100644 index 00000000..93f2dc05 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/cycle/simple/SimpleBeanTwoImpl.java @@ -0,0 +1,60 @@ +/* + * Copyright © 2021 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.injection.cycle.simple; + +import io.crysknife.annotation.CircularDependency; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/26/21 + */ +@Singleton +@CircularDependency +public class SimpleBeanTwoImpl implements SimpleBeanTwo { + + private SimpleBeanOneImpl simpleBeanOne; + + public String postConstruct; + + @Inject + public FieldInjectBean fieldInjectBean; + + @Inject + public SimpleBeanTwoImpl(SimpleBeanOneImpl simpleBeanOne) { + this.simpleBeanOne = simpleBeanOne; + } + + @PostConstruct + public void init() { + postConstruct = getClass().getSimpleName() + ".init"; + } + + @Override + public String whoAmI() { + return getClass().getSimpleName(); + } + + public String whoIsDep() { + return simpleBeanOne.whoAmI(); + } + + @Override + public String getPostConstruct() { + return postConstruct; + } +} diff --git a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBeanOne.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/BeanChild.java similarity index 67% rename from tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBeanOne.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/BeanChild.java index 85ec0d5b..7aea3e15 100644 --- a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBeanOne.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/BeanChild.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,20 +12,21 @@ * the License. */ -package org.treblereel.injection.qualifiers; +package org.treblereel.injection.inheritance; +import javax.inject.Inject; import javax.inject.Singleton; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/13/19 + * @author Dmitrii Tikhomirov Created by treblereel 8/21/21 */ -@QualifierOne @Singleton -public class QualifierBeanOne implements QualifierBean { +public class BeanChild extends Parent { - @Override - public String say() { - return this.getClass().getCanonicalName(); - } + @Inject + public Target test; + public Target getTarget() { + return target; + } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/InheritanceBean.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/InheritanceBean.java new file mode 100644 index 00000000..a181314a --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/InheritanceBean.java @@ -0,0 +1,32 @@ +/* + * Copyright © 2021 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.injection.inheritance; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/21/21 + */ +@Singleton +public class InheritanceBean { + + @Inject + private BeanChild bean; + + public BeanChild getBean() { + return bean; + } +} diff --git a/tests/src/test/java/org/treblereel/AbstractTest.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/Parent.java similarity index 67% rename from tests/src/test/java/org/treblereel/AbstractTest.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/Parent.java index 01f74fae..431cf2a7 100644 --- a/tests/src/test/java/org/treblereel/AbstractTest.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/Parent.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,20 +12,20 @@ * the License. */ -package org.treblereel; +package org.treblereel.injection.inheritance; -import org.junit.Before; +import javax.inject.Inject; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 + * @author Dmitrii Tikhomirov Created by treblereel 8/21/21 */ -public class AbstractTest { +public class Parent { - protected App app = new App(); + @Inject + public Target target; - @Before - public void init() { - new AppBootstrap(app).initialize(); + public Target getParentTarget() { + return target; } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/Target.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/Target.java new file mode 100644 index 00000000..39e36a78 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/Target.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2021 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.injection.inheritance; + +import javax.inject.Singleton; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/21/21 + */ +@Singleton +public class Target { + + public String hello() { + return getClass().getCanonicalName(); + } +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/AbstractTypeDefinitionFactory.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/AbstractTypeDefinitionFactory.java new file mode 100644 index 00000000..c06fcf7a --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/AbstractTypeDefinitionFactory.java @@ -0,0 +1,48 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates. + * + * 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.injection.inheritance.factories; + +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/24/21 + */ +public abstract class AbstractTypeDefinitionFactory implements TypeDefinitionFactory { + + @Override + public boolean accepts(final Class type) { + return getAcceptedClasses().contains(type); + } + + public abstract Set> getAcceptedClasses(); + + @Override + public boolean accepts(final String id) { + return getClass(id) != null; + } + + @Override + public T build(final String id) { + final Class clazz = getClass(id); + if (null != clazz) { + return build(clazz); + } + return null; + } + + protected Class getClass(final String id) { + return null; + } +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/BPMNDefinitionSetModelFactoryImpl.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/BPMNDefinitionSetModelFactoryImpl.java new file mode 100644 index 00000000..6bce073c --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/BPMNDefinitionSetModelFactoryImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates. + * + * 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.injection.inheritance.factories; + +import javax.enterprise.context.ApplicationScoped; +import java.util.Set; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/24/21 + */ +@ApplicationScoped +public class BPMNDefinitionSetModelFactoryImpl extends AbstractTypeDefinitionFactory { + + + @Override + public Set> getAcceptedClasses() { + return null; + } + + @Override + public Object build(Class type) { + return null; + } +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/CustomTask.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/CustomTask.java new file mode 100644 index 00000000..1c1c4b32 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/CustomTask.java @@ -0,0 +1,21 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates. + * + * 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.injection.inheritance.factories; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/24/21 + */ +public class CustomTask { +} diff --git a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentDefault.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/CustomTaskFactory.java similarity index 62% rename from tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentDefault.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/CustomTaskFactory.java index 3b430f3c..23f2cab5 100644 --- a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentDefault.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/CustomTaskFactory.java @@ -1,5 +1,5 @@ /* - * Copyright © 2021 Treblereel + * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * 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 @@ -12,20 +12,23 @@ * the License. */ -package org.treblereel.managedinstance; +package org.treblereel.injection.inheritance.factories; import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.inject.Default; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 + * @author Dmitrii Tikhomirov Created by treblereel 9/24/21 */ -@Default @ApplicationScoped -public class ComponentDefault implements ComponentIface { +public class CustomTaskFactory implements DefinitionFactory { @Override - public String getComponentName() { - return getClass().getSimpleName(); + public boolean accepts(String identifier) { + return false; + } + + @Override + public CustomTask build(String identifier) { + return null; } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/DefinitionFactory.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/DefinitionFactory.java new file mode 100644 index 00000000..f09a5033 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/DefinitionFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates. + * + * 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.injection.inheritance.factories; + +/** + * Factory for Definition domain objects. The identifier argument for + * accepts and build methods corresponds with the definition type + * identifier. ( Eg: Task, Rectangle ). + */ +public interface DefinitionFactory extends Factory { + + boolean accepts(final String identifier); + + T build(final String identifier); +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/Factory.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/Factory.java new file mode 100644 index 00000000..71b1c3c9 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/Factory.java @@ -0,0 +1,21 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates. + * + * 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.injection.inheritance.factories; + +public interface Factory { + + boolean accepts(final S source); +} + diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/FactoryHolder.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/FactoryHolder.java new file mode 100644 index 00000000..b449f170 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/FactoryHolder.java @@ -0,0 +1,42 @@ +/* + * Copyright © 2021 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.injection.inheritance.factories; + +import io.crysknife.client.ManagedInstance; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/24/21 + */ +@ApplicationScoped +public class FactoryHolder { + + private final ManagedInstance definitionFactoryInstances; + + @Inject + private ManagedInstance definitionFactoryInstances2; + + @Inject + public FactoryHolder(final ManagedInstance definitionFactoryInstances) { + this.definitionFactoryInstances = definitionFactoryInstances; + } + + + public ManagedInstance getDefinitionFactoryInstances() { + return definitionFactoryInstances; + } +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/TypeDefinitionFactory.java b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/TypeDefinitionFactory.java new file mode 100644 index 00000000..b3e9313f --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/inheritance/factories/TypeDefinitionFactory.java @@ -0,0 +1,25 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates. + * + * 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.injection.inheritance.factories; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/24/21 + */ +public interface TypeDefinitionFactory extends DefinitionFactory { + + boolean accepts(final Class type); + + T build(final Class type); +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/managedinstance/ManagedInstanceBean.java b/tests/jre-tests/src/main/java/org/treblereel/injection/managedinstance/ManagedInstanceBean.java index 224aa7f2..54282c96 100644 --- a/tests/jre-tests/src/main/java/org/treblereel/injection/managedinstance/ManagedInstanceBean.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/managedinstance/ManagedInstanceBean.java @@ -14,15 +14,14 @@ package org.treblereel.injection.managedinstance; -import java.lang.annotation.Annotation; +import io.crysknife.client.BeanManager; +import io.crysknife.client.ManagedInstance; +import org.treblereel.injection.dependent.SimpleBeanDependent; +import org.treblereel.produces.qualifier.QualifierBean; -import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Instance; import javax.inject.Inject; -import javax.inject.Named; - -import io.crysknife.client.BeanManager; -import io.crysknife.client.ManagedInstance; /** * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 @@ -33,15 +32,53 @@ public class ManagedInstanceBean { @Inject private BeanManager beanManager; + @Inject private ManagedInstance managedInstanceBean; - @PostConstruct - void init() { - managedInstanceBean = new ManagedInstanceImpl<>(ComponentIface.class, beanManager); + @Inject + private ManagedInstance InstanceBean; + + @Inject + private Instance bean; + + @Inject + private Instance bean2; + + @Inject + public Instance simpleBean1; + + @Inject + public ManagedInstance simpleBean2; + + public Instance constructor_simpleBean1; + + public ManagedInstance constructor_simpleBean2; + + public ManagedInstanceBean() { + + } + + @Inject + public ManagedInstanceBean(Instance simpleBean1, + ManagedInstance simpleBean2) { + this.constructor_simpleBean1 = simpleBean1; + this.constructor_simpleBean2 = simpleBean2; } + public ManagedInstance getManagedInstanceBean() { return managedInstanceBean; } + public ManagedInstance getInstanceBean() { + return InstanceBean; + } + + public Instance getBean() { + return bean; + } + + public Instance getBean2() { + return bean2; + } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/managedinstance/ManagedInstanceImpl.java b/tests/jre-tests/src/main/java/org/treblereel/injection/managedinstance/ManagedInstanceImpl.java deleted file mode 100644 index 650322e1..00000000 --- a/tests/jre-tests/src/main/java/org/treblereel/injection/managedinstance/ManagedInstanceImpl.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright © 2021 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.injection.managedinstance; - -import java.lang.annotation.Annotation; -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; - -import io.crysknife.client.BeanManager; -import io.crysknife.client.Instance; -import io.crysknife.client.ManagedInstance; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 - */ -public class ManagedInstanceImpl implements ManagedInstance { - - private final BeanManager beanManager; - - private final Class type; - - private final Set> beans; - - ManagedInstanceImpl(Class type, BeanManager beanManager) { - this.type = type; - this.beanManager = beanManager; - this.beans = beanManager.lookupBeans(type); - } - - @Override - public ManagedInstance select(Annotation... qualifiers) { - return null; - } - - @Override - public boolean isUnsatisfied() { - return false; - } - - @Override - public boolean isAmbiguous() { - return false; - } - - @Override - public void destroy(Object instance) { - - } - - @Override - public void destroyAll() { - - } - - @Override - public Iterator iterator() { - return new ManagedInstanceImplIterator(beans); - } - - @Override - public T get() { - return beanManager.lookupBean(type).get(); - } - - private static class ManagedInstanceImplIterator implements Iterator { - - private final Iterator> delegate; - - public ManagedInstanceImplIterator(final Collection> beans) { - this.delegate = beans.iterator(); - } - - @Override - public boolean hasNext() { - return delegate.hasNext(); - } - - @Override - public T next() { - final Instance bean = delegate.next(); - final T instance = bean.get(); - return instance; - } - } -} diff --git a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentOne.java b/tests/jre-tests/src/main/java/org/treblereel/injection/managedinstance/SimpleBean.java similarity index 71% rename from tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentOne.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/managedinstance/SimpleBean.java index fb0a09ea..df90e3b0 100644 --- a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentOne.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/managedinstance/SimpleBean.java @@ -12,19 +12,17 @@ * the License. */ -package org.treblereel.managedinstance; +package org.treblereel.injection.managedinstance; import javax.enterprise.context.ApplicationScoped; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 + * @author Dmitrii Tikhomirov Created by treblereel 8/25/21 */ @ApplicationScoped -@ComponentQualifierOne -public class ComponentOne implements ComponentIface { +public class SimpleBean { - @Override - public String getComponentName() { - return getClass().getSimpleName(); + public String say() { + return this.getClass().getCanonicalName(); } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanDefault.java b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanDefault.java index 264c8b3a..ddffd9f8 100644 --- a/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanDefault.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanDefault.java @@ -22,7 +22,7 @@ */ @Default @Singleton -public class NamedBeanDefault implements NamedBean { +public class NamedBeanDefault extends SimpleBeanTwo implements NamedBean { @Override public String say() { diff --git a/tests/src/main/java/org/treblereel/injection/named/NamedBeanOne.java b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanFour.java similarity index 82% rename from tests/src/main/java/org/treblereel/injection/named/NamedBeanOne.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanFour.java index 403c4bd2..d837288f 100644 --- a/tests/src/main/java/org/treblereel/injection/named/NamedBeanOne.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanFour.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -18,11 +18,11 @@ import javax.inject.Singleton; /** - * @author Dmitrii Tikhomirov Created by treblereel 12/12/19 + * @author Dmitrii Tikhomirov Created by treblereel 8/20/21 */ -@Named("NamedBeanOne") +@Named @Singleton -public class NamedBeanOne implements NamedBean { +public class NamedBeanFour implements NamedBean { @Override public String say() { diff --git a/tests/src/main/java/org/treblereel/injection/named/NamedBeanDefault.java b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanSubOne.java similarity index 74% rename from tests/src/main/java/org/treblereel/injection/named/NamedBeanDefault.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanSubOne.java index 264c8b3a..14ec1bec 100644 --- a/tests/src/main/java/org/treblereel/injection/named/NamedBeanDefault.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanSubOne.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -14,15 +14,10 @@ package org.treblereel.injection.named; -import javax.enterprise.inject.Default; -import javax.inject.Singleton; - /** - * @author Dmitrii Tikhomirov Created by treblereel 12/12/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/5/21 */ -@Default -@Singleton -public class NamedBeanDefault implements NamedBean { +public class NamedBeanSubOne implements NamedBean { @Override public String say() { diff --git a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBeanDefault.java b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanSubThree.java similarity index 68% rename from tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBeanDefault.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanSubThree.java index 7ca2da0c..88d9777c 100644 --- a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBeanDefault.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanSubThree.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,17 +12,17 @@ * the License. */ -package org.treblereel.injection.qualifiers; +package org.treblereel.injection.named; -import javax.enterprise.inject.Default; -import javax.inject.Singleton; +import javax.enterprise.context.Dependent; +import javax.inject.Named; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/13/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/5/21 */ -@Default -@Singleton -public class QualifierBeanDefault implements QualifierBean { +@Dependent +@Named("NamedBeanSubThree") +public class NamedBeanSubThree extends NamedBeanSubTwo { @Override public String say() { diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanSubTwo.java b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanSubTwo.java new file mode 100644 index 00000000..53e2304e --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanSubTwo.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2021 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.injection.named; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/5/21 + */ +public abstract class NamedBeanSubTwo extends NamedBeanSubOne { +} diff --git a/tests/src/main/java/org/treblereel/injection/named/NamedBeanTwo.java b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanThree.java similarity index 77% rename from tests/src/main/java/org/treblereel/injection/named/NamedBeanTwo.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanThree.java index 794c4d02..503bec58 100644 --- a/tests/src/main/java/org/treblereel/injection/named/NamedBeanTwo.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/named/NamedBeanThree.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -14,15 +14,16 @@ package org.treblereel.injection.named; +import javax.enterprise.context.Dependent; import javax.inject.Named; -import javax.inject.Singleton; /** - * @author Dmitrii Tikhomirov Created by treblereel 12/12/19 + * @author Dmitrii Tikhomirov Created by treblereel 8/20/21 */ -@Named("NamedBeanTwo") -@Singleton -public class NamedBeanTwo implements NamedBean { + +@Named +@Dependent +public class NamedBeanThree implements NamedBean { @Override public String say() { diff --git a/tests/src/main/java/org/treblereel/injection/named/NamedBean.java b/tests/jre-tests/src/main/java/org/treblereel/injection/named/SimpleBean.java similarity index 81% rename from tests/src/main/java/org/treblereel/injection/named/NamedBean.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/named/SimpleBean.java index 8c31c8a4..cb1c2a2a 100644 --- a/tests/src/main/java/org/treblereel/injection/named/NamedBean.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/named/SimpleBean.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -15,9 +15,7 @@ package org.treblereel.injection.named; /** - * @author Dmitrii Tikhomirov Created by treblereel 12/12/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/27/21 */ -public interface NamedBean { - - String say(); +public class SimpleBean { } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/named/SimpleBeanTwo.java b/tests/jre-tests/src/main/java/org/treblereel/injection/named/SimpleBeanTwo.java new file mode 100644 index 00000000..f798c3bb --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/named/SimpleBeanTwo.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2021 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.injection.named; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/27/21 + */ +public class SimpleBeanTwo extends SimpleBean { +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/DefaultImpls.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/DefaultImpls.java new file mode 100644 index 00000000..ca446667 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/DefaultImpls.java @@ -0,0 +1,101 @@ +/* + * Copyright © 2021 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.injection.qualifiers; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.Dependent; +import javax.enterprise.inject.Default; +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/23/21 + */ +@Singleton +public class DefaultImpls { + + @Inject + public BeanOne beanOne; + + @Inject + public BeanTwo beanTwo; + + @Inject + public Inner inner; + + public interface BeanOne { + + String say(); + } + + @Singleton + @Default + public static class BeanOneImpl implements BeanOne { + + private String answer; + + @PostConstruct + public void init() { + this.answer = "PostConstruct_BeanOneImpl"; + } + + @Override + public String say() { + return answer; + } + } + + @Dependent + public static class Inner { + + @Inject + public BeanOne beanOne; + + @Inject + public BeanTwo beanTwo; + + } + + public interface BeanTwo { + + String say(); + } + + public static abstract class BeanTwoAbstract implements BeanTwo { + + } + + @Singleton + @Default + public static class BeanTwoImpl extends BeanTwoAbstract { + + @Inject + Resolver resolver; + + @Override + public String say() { + return resolver.resolve(); + } + } + + @Singleton + public static class Resolver { + + String resolve() { + return "Resolver_BeanTwoImpl"; + } + } + +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/QualifierConstructorInjection.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/QualifierConstructorInjection.java index 26d45ee7..97219a74 100644 --- a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/QualifierConstructorInjection.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/QualifierConstructorInjection.java @@ -34,8 +34,8 @@ public class QualifierConstructorInjection { public QualifierBean qualifier; @Inject - public QualifierConstructorInjection(@QualifierTwo @Lazy QualifierBean qualifierBeanTwo, - @QualifierOne QualifierBean qualifierBeanOne) { + public QualifierConstructorInjection(@QualifierTwo @Lazy final QualifierBean qualifierBeanTwo, + @QualifierOne final QualifierBean qualifierBeanOne) { this.qualifierBeanOne = qualifierBeanOne; this.qualifierBeanTwo = qualifierBeanTwo; } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/QualifierFieldInjection.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/QualifierFieldInjection.java index 31bacd7b..69db92bf 100644 --- a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/QualifierFieldInjection.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/QualifierFieldInjection.java @@ -14,8 +14,11 @@ package org.treblereel.injection.qualifiers; +import org.treblereel.injection.qualifiers.typed.MorphNodeToolboxAction; + import javax.enterprise.inject.Default; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; /** @@ -36,6 +39,12 @@ public class QualifierFieldInjection { @Default public QualifierBean qualifierBeanDefault; + @Inject + public DefaultImpls impls; + + @Inject + public MorphNodeToolboxAction morphNodeToolboxAction; + public QualifierBean getQualifierBeanOne() { return qualifierBeanOne; } diff --git a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBean.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/AbstractCanvasHandler.java similarity index 78% rename from tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBean.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/AbstractCanvasHandler.java index 1d84c9fd..6f718bc0 100644 --- a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBean.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/AbstractCanvasHandler.java @@ -12,12 +12,11 @@ * the License. */ -package org.treblereel.injection.qualifiers; +package org.treblereel.injection.qualifiers.controls; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/13/19 + * @author Dmitrii Tikhomirov Created by treblereel 8/18/21 */ -public interface QualifierBean { +public abstract class AbstractCanvasHandler { - String say(); } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/CanvasCommandFactory.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/CanvasCommandFactory.java new file mode 100644 index 00000000..9915c313 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/CanvasCommandFactory.java @@ -0,0 +1,24 @@ +/* + * 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 org.treblereel.injection.qualifiers.controls; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/18/21 + */ +public interface CanvasCommandFactory { + + public abstract String hey(); + +} diff --git a/tests/src/main/java/org/treblereel/injection/applicationscoped/ApplicationScopedBean.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/LienzoCanvasCommandFactory.java similarity index 67% rename from tests/src/main/java/org/treblereel/injection/applicationscoped/ApplicationScopedBean.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/LienzoCanvasCommandFactory.java index 9623bec9..03e67e73 100644 --- a/tests/src/main/java/org/treblereel/injection/applicationscoped/ApplicationScopedBean.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/LienzoCanvasCommandFactory.java @@ -12,25 +12,18 @@ * the License. */ -package org.treblereel.injection.applicationscoped; - -import java.util.Random; +package org.treblereel.injection.qualifiers.controls; import javax.enterprise.context.ApplicationScoped; /** - * @author Dmitrii Tikhomirov Created by treblereel 5/21/19 + * @author Dmitrii Tikhomirov Created by treblereel 8/18/21 */ @ApplicationScoped -public class ApplicationScopedBean { - - private int unique = 0; - - ApplicationScopedBean() { - this.unique = new Random().nextInt(); - } +public class LienzoCanvasCommandFactory implements CanvasCommandFactory { - public int say() { - return this.unique; + @Override + public String hey() { + return "LienzoCanvasCommandFactory"; } } diff --git a/core/src/main/java/io/crysknife/client/Instance.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/NodeBuilderControl.java similarity index 74% rename from core/src/main/java/io/crysknife/client/Instance.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/NodeBuilderControl.java index 706cd56c..02e93b56 100644 --- a/core/src/main/java/io/crysknife/client/Instance.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/NodeBuilderControl.java @@ -11,17 +11,13 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ -package io.crysknife.client; + +package org.treblereel.injection.qualifiers.controls; /** - * @author Dmitrii Tikhomirov Created by treblereel 3/29/19 + * @author Dmitrii Tikhomirov Created by treblereel 8/18/21 */ -public interface Instance { - - T get(); - - void destroy(T var1); - - void destroyAll(); +public interface NodeBuilderControl { + CanvasCommandFactory get(); } diff --git a/tests/src/main/java/org/treblereel/injection/dependent/SimpleBeanDependent.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/NodeBuilderControlImpl.java similarity index 53% rename from tests/src/main/java/org/treblereel/injection/dependent/SimpleBeanDependent.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/NodeBuilderControlImpl.java index 08935880..be503d11 100644 --- a/tests/src/main/java/org/treblereel/injection/dependent/SimpleBeanDependent.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/controls/NodeBuilderControlImpl.java @@ -12,38 +12,28 @@ * the License. */ -package org.treblereel.injection.dependent; +package org.treblereel.injection.qualifiers.controls; -import java.util.Random; - -import javax.annotation.PostConstruct; import javax.enterprise.context.Dependent; +import javax.enterprise.inject.Default; +import javax.inject.Inject; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 + * @author Dmitrii Tikhomirov Created by treblereel 8/18/21 */ @Dependent -public class SimpleBeanDependent { - - private String postConstruct; - - private int random; +// @Default +public class NodeBuilderControlImpl implements NodeBuilderControl { - public String getName() { - return this.getClass().getSimpleName(); - } - - @PostConstruct - public void init() { - postConstruct = "done"; - random = new Random().nextInt(); - } + public final CanvasCommandFactory commandFactory; - public String getPostConstruct() { - return postConstruct; + @Inject + public NodeBuilderControlImpl(final CanvasCommandFactory commandFactory) { + this.commandFactory = commandFactory; } - public int getRandom() { - return random; + @Override + public CanvasCommandFactory get() { + return commandFactory; } } diff --git a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentQualifierDefault.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/Bean.java similarity index 80% rename from tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentQualifierDefault.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/Bean.java index 8e03a255..129d1088 100644 --- a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentQualifierDefault.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/Bean.java @@ -12,11 +12,12 @@ * the License. */ -package org.treblereel.managedinstance; +package org.treblereel.injection.qualifiers.specializes; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 + * @author Dmitrii Tikhomirov Created by treblereel 8/26/21 */ -public class ComponentQualifierDefault { +public interface Bean { + } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/BeanImpl.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/BeanImpl.java new file mode 100644 index 00000000..c8bbb41f --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/BeanImpl.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2021 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.injection.qualifiers.specializes; + +import org.treblereel.injection.managedinstance.SimpleBean; + +import javax.enterprise.context.Dependent; +import javax.inject.Inject; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/26/21 + */ +@Dependent +public class BeanImpl implements Bean { + + @Inject + protected SimpleBean simpleBean; + + public SimpleBean getSimpleBean() { + return simpleBean; + } +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/SpecializesBeanHolder.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/SpecializesBeanHolder.java new file mode 100644 index 00000000..192d92a8 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/SpecializesBeanHolder.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2021 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.injection.qualifiers.specializes; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/26/21 + */ +@Singleton +public class SpecializesBeanHolder { + + @Inject + public Bean bean; +} diff --git a/tests/src/main/java/org/treblereel/injection/singleton/SimpleBeanSingleton.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/SpecializesBeanImpl.java similarity index 57% rename from tests/src/main/java/org/treblereel/injection/singleton/SimpleBeanSingleton.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/SpecializesBeanImpl.java index 808399d2..384fd4ff 100644 --- a/tests/src/main/java/org/treblereel/injection/singleton/SimpleBeanSingleton.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/specializes/SpecializesBeanImpl.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,29 +12,26 @@ * the License. */ -package org.treblereel.injection.singleton; +package org.treblereel.injection.qualifiers.specializes; -import javax.annotation.PostConstruct; +import org.treblereel.injection.managedinstance.SimpleBean; + +import javax.enterprise.inject.Specializes; +import javax.inject.Inject; import javax.inject.Singleton; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 + * @author Dmitrii Tikhomirov Created by treblereel 8/26/21 */ +@Specializes @Singleton -public class SimpleBeanSingleton { - - private String postConstruct; +public class SpecializesBeanImpl extends BeanImpl { - public String getName() { - return this.getClass().getSimpleName(); - } + @Inject + private SimpleBean localSimpleBean; - @PostConstruct - public void init() { - postConstruct = "done"; + public SimpleBean getLocalSimpleBean() { + return localSimpleBean; } - public String getPostConstruct() { - return postConstruct; - } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/AbstractCanvasHandler.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/AbstractCanvasHandler.java new file mode 100644 index 00000000..52fe93ee --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/AbstractCanvasHandler.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2021 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.injection.qualifiers.typed; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/25/21 + */ +public abstract class AbstractCanvasHandler extends CanvasHandler { +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/ApplicationCommandManager.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/ApplicationCommandManager.java new file mode 100644 index 00000000..6d3b1497 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/ApplicationCommandManager.java @@ -0,0 +1,41 @@ +/* + * Copyright © 2021 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.injection.qualifiers.typed; + +import io.crysknife.client.ManagedInstance; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Typed; +import javax.inject.Inject; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/25/21 + */ +@ApplicationScoped +@Typed(SessionCommandManager.class) +public class ApplicationCommandManager implements SessionCommandManager { + + public RegistryAwareCommandManager commandManagerInstances; + + public ApplicationCommandManager() { + + } + + @Inject + public ApplicationCommandManager(final RegistryAwareCommandManager commandManagerInstances) { + this.commandManagerInstances = commandManagerInstances; + } + +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/CanvasHandler.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/CanvasHandler.java new file mode 100644 index 00000000..158be619 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/CanvasHandler.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2021 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.injection.qualifiers.typed; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/25/21 + */ +public class CanvasHandler { +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/MorphNodeToolboxAction.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/MorphNodeToolboxAction.java new file mode 100644 index 00000000..68a8474b --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/MorphNodeToolboxAction.java @@ -0,0 +1,33 @@ +/* + * Copyright © 2021 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.injection.qualifiers.typed; + +import javax.enterprise.context.Dependent; +import javax.inject.Inject; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/25/21 + */ +@Dependent +public class MorphNodeToolboxAction { + + public final SessionCommandManager sessionCommandManager; + + @Inject + public MorphNodeToolboxAction( + final SessionCommandManager sessionCommandManager) { + this.sessionCommandManager = sessionCommandManager; + } +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/RegistryAwareCommandManager.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/RegistryAwareCommandManager.java new file mode 100644 index 00000000..52d88ed5 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/RegistryAwareCommandManager.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2021 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.injection.qualifiers.typed; + +import javax.enterprise.context.Dependent; +import javax.enterprise.inject.Typed; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/25/21 + */ +@Dependent +@Typed(RegistryAwareCommandManager.class) +public class RegistryAwareCommandManager implements SessionCommandManager { +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/SessionCommandManager.java b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/SessionCommandManager.java new file mode 100644 index 00000000..b81e6f7b --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/qualifiers/typed/SessionCommandManager.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2021 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.injection.qualifiers.typed; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/25/21 + */ +public interface SessionCommandManager { +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/injection/unscopedbean/MyBean.java b/tests/jre-tests/src/main/java/org/treblereel/injection/unscopedbean/MyBean.java new file mode 100644 index 00000000..36e7d2f1 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/unscopedbean/MyBean.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2021 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.injection.unscopedbean; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/9/21 + */ +public class MyBean { + + + private String id = "MyBean"; + + public String getId() { + return id; + } +} diff --git a/tests/src/main/java/org/treblereel/injection/named/NamedConstructorInjection.java b/tests/jre-tests/src/main/java/org/treblereel/injection/unscopedbean/UnscopedBeanHolder.java similarity index 56% rename from tests/src/main/java/org/treblereel/injection/named/NamedConstructorInjection.java rename to tests/jre-tests/src/main/java/org/treblereel/injection/unscopedbean/UnscopedBeanHolder.java index 301c2d31..9dd1a694 100644 --- a/tests/src/main/java/org/treblereel/injection/named/NamedConstructorInjection.java +++ b/tests/jre-tests/src/main/java/org/treblereel/injection/unscopedbean/UnscopedBeanHolder.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,29 +12,41 @@ * the License. */ -package org.treblereel.injection.named; +package org.treblereel.injection.unscopedbean; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; -import javax.inject.Named; /** - * @author Dmitrii Tikhomirov Created by treblereel 12/12/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/9/21 */ @ApplicationScoped -public class NamedConstructorInjection { +public class UnscopedBeanHolder { - public NamedBean one; + @Inject + private MyBean myBean; - public NamedBean two; + @Inject + private MyBean2 myBean2; - public NamedBean def; + public MyBean getMyBean() { + return myBean; + } - @Inject - public NamedConstructorInjection(@Named("NamedBeanOne") NamedBean one, - @Named("NamedBeanTwo") NamedBean two, NamedBean def) { - this.one = one; - this.two = two; - this.def = def; + public MyBean2 getMyBean2() { + return myBean2; + } + + public void setMyBean(MyBean myBean) { + this.myBean = myBean; + } + + public static class MyBean2 { + + private String id = "MyBean2"; + + public String getId() { + return id; + } } } diff --git a/tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerTest.java b/tests/jre-tests/src/main/java/org/treblereel/observes/ObservesBean.java similarity index 62% rename from tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerTest.java rename to tests/jre-tests/src/main/java/org/treblereel/observes/ObservesBean.java index b2147533..78faae8c 100644 --- a/tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerTest.java +++ b/tests/jre-tests/src/main/java/org/treblereel/observes/ObservesBean.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,25 +12,23 @@ * the License. */ -package org.treblereel.produces.qualifier; +package org.treblereel.observes; +import javax.enterprise.event.Event; +import javax.enterprise.event.Observes; import javax.inject.Inject; import javax.inject.Singleton; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 + * @author Dmitrii Tikhomirov Created by treblereel 9/6/21 */ @Singleton -public class QualifierBeanProducerTest { +public class ObservesBean { @Inject - private QualifierBean qualifierBean; + protected Event eventUser; - public QualifierBean getQualifierBean() { - return qualifierBean; - } - - public void setQualifierBean(QualifierBean qualifierBean) { - this.qualifierBean = qualifierBean; + public void onUserEvent(@Observes User user) { + // setText(user.toString()); } } diff --git a/processor/src/main/java/io/crysknife/generator/point/Point.java b/tests/jre-tests/src/main/java/org/treblereel/observes/User.java similarity index 59% rename from processor/src/main/java/io/crysknife/generator/point/Point.java rename to tests/jre-tests/src/main/java/org/treblereel/observes/User.java index efb7f291..95f76291 100644 --- a/processor/src/main/java/io/crysknife/generator/point/Point.java +++ b/tests/jre-tests/src/main/java/org/treblereel/observes/User.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,33 +12,35 @@ * the License. */ -package io.crysknife.generator.point; - -import javax.lang.model.element.TypeElement; +package org.treblereel.observes; /** - * @author Dmitrii Tikhomirov Created by treblereel 3/2/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/6/21 */ -public abstract class Point { +public class User { - protected final String name; + private int id; - protected TypeElement type; + private String name; - public Point(TypeElement type, String name) { - this.type = type; - this.name = name; + @Override + public String toString() { + return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } - public TypeElement getType() { - return type; + public int getId() { + return id; } - public void setType(TypeElement type) { - this.type = type; + public void setId(int id) { + this.id = id; } public String getName() { return name; } + + public void setName(String name) { + this.name = name; + } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/postconstruct/Child.java b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/Child.java new file mode 100644 index 00000000..70e07d15 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/Child.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2021 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.postconstruct; + +import javax.inject.Singleton; + + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/17/21 + */ +@Singleton +public class Child extends Parent { + +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/postconstruct/ChildFour.java b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/ChildFour.java new file mode 100644 index 00000000..e442d5cc --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/ChildFour.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2021 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.postconstruct; + +import javax.annotation.PostConstruct; +import javax.inject.Singleton; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/17/21 + */ +@Singleton +public class ChildFour extends ChildThree { + + @PostConstruct + protected void init1() { + calls.add("ChildFour"); + } +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/postconstruct/ChildThree.java b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/ChildThree.java new file mode 100644 index 00000000..2624ecf2 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/ChildThree.java @@ -0,0 +1,25 @@ +/* + * Copyright © 2021 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.postconstruct; + +import javax.inject.Singleton; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/17/21 + */ +@Singleton +public class ChildThree extends ChildTwo { + +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/postconstruct/ChildTwo.java b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/ChildTwo.java new file mode 100644 index 00000000..9aaa8629 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/ChildTwo.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2021 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.postconstruct; + +import javax.annotation.PostConstruct; +import javax.inject.Singleton; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/17/21 + */ +@Singleton +public class ChildTwo extends Parent { + + @PostConstruct + protected void init11() { + calls.add("ChildTwo"); + } +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/postconstruct/Parent.java b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/Parent.java new file mode 100644 index 00000000..552e40cf --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/Parent.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2021 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.postconstruct; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.Dependent; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/17/21 + */ +public abstract class Parent { + + public List calls = new LinkedList<>(); + + @PostConstruct + protected void init2() { + calls.add("Parent"); + } + +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/postconstruct/PostConstructs.java b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/PostConstructs.java new file mode 100644 index 00000000..0916aff3 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/postconstruct/PostConstructs.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2021 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.postconstruct; + +import io.crysknife.client.BeanManager; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/17/21 + */ +@Singleton +public class PostConstructs { + + @Inject + public BeanManager beanManager; + + @Inject + public Child child; + + @Inject + public ChildTwo childTwo; + + @Inject + public ChildThree childThree; + + @Inject + public ChildFour childFour; + +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/produces/SimpleBeanProducerTest.java b/tests/jre-tests/src/main/java/org/treblereel/produces/SimpleBeanProducerTest.java index 6578ce22..5618a0ab 100644 --- a/tests/jre-tests/src/main/java/org/treblereel/produces/SimpleBeanProducerTest.java +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/SimpleBeanProducerTest.java @@ -14,6 +14,8 @@ package org.treblereel.produces; +import org.treblereel.produces.staticproduces.MyStaticBean; + import javax.inject.Inject; import javax.inject.Singleton; @@ -32,6 +34,9 @@ public class SimpleBeanProducerTest { @Inject private SimpleBeanDependent simpleBeanDependentTwo; + @Inject + private MyStaticBean myStaticBean; + public SimpleBeanSingleton getSimpleBeanSingletonOne() { return simpleBeanSingletonOne; } @@ -47,4 +52,8 @@ public SimpleBeanDependent getSimpleBeanDependentOne() { public SimpleBeanDependent getSimpleBeanDependentTwo() { return simpleBeanDependentTwo; } + + public MyStaticBean getMyStaticBean() { + return myStaticBean; + } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java b/tests/jre-tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java index 9c6c1297..0baa06c8 100644 --- a/tests/jre-tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java @@ -28,7 +28,7 @@ public QualifierBean getSimpleQualifierBean() { return new QualifierBean() { @Override public String say() { - return this.getClass().getSimpleName(); + return "REDHAT"; } }; } diff --git a/tests/jre-tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerTest.java b/tests/jre-tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerTest.java index b2147533..269b2499 100644 --- a/tests/jre-tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerTest.java +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducerTest.java @@ -30,7 +30,4 @@ public QualifierBean getQualifierBean() { return qualifierBean; } - public void setQualifierBean(QualifierBean qualifierBean) { - this.qualifierBean = qualifierBean; - } } diff --git a/tests/src/main/java/org/treblereel/injection/applicationscoped/ApplicationScopedConstructorInjection.java b/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/HistoryTokenFactory.java similarity index 59% rename from tests/src/main/java/org/treblereel/injection/applicationscoped/ApplicationScopedConstructorInjection.java rename to tests/jre-tests/src/main/java/org/treblereel/produces/scoped/HistoryTokenFactory.java index f7bbd734..28eb2b83 100644 --- a/tests/src/main/java/org/treblereel/injection/applicationscoped/ApplicationScopedConstructorInjection.java +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/HistoryTokenFactory.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,25 +12,30 @@ * the License. */ -package org.treblereel.injection.applicationscoped; +package org.treblereel.produces.scoped; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; /** - * @author Dmitrii Tikhomirov Created by treblereel 5/21/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/10/21 */ @ApplicationScoped -public class ApplicationScopedConstructorInjection { +public class HistoryTokenFactory { - public ApplicationScopedBean bean; + private final URLPatternMatcher patternMatcher; - // @Inject - public ApplicationScopedBean bean2; + // For proxying + public HistoryTokenFactory() { + patternMatcher = null; + } @Inject - public ApplicationScopedConstructorInjection(ApplicationScopedBean bean) { - this.bean = bean; + public HistoryTokenFactory(URLPatternMatcher upm) { + this.patternMatcher = upm; } + public URLPatternMatcher getPatternMatcher() { + return patternMatcher; + } } diff --git a/tests/src/main/java/org/treblereel/injection/named/NamedFieldInjection.java b/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/Navigation.java similarity index 65% rename from tests/src/main/java/org/treblereel/injection/named/NamedFieldInjection.java rename to tests/jre-tests/src/main/java/org/treblereel/produces/scoped/Navigation.java index 452f0660..a2057314 100644 --- a/tests/src/main/java/org/treblereel/injection/named/NamedFieldInjection.java +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/Navigation.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,26 +12,22 @@ * the License. */ -package org.treblereel.injection.named; +package org.treblereel.produces.scoped; import javax.inject.Inject; -import javax.inject.Named; import javax.inject.Singleton; /** - * @author Dmitrii Tikhomirov Created by treblereel 12/12/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/10/21 */ @Singleton -public class NamedFieldInjection { +public class Navigation { @Inject - @Named("NamedBeanOne") - public NamedBean one; + private HistoryTokenFactory historyTokenFactory; - @Inject - @Named("NamedBeanTwo") - public NamedBean two; - @Inject - public NamedBean def; + public String test() { + return historyTokenFactory.getPatternMatcher().getStatus(); + } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/URLPatternMatcher.java b/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/URLPatternMatcher.java new file mode 100644 index 00000000..56552bac --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/URLPatternMatcher.java @@ -0,0 +1,31 @@ +/* + * Copyright © 2021 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.scoped; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/10/21 + */ +public class URLPatternMatcher { + + private String status; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/URLPatternMatcherHolder.java b/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/URLPatternMatcherHolder.java new file mode 100644 index 00000000..23aa9d1e --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/URLPatternMatcherHolder.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2021 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.scoped; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/10/21 + */ +@Singleton +public class URLPatternMatcherHolder { + + @Inject + public Navigation matcher; +} diff --git a/tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java b/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/URLPatternMatcherProvider.java similarity index 55% rename from tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java rename to tests/jre-tests/src/main/java/org/treblereel/produces/scoped/URLPatternMatcherProvider.java index 9c6c1297..7fa7574f 100644 --- a/tests/src/main/java/org/treblereel/produces/qualifier/QualifierBeanProducer.java +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/scoped/URLPatternMatcherProvider.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,24 +12,23 @@ * the License. */ -package org.treblereel.produces.qualifier; +package org.treblereel.produces.scoped; -import javax.enterprise.context.Dependent; +import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; +import javax.inject.Singleton; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 + * @author Dmitrii Tikhomirov Created by treblereel 9/10/21 */ -public class QualifierBeanProducer { +@Singleton +public class URLPatternMatcherProvider { @Produces - @Dependent - public QualifierBean getSimpleQualifierBean() { - return new QualifierBean() { - @Override - public String say() { - return this.getClass().getSimpleName(); - } - }; + @ApplicationScoped + public URLPatternMatcher createURLPatternMatcher() { + URLPatternMatcher patternMatcher = new URLPatternMatcher(); + patternMatcher.setStatus("URLPatternMatcherProvider"); + return patternMatcher; } } diff --git a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBeanTwo.java b/tests/jre-tests/src/main/java/org/treblereel/produces/staticproduces/MyStaticBean.java similarity index 71% rename from tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBeanTwo.java rename to tests/jre-tests/src/main/java/org/treblereel/produces/staticproduces/MyStaticBean.java index 2deaf45e..b40e6d6e 100644 --- a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierBeanTwo.java +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/staticproduces/MyStaticBean.java @@ -12,20 +12,16 @@ * the License. */ -package org.treblereel.injection.qualifiers; - -import javax.inject.Singleton; +package org.treblereel.produces.staticproduces; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/13/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/12/21 */ -@QualifierTwo -@Singleton -public class QualifierBeanTwo implements QualifierBean { +public class MyStaticBean { + + public boolean ready = false; - @Override - public String say() { + public String whoami() { return this.getClass().getCanonicalName(); } - } diff --git a/tests/src/main/java/org/treblereel/produces/RandomGenerator.java b/tests/jre-tests/src/main/java/org/treblereel/produces/staticproduces/MyStaticBeanProducer.java similarity index 65% rename from tests/src/main/java/org/treblereel/produces/RandomGenerator.java rename to tests/jre-tests/src/main/java/org/treblereel/produces/staticproduces/MyStaticBeanProducer.java index b41349b3..19972db5 100644 --- a/tests/src/main/java/org/treblereel/produces/RandomGenerator.java +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/staticproduces/MyStaticBeanProducer.java @@ -12,25 +12,20 @@ * the License. */ -package org.treblereel.produces; +package org.treblereel.produces.staticproduces; -import java.util.Random; - -import javax.inject.Singleton; +import javax.enterprise.inject.Produces; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 + * @author Dmitrii Tikhomirov Created by treblereel 9/12/21 */ -@Singleton -public class RandomGenerator { - - private int random; +public class MyStaticBeanProducer { - public void init() { - random = new Random().nextInt(); - } - public int getRandom() { - return random; + @Produces + public static MyStaticBean get() { + MyStaticBean result = new MyStaticBean(); + result.ready = true; + return result; } } diff --git a/tests/jre-tests/src/main/java/org/treblereel/produces/typed/HTMLElement.java b/tests/jre-tests/src/main/java/org/treblereel/produces/typed/HTMLElement.java new file mode 100644 index 00000000..57c23817 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/typed/HTMLElement.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2021 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.typed; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 10/4/21 + */ +public class HTMLElement { +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/produces/typed/JQueryProducer.java b/tests/jre-tests/src/main/java/org/treblereel/produces/typed/JQueryProducer.java new file mode 100644 index 00000000..f6d2b458 --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/typed/JQueryProducer.java @@ -0,0 +1,45 @@ +/* + * Copyright © 2021 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.typed; + +import elemental2.dom.Element; +import elemental2.dom.HTMLElement; + +import javax.enterprise.inject.Produces; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 10/4/21 + */ +public class JQueryProducer { + + @Produces + public static JQuery get() { + return new JQuery() { + + @Override + public JQueryElement wrap(Element element) { + return null; + } + }; + } + + public interface JQuery { + + T wrap(Element element); + } + + public static abstract class JQueryElement extends HTMLElement { + } +} diff --git a/tests/jre-tests/src/main/java/org/treblereel/produces/typed/Popover.java b/tests/jre-tests/src/main/java/org/treblereel/produces/typed/Popover.java new file mode 100644 index 00000000..490138ee --- /dev/null +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/typed/Popover.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2021 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.typed; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 10/4/21 + */ +public class Popover extends JQueryProducer.JQueryElement { +} diff --git a/tests/src/main/java/org/treblereel/injection/named/NamedTestBean.java b/tests/jre-tests/src/main/java/org/treblereel/produces/typed/TypedProducesTestHolder.java similarity index 70% rename from tests/src/main/java/org/treblereel/injection/named/NamedTestBean.java rename to tests/jre-tests/src/main/java/org/treblereel/produces/typed/TypedProducesTestHolder.java index 6789e5ac..86ddd217 100644 --- a/tests/src/main/java/org/treblereel/injection/named/NamedTestBean.java +++ b/tests/jre-tests/src/main/java/org/treblereel/produces/typed/TypedProducesTestHolder.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -12,21 +12,18 @@ * the License. */ -package org.treblereel.injection.named; +package org.treblereel.produces.typed; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; /** - * @author Dmitrii Tikhomirov Created by treblereel 3/14/20 + * @author Dmitrii Tikhomirov Created by treblereel 10/4/21 */ @ApplicationScoped -public class NamedTestBean { +public class TypedProducesTestHolder { @Inject - public NamedConstructorInjection namedConstructorInjection; - - @Inject - public NamedFieldInjection namedFieldInjection; + public JQueryProducer.JQuery jQueryPopover; } diff --git a/tests/jre-tests/src/test/java/org/treblereel/BeanManagerTest.java b/tests/jre-tests/src/test/java/org/treblereel/BeanManagerTest.java index a1b9ad00..bfa1f0f8 100644 --- a/tests/jre-tests/src/test/java/org/treblereel/BeanManagerTest.java +++ b/tests/jre-tests/src/test/java/org/treblereel/BeanManagerTest.java @@ -68,38 +68,54 @@ public Class annotationType() { } }; - ComponentIface componentDefault = - super.app.beanManager.lookupBean(ComponentIface.class, _default).get(); - ComponentIface componentOne = - super.app.beanManager.lookupBean(ComponentIface.class, componentQualifierOne).get(); - ComponentIface componentTwo = - super.app.beanManager.lookupBean(ComponentIface.class, componentQualifierTwo).get(); + ComponentIface componentDefault = super.app.beanManager + .lookupBean(ComponentIface.class, _default).getInstance(); + ComponentIface componentOne = super.app.beanManager + .lookupBean(ComponentIface.class, componentQualifierOne).getInstance(); + ComponentIface componentTwo = super.app.beanManager + .lookupBean(ComponentIface.class, componentQualifierTwo).getInstance(); assertEquals("ComponentDefault", componentDefault.getComponentName()); assertEquals("ComponentOne", componentOne.getComponentName()); assertEquals("ComponentTwo", componentTwo.getComponentName()); - assertEquals(3, super.app.beanManager.lookupBeans(ComponentIface.class).size()); + assertEquals(3, + StreamSupport + .stream(super.app.beanManager.lookupBeans(ComponentIface.class).spliterator(), false) + .count()); - assertEquals(1, super.app.beanManager.lookupBeans(ComponentIface.class, _default).size()); + assertEquals(1, + StreamSupport + .stream(super.app.beanManager.lookupBeans(ComponentIface.class, _default).spliterator(), + false) + .count()); ComponentIface _defInstance = - super.app.beanManager.lookupBeans(ComponentIface.class, _default).iterator().next().get(); + super.app.beanManager.lookupBeans(ComponentIface.class, _default).iterator() + .next().getInstance(); assertEquals("ComponentDefault", _defInstance.getComponentName()); assertEquals(1, - super.app.beanManager.lookupBeans(ComponentIface.class, componentQualifierOne).size()); + StreamSupport.stream(super.app.beanManager + .lookupBeans(ComponentIface.class, componentQualifierOne).spliterator(), false) + .count()); ComponentIface _componentQualifierOne = super.app.beanManager - .lookupBeans(ComponentIface.class, componentQualifierOne).iterator().next().get(); + .lookupBeans(ComponentIface.class, componentQualifierOne).iterator().next() + .getInstance(); assertEquals("ComponentOne", _componentQualifierOne.getComponentName()); assertEquals(1, - super.app.beanManager.lookupBeans(ComponentIface.class, componentQualifierTwo).size()); + StreamSupport.stream(super.app.beanManager + .lookupBeans(ComponentIface.class, componentQualifierTwo).spliterator(), false) + .count()); ComponentIface _componentQualifierTwo = super.app.beanManager - .lookupBeans(ComponentIface.class, componentQualifierTwo).iterator().next().get(); + .lookupBeans(ComponentIface.class, componentQualifierTwo).iterator().next() + .getInstance(); assertEquals("ComponentTwo", _componentQualifierTwo.getComponentName()); - assertEquals(0, super.app.beanManager - .lookupBeans(ComponentIface.class, componentQualifierOne, componentQualifierTwo).size()); + assertEquals(0, + StreamSupport.stream(super.app.beanManager + .lookupBeans(ComponentIface.class, componentQualifierOne, componentQualifierTwo) + .spliterator(), false).count()); } @@ -142,37 +158,47 @@ public String value() { } }; - NamedBean componentDefault = super.app.beanManager.lookupBean(NamedBean.class, _default).get(); - NamedBean componentOne = super.app.beanManager.lookupBean(NamedBean.class, named1).get(); - NamedBean componentTwo = super.app.beanManager.lookupBean(NamedBean.class, named2).get(); + NamedBean componentDefault = + super.app.beanManager.lookupBean(NamedBean.class, _default).getInstance(); + NamedBean componentOne = + super.app.beanManager.lookupBean(NamedBean.class, named1).getInstance(); + NamedBean componentTwo = + super.app.beanManager.lookupBean(NamedBean.class, named2).getInstance(); assertEquals("org.treblereel.injection.named.NamedBeanDefault", componentDefault.say()); assertEquals("org.treblereel.injection.named.NamedBeanOne", componentOne.say()); assertEquals("org.treblereel.injection.named.NamedBeanTwo", componentTwo.say()); - assertEquals(3, super.app.beanManager.lookupBeans(NamedBean.class).size()); - - - assertEquals(3, super.app.beanManager.lookupBeans(NamedBean.class).size()); - - assertEquals(1, super.app.beanManager.lookupBeans(NamedBean.class, _default).size()); - NamedBean _defInstance = - super.app.beanManager.lookupBeans(NamedBean.class, _default).iterator().next().get(); + assertEquals(6, StreamSupport + .stream(super.app.beanManager.lookupBeans(NamedBean.class).spliterator(), false).count()); + + assertEquals(1, StreamSupport + .stream(super.app.beanManager.lookupBeans(NamedBean.class, _default).spliterator(), false) + .count()); + NamedBean _defInstance = super.app.beanManager.lookupBeans(NamedBean.class, _default) + .iterator().next().getInstance(); assertEquals("org.treblereel.injection.named.NamedBeanDefault", _defInstance.say()); - assertEquals(1, super.app.beanManager.lookupBeans(NamedBean.class, named1).size()); - NamedBean _componentQualifierOne = - super.app.beanManager.lookupBeans(NamedBean.class, named1).iterator().next().get(); + assertEquals(1, + StreamSupport.stream( + super.app.beanManager.lookupBeans(NamedBean.class, named1).spliterator(), + false).count()); + NamedBean _componentQualifierOne = super.app.beanManager + .lookupBeans(NamedBean.class, named1).iterator().next().getInstance(); assertEquals("org.treblereel.injection.named.NamedBeanOne", _componentQualifierOne.say()); - assertEquals(1, super.app.beanManager.lookupBeans(NamedBean.class, named2).size()); + assertEquals(1, + StreamSupport + .stream(super.app.beanManager.lookupBeans(NamedBean.class, named2).spliterator(), false) + .count()); NamedBean _componentQualifierTwo = - super.app.beanManager.lookupBeans(NamedBean.class, named2).iterator().next().get(); + super.app.beanManager.lookupBeans(NamedBean.class, named2).iterator().next().getInstance(); assertEquals("org.treblereel.injection.named.NamedBeanTwo", _componentQualifierTwo.say()); - assertEquals(0, super.app.beanManager.lookupBeans(NamedBean.class, named1, named2).size()); - - + assertEquals(0, + StreamSupport.stream( + super.app.beanManager.lookupBeans(NamedBean.class, named1, named2).spliterator(), false) + .count()); } } diff --git a/tests/jre-tests/src/test/java/org/treblereel/InheritanceTest.java b/tests/jre-tests/src/test/java/org/treblereel/InheritanceTest.java new file mode 100644 index 00000000..6b1f5555 --- /dev/null +++ b/tests/jre-tests/src/test/java/org/treblereel/InheritanceTest.java @@ -0,0 +1,81 @@ +/* + * 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 org.treblereel; + +import org.junit.Test; +import org.treblereel.injection.inheritance.BeanChild; +import org.treblereel.injection.inheritance.Target; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 + */ +public class InheritanceTest extends AbstractTest { + + @Test + public void testPostConstructAppBootstrap() { + assertEquals("PostConstruct", app.testPostConstruct); + } + + @Test + public void testSimpleBeanSingleton() { + assertEquals("done", app.getSimpleBeanSingleton().getPostConstruct()); + } + + @Test + public void testSimpleBeanApplicationScoped() { + assertEquals("done", app.getSimpleBeanApplicationScoped().getPostConstruct()); + } + + @Test + public void testSimpleDependent() { + assertEquals("done", app.getSimpleBeanDependent().getPostConstruct()); + } + + @Test + public void testChildPostConstructCalled() { + assertEquals(1, app.postConstructs.child.calls.size()); + assertEquals("Parent", app.postConstructs.child.calls.get(0)); + assertEquals(2, app.postConstructs.childTwo.calls.size()); + assertEquals("Parent", app.postConstructs.childTwo.calls.get(0)); + assertEquals("ChildTwo", app.postConstructs.childTwo.calls.get(1)); + assertEquals(2, app.postConstructs.childThree.calls.size()); + assertEquals(3, app.postConstructs.childFour.calls.size()); + assertEquals("Parent", app.postConstructs.childTwo.calls.get(0)); + assertEquals("ChildTwo", app.postConstructs.childTwo.calls.get(1)); + assertEquals("ChildFour", app.postConstructs.childFour.calls.get(2)); + } + + @Test + public void testParentFieldInjected() { + + assertNotNull(app.inheritanceBean); + assertNotNull(app.inheritanceBean.getBean()); + assertNotNull(app.inheritanceBean.getBean().getTarget()); + assertNotNull(app.inheritanceBean.getBean().getParentTarget()); + assertNotNull(app.inheritanceBean.getBean().getParentTarget()); + assertNotNull(app.inheritanceBean.getBean().getParentTarget().hello()); + + assertEquals(Target.class, app.inheritanceBean.getBean().getTarget().getClass()); + assertEquals(Target.class, app.inheritanceBean.getBean().getParentTarget().getClass()); + assertEquals(Target.class.getCanonicalName(), + app.inheritanceBean.getBean().getTarget().hello()); + assertEquals(Target.class.getCanonicalName(), + app.inheritanceBean.getBean().getParentTarget().hello()); + } + +} diff --git a/tests/jre-tests/src/test/java/org/treblereel/PostConstructTest.java b/tests/jre-tests/src/test/java/org/treblereel/InnerBeansTest.java similarity index 51% rename from tests/jre-tests/src/test/java/org/treblereel/PostConstructTest.java rename to tests/jre-tests/src/test/java/org/treblereel/InnerBeansTest.java index 1c23f022..969f19de 100644 --- a/tests/jre-tests/src/test/java/org/treblereel/PostConstructTest.java +++ b/tests/jre-tests/src/test/java/org/treblereel/InnerBeansTest.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020 Treblereel + * Copyright © 2021 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 @@ -19,28 +19,21 @@ import static org.junit.Assert.assertEquals; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 + * @author Dmitrii Tikhomirov Created by treblereel 8/23/21 */ -public class PostConstructTest extends AbstractTest { +public class InnerBeansTest extends AbstractTest { - @Test - public void testPostConstructAppBootstrap() { - assertEquals("PostConstruct", app.testPostConstruct); - } - - @Test - public void testSimpleBeanSingleton() { - assertEquals("done", app.getSimpleBeanSingleton().getPostConstruct()); - } @Test - public void testSimpleBeanApplicationScoped() { - assertEquals("done", app.getSimpleBeanApplicationScoped().getPostConstruct()); + public void testBeanOneImpl() { + assertEquals("PostConstruct_BeanOneImpl", app.qualifierFieldInjection.impls.beanOne.say()); + assertEquals("PostConstruct_BeanOneImpl", + app.qualifierFieldInjection.impls.inner.beanOne.say()); } @Test - public void testSimpleDependent() { - assertEquals("done", app.getSimpleBeanDependent().getPostConstruct()); + public void testBeanTwoImpl() { + assertEquals("Resolver_BeanTwoImpl", app.qualifierFieldInjection.impls.beanTwo.say()); + assertEquals("Resolver_BeanTwoImpl", app.qualifierFieldInjection.impls.inner.beanTwo.say()); } - } diff --git a/tests/jre-tests/src/test/java/org/treblereel/ManagedInstanceBeanTest.java b/tests/jre-tests/src/test/java/org/treblereel/ManagedInstanceBeanTest.java index fb804bf2..69b8b267 100644 --- a/tests/jre-tests/src/test/java/org/treblereel/ManagedInstanceBeanTest.java +++ b/tests/jre-tests/src/test/java/org/treblereel/ManagedInstanceBeanTest.java @@ -19,14 +19,17 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import javax.enterprise.inject.Instance; import javax.inject.Named; import io.crysknife.client.ManagedInstance; -import org.junit.Assert; import org.junit.Test; +import org.treblereel.injection.dependent.SimpleBeanDependent; import org.treblereel.injection.managedinstance.ComponentIface; import org.treblereel.injection.managedinstance.ComponentQualifierOne; import org.treblereel.injection.managedinstance.ComponentQualifierTwo; +import org.treblereel.injection.managedinstance.SimpleBean; +import org.treblereel.produces.qualifier.QualifierBean; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -102,9 +105,110 @@ public String value() { } }; - ComponentIface componentTwo = - super.app.beanManager.lookupBean(ComponentIface.class, componentQualifierTwo).get(); + ComponentIface componentTwo = super.app.beanManager + .lookupBean(ComponentIface.class, componentQualifierTwo).getInstance(); assertEquals("ComponentTwo", componentTwo.getComponentName()); } + + @Test + public void testInstance() { + ManagedInstance managedInstanceBean = + app.getManagedInstanceBean().getInstanceBean(); + + assertNotNull(managedInstanceBean); + + List actualList = + StreamSupport.stream(managedInstanceBean.spliterator(), false).collect(Collectors.toList()); + assertEquals(3, actualList.size()); + + ComponentQualifierOne componentQualifierOne = new ComponentQualifierOne() { + + @Override + public Class annotationType() { + return ComponentQualifierOne.class; + } + }; + + ComponentQualifierTwo componentQualifierTwo = new ComponentQualifierTwo() { + + @Override + public Class annotationType() { + return ComponentQualifierTwo.class; + } + }; + + Named named1 = new Named() { + + @Override + public Class annotationType() { + return Named.class; + } + + @Override + public String value() { + return "one"; + } + }; + + Named named11 = new Named() { + + @Override + public Class annotationType() { + return Named.class; + } + + @Override + public String value() { + return "one"; + } + }; + + Named named2 = new Named() { + + @Override + public Class annotationType() { + return Named.class; + } + + @Override + public String value() { + return "two"; + } + }; + + ComponentIface componentTwo = super.app.beanManager + .lookupBean(ComponentIface.class, componentQualifierTwo).getInstance(); + assertEquals("ComponentTwo", componentTwo.getComponentName()); + } + + @Test + public void testInstance2() { + Instance managedInstanceBean = app.getManagedInstanceBean().getBean(); + assertEquals(SimpleBeanDependent.class.getSimpleName(), managedInstanceBean.get().getName()); + } + + @Test + public void testInstanceProducerBean() { + Instance managedInstanceBean = app.getManagedInstanceBean().getBean2(); + assertEquals("REDHAT", managedInstanceBean.get().say()); + } + + @Test + public void testSimpleBean1() { + assertEquals(SimpleBean.class.getCanonicalName(), + app.getManagedInstanceBean().simpleBean1.get().say()); + + assertEquals(SimpleBean.class.getCanonicalName(), + app.getManagedInstanceBean().constructor_simpleBean1.get().say()); + } + + @Test + public void testSimpleBean2() { + assertEquals(SimpleBean.class.getCanonicalName(), + app.getManagedInstanceBean().simpleBean2.get().say()); + + assertEquals(SimpleBean.class.getCanonicalName(), + app.getManagedInstanceBean().constructor_simpleBean2.get().say()); + } } diff --git a/tests/jre-tests/src/test/java/org/treblereel/NamedTest.java b/tests/jre-tests/src/test/java/org/treblereel/NamedTest.java index adc182f6..197c467b 100644 --- a/tests/jre-tests/src/test/java/org/treblereel/NamedTest.java +++ b/tests/jre-tests/src/test/java/org/treblereel/NamedTest.java @@ -14,12 +14,24 @@ package org.treblereel; +import io.crysknife.client.SyncBeanDef; import org.junit.Test; +import org.treblereel.injection.named.NamedBean; import org.treblereel.injection.named.NamedBeanDefault; import org.treblereel.injection.named.NamedBeanOne; import org.treblereel.injection.named.NamedBeanTwo; +import org.treblereel.injection.qualifiers.QualifierBean; + +import javax.enterprise.inject.Instance; +import javax.inject.Named; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 @@ -45,4 +57,53 @@ public void testNamedFieldInjection() { assertEquals(NamedBeanTwo.class.getSimpleName(), app.getNamedTestBean().namedFieldInjection.two.getClass().getSimpleName()); } + + @Test + public void testBeanManager() { + Set beans = new HashSet<>(); + for (SyncBeanDef lookupBean : app.beanManager + .lookupBeans(NamedBean.class)) { + beans.add(lookupBean.getInstance()); + } + + + assertEquals(6, beans.size()); + List result = new ArrayList<>(); + for (SyncBeanDef lookupBean : app.beanManager.lookupBeans(NamedBean.class)) { + result.add(((NamedBean) lookupBean.getInstance()).say()); + } + assertTrue(result.contains(NamedBeanDefault.class.getCanonicalName())); + assertTrue(result.contains(NamedBeanOne.class.getCanonicalName())); + assertTrue(result.contains(NamedBeanTwo.class.getCanonicalName())); + + Named namedBeanOne = new Named() { + + public Class annotationType() { + return javax.inject.Named.class; + } + + public String value() { + return "NamedBeanOne"; + } + }; + + Named namedBeanTwo = new Named() { + + public Class annotationType() { + return javax.inject.Named.class; + } + + public String value() { + return "NamedBeanTwo"; + } + }; + + assertEquals(NamedBeanDefault.class, + app.beanManager.lookupBean(NamedBean.class).getInstance().getClass()); + assertEquals(NamedBeanOne.class, + app.beanManager.lookupBean(NamedBean.class, namedBeanOne).getInstance().getClass()); + assertEquals(NamedBeanTwo.class, + app.beanManager.lookupBean(NamedBean.class, namedBeanTwo).getInstance().getClass()); + + } } diff --git a/tests/jre-tests/src/test/java/org/treblereel/QualifierTest.java b/tests/jre-tests/src/test/java/org/treblereel/QualifierTest.java index c3d0b290..de8e86d0 100644 --- a/tests/jre-tests/src/test/java/org/treblereel/QualifierTest.java +++ b/tests/jre-tests/src/test/java/org/treblereel/QualifierTest.java @@ -14,14 +14,29 @@ package org.treblereel; +import io.crysknife.client.SyncBeanDef; import org.junit.Test; +import org.treblereel.injection.qualifiers.QualifierBean; import org.treblereel.injection.qualifiers.QualifierBeanDefault; import org.treblereel.injection.qualifiers.QualifierBeanOne; import org.treblereel.injection.qualifiers.QualifierBeanTwo; import org.treblereel.injection.qualifiers.QualifierConstructorInjection; +import org.treblereel.injection.qualifiers.QualifierOne; +import org.treblereel.injection.qualifiers.QualifierTwo; + +import javax.enterprise.inject.Instance; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import java.util.ArrayList; +import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 @@ -32,8 +47,10 @@ public class QualifierTest extends AbstractTest { public void testQualifierFieldInjectionBean() { assertEquals(QualifierBeanDefault.class.getSimpleName(), app.getQualifierFieldInjection().getQualifierBeanDefault().getClass().getSimpleName()); + assertEquals(QualifierBeanOne.class.getSimpleName(), app.getQualifierFieldInjection().qualifierBeanOne.getClass().getSimpleName()); + assertEquals(QualifierBeanTwo.class.getSimpleName(), app.getQualifierFieldInjection().qualifierBeanTwo.getClass().getSimpleName()); } @@ -48,4 +65,44 @@ public void testAppSimpleBean() { assertEquals(QualifierBeanTwo.class, app.getQualifierConstructorInjection().qualifierBeanTwo.getClass()); } + + @Test + public void testBeanManager() { + Set beans = new HashSet<>(); + for (SyncBeanDef lookupBean : app.beanManager.lookupBeans(QualifierBean.class)) { + beans.add(lookupBean.getInstance()); + } + + assertEquals(3, beans.size()); + List result = new ArrayList<>(); + for (SyncBeanDef lookupBean : app.beanManager.lookupBeans(QualifierBean.class)) { + result.add(((QualifierBean) lookupBean.getInstance()).say()); + } + assertTrue(result.contains("org.treblereel.injection.qualifiers.QualifierBeanDefault")); + assertTrue(result.contains("org.treblereel.injection.qualifiers.QualifierBeanOne")); + assertTrue(result.contains("org.treblereel.injection.qualifiers.QualifierBeanTwo")); + + QualifierOne qualifierOne = new org.treblereel.injection.qualifiers.QualifierOne() { + + public Class annotationType() { + return org.treblereel.injection.qualifiers.QualifierOne.class; + } + }; + + QualifierTwo qualifierTwo = new org.treblereel.injection.qualifiers.QualifierTwo() { + + public Class annotationType() { + return org.treblereel.injection.qualifiers.QualifierTwo.class; + } + }; + + assertEquals(QualifierBeanOne.class, + app.beanManager.lookupBean(QualifierBean.class, qualifierOne).getInstance().getClass()); + assertEquals(QualifierBeanTwo.class, + app.beanManager.lookupBean(QualifierBean.class, qualifierTwo).getInstance().getClass()); + assertEquals(QualifierBeanDefault.class, + app.beanManager.lookupBean(QualifierBean.class).getInstance().getClass()); + + + } } diff --git a/tests/jre-tests/src/test/java/org/treblereel/SimpleBeanProducerTest.java b/tests/jre-tests/src/test/java/org/treblereel/SimpleBeanProducerTest.java index 3236daf7..ce9bec3b 100644 --- a/tests/jre-tests/src/test/java/org/treblereel/SimpleBeanProducerTest.java +++ b/tests/jre-tests/src/test/java/org/treblereel/SimpleBeanProducerTest.java @@ -15,9 +15,13 @@ package org.treblereel; import org.junit.Test; +import org.treblereel.produces.scoped.URLPatternMatcherHolder; +import org.treblereel.produces.staticproduces.MyStaticBean; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 @@ -30,10 +34,45 @@ public void testAppSimpleBean() { app.getSimpleBeanProducerTest().getSimpleBeanDependentTwo()); assertEquals(app.getSimpleBeanProducerTest().getSimpleBeanSingletonOne(), app.getSimpleBeanProducerTest().getSimpleBeanSingletonTwo()); + + assertNotNull(app.getSimpleBeanProducerTest().getSimpleBeanDependentOne()); + assertNotNull(app.getSimpleBeanProducerTest().getSimpleBeanDependentTwo()); + assertNotNull(app.getSimpleBeanProducerTest().getSimpleBeanSingletonOne()); + assertNotNull(app.getSimpleBeanProducerTest().getSimpleBeanSingletonTwo()); } - // @Test + @Test public void testQualifierBeanProducerTest() { - assertEquals("ZZZ", app.getQualifierBeanProducerTest().getQualifierBean().say()); + assertNotNull(app.getQualifierBeanProducerTest().getQualifierBean()); + assertEquals("REDHAT", app.getQualifierBeanProducerTest().getQualifierBean().say()); + } + + @Test + public void testURLPatternMatcherTest() { + assertNotNull(app.beanManager.lookupBean(URLPatternMatcherHolder.class) + .getInstance().matcher); + assertNotNull(app.beanManager.lookupBean(URLPatternMatcherHolder.class) + .getInstance().matcher.test()); + assertEquals("URLPatternMatcherProvider", + app.beanManager.lookupBean(URLPatternMatcherHolder.class) + .getInstance().matcher.test()); + } + + @Test + public void testAppStaticBean() { + assertNotNull(app.getSimpleBeanProducerTest().getMyStaticBean()); + assertTrue(app.getSimpleBeanProducerTest().getMyStaticBean().ready); + assertEquals(MyStaticBean.class.getCanonicalName(), + app.getSimpleBeanProducerTest().getMyStaticBean().whoami()); + + assertNotNull(app.beanManager.lookupBean(MyStaticBean.class).getInstance()); + assertTrue(app.beanManager.lookupBean(MyStaticBean.class).getInstance().ready); + + assertEquals(MyStaticBean.class.getCanonicalName(), + app.beanManager.lookupBean(MyStaticBean.class).getInstance().whoami()); + + } + + } diff --git a/tests/jre-tests/src/test/java/org/treblereel/inject/CycleDepsTest.java b/tests/jre-tests/src/test/java/org/treblereel/inject/CycleDepsTest.java new file mode 100644 index 00000000..0ded203a --- /dev/null +++ b/tests/jre-tests/src/test/java/org/treblereel/inject/CycleDepsTest.java @@ -0,0 +1,85 @@ +/* + * Copyright © 2021 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.inject; + +import io.crysknife.annotation.CircularDependency; +import io.crysknife.client.BeanManager; +import org.junit.Test; +import org.treblereel.AbstractTest; +import org.treblereel.injection.cycle.AbstractRegistryFactory; +import org.treblereel.injection.cycle.AdapterManager; +import org.treblereel.injection.cycle.ClientRegistryFactoryImpl; +import org.treblereel.injection.cycle.simple.SimpleBeanOne; +import org.treblereel.injection.cycle.simple.SimpleBeanOneImpl; +import org.treblereel.injection.cycle.simple.SimpleBeanOneImpl_Factory; +import org.treblereel.injection.cycle.simple.SimpleBeanTwo; +import org.treblereel.injection.cycle.simple.SimpleBeanTwoImpl; + +import static org.junit.Assert.assertEquals; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/15/21 + */ +public class CycleDepsTest extends AbstractTest { + + @Test + public void testSimple() { + BeanManager beanManager = app.beanManager; + SimpleBeanOne simpleBeanOne = beanManager.lookupBean(SimpleBeanOne.class).getInstance(); + SimpleBeanTwo simpleBeanTwo = beanManager.lookupBean(SimpleBeanTwo.class).getInstance(); + + SimpleBeanOneImpl simpleBeanOne1 = (SimpleBeanOneImpl) simpleBeanOne; + SimpleBeanTwoImpl simpleBeanTwo2 = (SimpleBeanTwoImpl) simpleBeanTwo; + + assertEquals( + "org.treblereel.injection.cycle.simple.SimpleBeanOneImpl_Factory.ProxySimpleBeanOneImpl", + simpleBeanOne1.getClass().getCanonicalName()); + + assertEquals("SimpleBeanOneImpl", simpleBeanOne.whoAmI()); + assertEquals("SimpleBeanTwoImpl", simpleBeanOne.whoIsDep()); + assertEquals("SimpleBeanOneImpl.init", simpleBeanOne.getPostConstruct()); + + assertEquals( + "org.treblereel.injection.cycle.simple.SimpleBeanTwoImpl_Factory.ProxySimpleBeanTwoImpl", + simpleBeanTwo.getClass().getCanonicalName()); + + assertEquals("SimpleBeanTwoImpl", simpleBeanTwo.whoAmI()); + assertEquals("SimpleBeanOneImpl", simpleBeanTwo.whoIsDep()); + assertEquals("SimpleBeanTwoImpl.init", simpleBeanTwo.getPostConstruct()); + + assertEquals("FieldInjectBean", simpleBeanOne1.fieldInjectBean.hello()); + assertEquals("FieldInjectBean", simpleBeanTwo2.fieldInjectBean.hello()); + + } + + @Test + public void test() { + BeanManager beanManager = app.beanManager; + + AbstractRegistryFactory abstractRegistryFactory = beanManager + .lookupBean(AbstractRegistryFactory.class).getInstance(); + + AdapterManager adapterManager = + beanManager.lookupBean(AdapterManager.class).getInstance(); + + assertEquals( + "org.treblereel.injection.cycle.ClientRegistryFactoryImpl_Factory.ProxyClientRegistryFactoryImpl", + abstractRegistryFactory.getClass().getCanonicalName()); + + assertEquals( + "org.treblereel.injection.cycle.AdapterManagerImpl_Factory.ProxyAdapterManagerImpl", + adapterManager.getClass().getCanonicalName()); + } +} diff --git a/tests/src/main/java/org/treblereel/injection/singleton/SingletonBean.java b/tests/jre-tests/src/test/java/org/treblereel/inject/FactoryHolderTest.java similarity index 52% rename from tests/src/main/java/org/treblereel/injection/singleton/SingletonBean.java rename to tests/jre-tests/src/test/java/org/treblereel/inject/FactoryHolderTest.java index 53cf5ad3..618b7f69 100644 --- a/tests/src/main/java/org/treblereel/injection/singleton/SingletonBean.java +++ b/tests/jre-tests/src/test/java/org/treblereel/inject/FactoryHolderTest.java @@ -12,31 +12,27 @@ * the License. */ -package org.treblereel.injection.singleton; +package org.treblereel.inject; -import java.util.Random; +import org.junit.Test; +import org.treblereel.AbstractTest; +import org.treblereel.injection.inheritance.factories.FactoryHolder; -import javax.annotation.PostConstruct; -import javax.inject.Singleton; +import static org.junit.Assert.assertEquals; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/14/19 + * @author Dmitrii Tikhomirov Created by treblereel 9/24/21 */ -@Singleton -public class SingletonBean { +public class FactoryHolderTest extends AbstractTest { - private int random; - public String say() { - return this.getClass().getCanonicalName(); - } + // @Test + public void beanManagertest() { + FactoryHolder factoryHolder = + (FactoryHolder) app.beanManager.lookupBean(FactoryHolder.class).getInstance(); + - @PostConstruct - public void init() { - random = new Random().nextInt(); - } - public int getRandom() { - return random; + assertEquals(FactoryHolder.class, factoryHolder.getClass()); } } diff --git a/tests/src/test/java/org/treblereel/SimpleSingletonTest.java b/tests/jre-tests/src/test/java/org/treblereel/inject/NodeBuilderControlTest.java similarity index 56% rename from tests/src/test/java/org/treblereel/SimpleSingletonTest.java rename to tests/jre-tests/src/test/java/org/treblereel/inject/NodeBuilderControlTest.java index f91271bf..04265878 100644 --- a/tests/src/test/java/org/treblereel/SimpleSingletonTest.java +++ b/tests/jre-tests/src/test/java/org/treblereel/inject/NodeBuilderControlTest.java @@ -12,25 +12,23 @@ * the License. */ -package org.treblereel; +package org.treblereel.inject; import org.junit.Test; +import org.treblereel.AbstractTest; +import org.treblereel.injection.qualifiers.QualifierBeanDefault; +import org.treblereel.injection.qualifiers.QualifierBeanOne; +import org.treblereel.injection.qualifiers.QualifierBeanTwo; import static org.junit.Assert.assertEquals; /** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 + * @author Dmitrii Tikhomirov Created by treblereel 8/18/21 */ -public class SimpleSingletonTest extends AbstractTest { +public class NodeBuilderControlTest extends AbstractTest { @Test - public void testDependent() { - int fieldOne = app.simpleSingletonTest.getFieldOne().getRandom(); - int fieldTwo = app.simpleSingletonTest.getFieldTwo().getRandom(); - int constrOne = app.simpleSingletonTest.getConstrOne().getRandom(); - int constrTwo = app.simpleSingletonTest.getConstrTwo().getRandom(); - - assertEquals(fieldOne, fieldTwo); - assertEquals(constrOne, constrTwo); + public void testQualifierFieldInjectionBean() { + assertEquals("LienzoCanvasCommandFactory", app.nodeBuilderControl.get().hey()); } } diff --git a/tests/jre-tests/src/test/java/org/treblereel/inject/SpecializesTest.java b/tests/jre-tests/src/test/java/org/treblereel/inject/SpecializesTest.java new file mode 100644 index 00000000..3c2c0875 --- /dev/null +++ b/tests/jre-tests/src/test/java/org/treblereel/inject/SpecializesTest.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2021 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.inject; + +import org.junit.Before; +import org.junit.Test; +import org.treblereel.AbstractTest; +import org.treblereel.injection.managedinstance.SimpleBean; +import org.treblereel.injection.qualifiers.specializes.SpecializesBeanImpl; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import static org.junit.Assert.assertEquals; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/26/21 + */ +public class SpecializesTest extends AbstractTest { + + private final PrintStream standardOut = System.out; + private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream(); + + @Before + public void setUp() { + System.setOut(new PrintStream(outputStreamCaptor)); + } + + @Test + public void testSpecializesBean() { + assertEquals(SpecializesBeanImpl.class, app.specializesBeanHolder.bean.getClass()); + assertEquals(SimpleBean.class.getCanonicalName(), + ((SpecializesBeanImpl) app.specializesBeanHolder.bean).getSimpleBean().say()); + assertEquals(SimpleBean.class.getCanonicalName(), + ((SpecializesBeanImpl) app.specializesBeanHolder.bean).getLocalSimpleBean().say()); + } +} diff --git a/tests/jre-tests/src/test/java/org/treblereel/inject/TypedTest.java b/tests/jre-tests/src/test/java/org/treblereel/inject/TypedTest.java new file mode 100644 index 00000000..b1e0580f --- /dev/null +++ b/tests/jre-tests/src/test/java/org/treblereel/inject/TypedTest.java @@ -0,0 +1,41 @@ +/* + * 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 org.treblereel.inject; + +import org.junit.Test; +import org.treblereel.AbstractTest; +import org.treblereel.injection.qualifiers.typed.AbstractCanvasHandler; +import org.treblereel.injection.qualifiers.typed.ApplicationCommandManager; +import org.treblereel.injection.qualifiers.typed.RegistryAwareCommandManager; +import org.treblereel.injection.qualifiers.typed.SessionCommandManager; + +import static org.junit.Assert.assertEquals; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/25/21 + */ +public class TypedTest extends AbstractTest { + + @Test + public void testQualifierFieldInjectionBean() { + SessionCommandManager sessionCommandManager = + app.qualifierFieldInjection.morphNodeToolboxAction.sessionCommandManager; + + assertEquals(ApplicationCommandManager.class, sessionCommandManager.getClass()); + + assertEquals(RegistryAwareCommandManager.class, + ((ApplicationCommandManager) sessionCommandManager).commandManagerInstances.getClass()); + } +} diff --git a/tests/jre-tests/src/test/java/org/treblereel/inject/UnscopedBeanTest.java b/tests/jre-tests/src/test/java/org/treblereel/inject/UnscopedBeanTest.java new file mode 100644 index 00000000..227b55be --- /dev/null +++ b/tests/jre-tests/src/test/java/org/treblereel/inject/UnscopedBeanTest.java @@ -0,0 +1,39 @@ +/* + * Copyright © 2021 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.inject; + +import org.junit.Test; +import org.treblereel.AbstractTest; +import org.treblereel.injection.unscopedbean.UnscopedBeanHolder; + +import static org.junit.Assert.assertEquals; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/9/21 + */ +public class UnscopedBeanTest extends AbstractTest { + + + @Test + public void unscopedBeanTest() { + assertEquals("MyBean", + ((UnscopedBeanHolder) app.beanManager.lookupBean(UnscopedBeanHolder.class).getInstance()) + .getMyBean().getId()); + + assertEquals("MyBean2", + ((UnscopedBeanHolder) app.beanManager.lookupBean(UnscopedBeanHolder.class).getInstance()) + .getMyBean2().getId()); + } +} diff --git a/tests/jre-tests/src/test/java/org/treblereel/produces/typed/TypedProducesTest.java b/tests/jre-tests/src/test/java/org/treblereel/produces/typed/TypedProducesTest.java new file mode 100644 index 00000000..888bcdc3 --- /dev/null +++ b/tests/jre-tests/src/test/java/org/treblereel/produces/typed/TypedProducesTest.java @@ -0,0 +1,35 @@ +/* + * Copyright © 2021 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.typed; + +import org.junit.Test; +import org.treblereel.AbstractTest; + +import static org.junit.Assert.assertNotNull; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 10/4/21 + */ +public class TypedProducesTest extends AbstractTest { + + + @Test + public void test() { + TypedProducesTestHolder holder = + app.beanManager.lookupBean(TypedProducesTestHolder.class).getInstance(); + assertNotNull(holder); + assertNotNull(holder.jQueryPopover); + } +} diff --git a/tests/src/main/java/org/treblereel/App.java b/tests/src/main/java/org/treblereel/App.java deleted file mode 100644 index 28f926d2..00000000 --- a/tests/src/main/java/org/treblereel/App.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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 org.treblereel; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; - -import io.crysknife.annotation.Application; -import org.treblereel.injection.applicationscoped.SimpleBeanApplicationScoped; -import org.treblereel.injection.dependent.SimpleBeanDependent; -import org.treblereel.injection.dependent.SimpleDependentTest; -import org.treblereel.injection.named.NamedTestBean; -import org.treblereel.injection.qualifiers.QualifierConstructorInjection; -import org.treblereel.injection.qualifiers.QualifierFieldInjection; -import org.treblereel.injection.singleton.SimpleBeanSingleton; -import org.treblereel.injection.singleton.SimpleSingletonTest; -import org.treblereel.produces.SimpleBeanProducerTest; -import org.treblereel.produces.qualifier.QualifierBeanProducerTest; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 3/21/20 - */ -@Application -public class App { - - public String testPostConstruct; - @Inject - public QualifierFieldInjection qualifierFieldInjection; - @Inject - public QualifierConstructorInjection qualifierConstructorInjection; - @Inject - public SimpleDependentTest simpleDependentTest; - @Inject - public SimpleSingletonTest simpleSingletonTest; - @Inject - private SimpleBeanApplicationScoped simpleBeanApplicationScoped; - @Inject - private SimpleBeanSingleton simpleBeanSingleton; - @Inject - private SimpleBeanDependent simpleBeanDependent; - @Inject - private NamedTestBean namedTestBean; - - @Inject - private SimpleBeanProducerTest simpleBeanProducerTest; - - @Inject - private QualifierBeanProducerTest qualifierBeanProducerTest; - - public void onModuleLoad() { - new AppBootstrap(this).initialize(); - } - - @PostConstruct - public void init() { - this.testPostConstruct = "PostConstruct"; - } - - public String getTestPostConstruct() { - return testPostConstruct; - } - - public SimpleBeanApplicationScoped getSimpleBeanApplicationScoped() { - return simpleBeanApplicationScoped; - } - - public QualifierConstructorInjection getQualifierConstructorInjection() { - return qualifierConstructorInjection; - } - - public SimpleBeanSingleton getSimpleBeanSingleton() { - return simpleBeanSingleton; - } - - public SimpleBeanDependent getSimpleBeanDependent() { - return simpleBeanDependent; - } - - public QualifierFieldInjection getQualifierFieldInjection() { - return qualifierFieldInjection; - } - - public NamedTestBean getNamedTestBean() { - return namedTestBean; - } - - public SimpleBeanProducerTest getSimpleBeanProducerTest() { - return simpleBeanProducerTest; - } - - public void setSimpleBeanProducerTest(SimpleBeanProducerTest simpleBeanProducerTest) { - this.simpleBeanProducerTest = simpleBeanProducerTest; - } - - public QualifierBeanProducerTest getQualifierBeanProducerTest() { - return qualifierBeanProducerTest; - } -} diff --git a/tests/src/main/java/org/treblereel/injection/dependent/SimpleDependentTest.java b/tests/src/main/java/org/treblereel/injection/dependent/SimpleDependentTest.java deleted file mode 100644 index f77a48b2..00000000 --- a/tests/src/main/java/org/treblereel/injection/dependent/SimpleDependentTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 org.treblereel.injection.dependent; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -@Singleton -public class SimpleDependentTest { - - @Inject - private SimpleBeanDependent fieldOne; - @Inject - private SimpleBeanDependent fieldTwo; - private SimpleBeanDependent constrOne; - private SimpleBeanDependent constrTwo; - - @Inject - public SimpleDependentTest(SimpleBeanDependent constrOne, SimpleBeanDependent constrTwo) { - this.constrOne = constrOne; - this.constrTwo = constrTwo; - } - - public SimpleBeanDependent getFieldOne() { - return fieldOne; - } - - public SimpleBeanDependent getFieldTwo() { - return fieldTwo; - } - - public SimpleBeanDependent getConstrOne() { - return constrOne; - } - - public SimpleBeanDependent getConstrTwo() { - return constrTwo; - } -} diff --git a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierConstructorInjection.java b/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierConstructorInjection.java deleted file mode 100644 index 26d45ee7..00000000 --- a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierConstructorInjection.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 org.treblereel.injection.qualifiers; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import io.crysknife.annotation.Lazy; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/14/19 - */ -@Singleton -public class QualifierConstructorInjection { - - public QualifierBean qualifierBeanOne; - - public QualifierBean qualifierBeanTwo; - - @Inject - @Lazy - public QualifierBean qualifier; - - @Inject - public QualifierConstructorInjection(@QualifierTwo @Lazy QualifierBean qualifierBeanTwo, - @QualifierOne QualifierBean qualifierBeanOne) { - this.qualifierBeanOne = qualifierBeanOne; - this.qualifierBeanTwo = qualifierBeanTwo; - } -} diff --git a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierFieldInjection.java b/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierFieldInjection.java deleted file mode 100644 index 31bacd7b..00000000 --- a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierFieldInjection.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 org.treblereel.injection.qualifiers; - -import javax.enterprise.inject.Default; -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/14/19 - */ -@Singleton -public class QualifierFieldInjection { - - @Inject - @QualifierOne - public QualifierBean qualifierBeanOne; - - @Inject - @QualifierTwo - public QualifierBean qualifierBeanTwo; - - @Inject - @Default - public QualifierBean qualifierBeanDefault; - - public QualifierBean getQualifierBeanOne() { - return qualifierBeanOne; - } - - public QualifierBean getQualifierBeanTwo() { - return qualifierBeanTwo; - } - - public QualifierBean getQualifierBeanDefault() { - return qualifierBeanDefault; - } -} diff --git a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierTwo.java b/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierTwo.java deleted file mode 100644 index e9b29cca..00000000 --- a/tests/src/main/java/org/treblereel/injection/qualifiers/QualifierTwo.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 org.treblereel.injection.qualifiers; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import javax.inject.Qualifier; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/13/19 - */ -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Qualifier -public @interface QualifierTwo { - -} diff --git a/tests/src/main/java/org/treblereel/injection/singleton/SimpleSingletonTest.java b/tests/src/main/java/org/treblereel/injection/singleton/SimpleSingletonTest.java deleted file mode 100644 index 9a05c057..00000000 --- a/tests/src/main/java/org/treblereel/injection/singleton/SimpleSingletonTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 org.treblereel.injection.singleton; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -@Singleton -public class SimpleSingletonTest { - - @Inject - private SingletonBean fieldOne; - @Inject - private SingletonBean fieldTwo; - private SingletonBean constrOne; - private SingletonBean constrTwo; - - @Inject - public SimpleSingletonTest(SingletonBean constrOne, SingletonBean constrTwo) { - this.constrOne = constrOne; - this.constrTwo = constrTwo; - } - - public SingletonBean getFieldOne() { - return fieldOne; - } - - public SingletonBean getFieldTwo() { - return fieldTwo; - } - - public SingletonBean getConstrOne() { - return constrOne; - } - - public SingletonBean getConstrTwo() { - return constrTwo; - } -} diff --git a/tests/src/main/java/org/treblereel/produces/SimpleBeanDependent.java b/tests/src/main/java/org/treblereel/produces/SimpleBeanDependent.java deleted file mode 100644 index 377adc98..00000000 --- a/tests/src/main/java/org/treblereel/produces/SimpleBeanDependent.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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 org.treblereel.produces; - -import java.util.Objects; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -public class SimpleBeanDependent { - - private String foo; - private int bar; - private int staticValue; - - public String getFoo() { - return foo; - } - - public void setFoo(String foo) { - this.foo = foo; - } - - public int getBar() { - return bar; - } - - public void setBar(int bar) { - this.bar = bar; - } - - public int getStaticValue() { - return staticValue; - } - - public void setStaticValue(int staticValue) { - this.staticValue = staticValue; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof SimpleBeanDependent)) { - return false; - } - SimpleBeanDependent that = (SimpleBeanDependent) o; - return getBar() == that.getBar() && getStaticValue() == that.getStaticValue() - && Objects.equals(getFoo(), that.getFoo()); - } - - @Override - public int hashCode() { - return Objects.hash(getFoo(), getBar(), getStaticValue()); - } -} diff --git a/tests/src/main/java/org/treblereel/produces/SimpleBeanProducer.java b/tests/src/main/java/org/treblereel/produces/SimpleBeanProducer.java deleted file mode 100644 index 6ea7a1a0..00000000 --- a/tests/src/main/java/org/treblereel/produces/SimpleBeanProducer.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 org.treblereel.produces; - -import java.util.Random; - -import javax.enterprise.context.Dependent; -import javax.enterprise.inject.Produces; -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -public class SimpleBeanProducer { - - @Inject - private RandomGenerator randomGenerator; - - @Produces - @Singleton - public SimpleBeanSingleton getSimpleBeanSingleton() { - SimpleBeanSingleton bean = new SimpleBeanSingleton(); - bean.setFoo(this.getClass().getSimpleName()); - bean.setBar(new Random().nextInt()); - bean.setStaticValue(randomGenerator.getRandom()); - return bean; - } - - @Produces - @Dependent - public SimpleBeanDependent getSimpleBeanDependent() { - SimpleBeanDependent bean = new SimpleBeanDependent(); - bean.setFoo(this.getClass().getSimpleName()); - bean.setBar(new Random().nextInt()); - bean.setStaticValue(randomGenerator.getRandom()); - return bean; - } -} diff --git a/tests/src/main/java/org/treblereel/produces/SimpleBeanProducerTest.java b/tests/src/main/java/org/treblereel/produces/SimpleBeanProducerTest.java deleted file mode 100644 index 6578ce22..00000000 --- a/tests/src/main/java/org/treblereel/produces/SimpleBeanProducerTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 org.treblereel.produces; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -@Singleton -public class SimpleBeanProducerTest { - - @Inject - private SimpleBeanSingleton simpleBeanSingletonOne; - @Inject - private SimpleBeanSingleton simpleBeanSingletonTwo; - @Inject - private SimpleBeanDependent simpleBeanDependentOne; - @Inject - private SimpleBeanDependent simpleBeanDependentTwo; - - public SimpleBeanSingleton getSimpleBeanSingletonOne() { - return simpleBeanSingletonOne; - } - - public SimpleBeanSingleton getSimpleBeanSingletonTwo() { - return simpleBeanSingletonTwo; - } - - public SimpleBeanDependent getSimpleBeanDependentOne() { - return simpleBeanDependentOne; - } - - public SimpleBeanDependent getSimpleBeanDependentTwo() { - return simpleBeanDependentTwo; - } -} diff --git a/tests/src/main/java/org/treblereel/produces/SimpleBeanSingleton.java b/tests/src/main/java/org/treblereel/produces/SimpleBeanSingleton.java deleted file mode 100644 index 39c1af1f..00000000 --- a/tests/src/main/java/org/treblereel/produces/SimpleBeanSingleton.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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 org.treblereel.produces; - -import java.util.Objects; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -public class SimpleBeanSingleton { - - private String foo; - private int bar; - private int staticValue; - - @Override - public int hashCode() { - return Objects.hash(getFoo(), getBar(), getStaticValue()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof SimpleBeanSingleton)) { - return false; - } - SimpleBeanSingleton that = (SimpleBeanSingleton) o; - return getBar() == that.getBar() && getStaticValue() == that.getStaticValue() - && Objects.equals(getFoo(), that.getFoo()); - } - - public int getBar() { - return bar; - } - - public void setBar(int bar) { - this.bar = bar; - } - - public int getStaticValue() { - return staticValue; - } - - public String getFoo() { - return foo; - } - - public void setFoo(String foo) { - this.foo = foo; - } - - public void setStaticValue(int staticValue) { - this.staticValue = staticValue; - } -} diff --git a/tests/src/test/java/org/treblereel/NamedTest.java b/tests/src/test/java/org/treblereel/NamedTest.java deleted file mode 100644 index adc182f6..00000000 --- a/tests/src/test/java/org/treblereel/NamedTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 org.treblereel; - -import org.junit.Test; -import org.treblereel.injection.named.NamedBeanDefault; -import org.treblereel.injection.named.NamedBeanOne; -import org.treblereel.injection.named.NamedBeanTwo; - -import static org.junit.Assert.assertEquals; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -public class NamedTest extends AbstractTest { - - @Test - public void testNamedConstructorInjection() { - assertEquals(NamedBeanDefault.class.getSimpleName(), - app.getNamedTestBean().namedConstructorInjection.def.getClass().getSimpleName()); - assertEquals(NamedBeanOne.class.getSimpleName(), - app.getNamedTestBean().namedConstructorInjection.one.getClass().getSimpleName()); - assertEquals(NamedBeanTwo.class.getSimpleName(), - app.getNamedTestBean().namedConstructorInjection.two.getClass().getSimpleName()); - } - - @Test - public void testNamedFieldInjection() { - assertEquals(NamedBeanDefault.class.getSimpleName(), - app.getNamedTestBean().namedFieldInjection.def.getClass().getSimpleName()); - assertEquals(NamedBeanOne.class.getSimpleName(), - app.getNamedTestBean().namedFieldInjection.one.getClass().getSimpleName()); - assertEquals(NamedBeanTwo.class.getSimpleName(), - app.getNamedTestBean().namedFieldInjection.two.getClass().getSimpleName()); - } -} diff --git a/tests/src/test/java/org/treblereel/PostConstructTest.java b/tests/src/test/java/org/treblereel/PostConstructTest.java deleted file mode 100644 index 1c23f022..00000000 --- a/tests/src/test/java/org/treblereel/PostConstructTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 org.treblereel; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -public class PostConstructTest extends AbstractTest { - - @Test - public void testPostConstructAppBootstrap() { - assertEquals("PostConstruct", app.testPostConstruct); - } - - @Test - public void testSimpleBeanSingleton() { - assertEquals("done", app.getSimpleBeanSingleton().getPostConstruct()); - } - - @Test - public void testSimpleBeanApplicationScoped() { - assertEquals("done", app.getSimpleBeanApplicationScoped().getPostConstruct()); - } - - @Test - public void testSimpleDependent() { - assertEquals("done", app.getSimpleBeanDependent().getPostConstruct()); - } - -} diff --git a/tests/src/test/java/org/treblereel/QualifierTest.java b/tests/src/test/java/org/treblereel/QualifierTest.java deleted file mode 100644 index c3d0b290..00000000 --- a/tests/src/test/java/org/treblereel/QualifierTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 org.treblereel; - -import org.junit.Test; -import org.treblereel.injection.qualifiers.QualifierBeanDefault; -import org.treblereel.injection.qualifiers.QualifierBeanOne; -import org.treblereel.injection.qualifiers.QualifierBeanTwo; -import org.treblereel.injection.qualifiers.QualifierConstructorInjection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -public class QualifierTest extends AbstractTest { - - @Test - public void testQualifierFieldInjectionBean() { - assertEquals(QualifierBeanDefault.class.getSimpleName(), - app.getQualifierFieldInjection().getQualifierBeanDefault().getClass().getSimpleName()); - assertEquals(QualifierBeanOne.class.getSimpleName(), - app.getQualifierFieldInjection().qualifierBeanOne.getClass().getSimpleName()); - assertEquals(QualifierBeanTwo.class.getSimpleName(), - app.getQualifierFieldInjection().qualifierBeanTwo.getClass().getSimpleName()); - } - - @Test - public void testAppSimpleBean() { - assertNotNull(app.getQualifierConstructorInjection()); - assertEquals(QualifierConstructorInjection.class.getSimpleName(), - app.getQualifierConstructorInjection().getClass().getSimpleName()); - assertEquals(QualifierBeanOne.class, - app.getQualifierConstructorInjection().qualifierBeanOne.getClass()); - assertEquals(QualifierBeanTwo.class, - app.getQualifierConstructorInjection().qualifierBeanTwo.getClass()); - } -} diff --git a/tests/src/test/java/org/treblereel/SimpleBeanProducerTest.java b/tests/src/test/java/org/treblereel/SimpleBeanProducerTest.java deleted file mode 100644 index 3236daf7..00000000 --- a/tests/src/test/java/org/treblereel/SimpleBeanProducerTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 org.treblereel; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -public class SimpleBeanProducerTest extends AbstractTest { - - @Test - public void testAppSimpleBean() { - assertNotEquals(app.getSimpleBeanProducerTest().getSimpleBeanDependentOne(), - app.getSimpleBeanProducerTest().getSimpleBeanDependentTwo()); - assertEquals(app.getSimpleBeanProducerTest().getSimpleBeanSingletonOne(), - app.getSimpleBeanProducerTest().getSimpleBeanSingletonTwo()); - } - - // @Test - public void testQualifierBeanProducerTest() { - assertEquals("ZZZ", app.getQualifierBeanProducerTest().getQualifierBean().say()); - } -} diff --git a/tests/src/test/java/org/treblereel/SimpleBeanTest.java b/tests/src/test/java/org/treblereel/SimpleBeanTest.java deleted file mode 100644 index e82defc3..00000000 --- a/tests/src/test/java/org/treblereel/SimpleBeanTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 org.treblereel; - -import org.junit.Test; -import org.treblereel.injection.applicationscoped.SimpleBeanApplicationScoped; -import org.treblereel.injection.qualifiers.QualifierBeanOne; -import org.treblereel.injection.qualifiers.QualifierBeanTwo; -import org.treblereel.injection.qualifiers.QualifierConstructorInjection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 9/10/19 - */ -public class SimpleBeanTest extends AbstractTest { - - @Test - public void testAppSimpleBean() { - assertNotNull(app.getSimpleBeanApplicationScoped()); - assertEquals(SimpleBeanApplicationScoped.class.getSimpleName(), - app.getSimpleBeanApplicationScoped().getName()); - - assertNotNull(app.getQualifierConstructorInjection()); - assertEquals(QualifierConstructorInjection.class.getSimpleName(), - app.getQualifierConstructorInjection().getClass().getSimpleName()); - assertEquals(QualifierBeanOne.class, - app.getQualifierConstructorInjection().qualifierBeanOne.getClass()); - assertEquals(QualifierBeanTwo.class, - app.getQualifierConstructorInjection().qualifierBeanTwo.getClass()); - } -} diff --git a/tests/src/test/java/org/treblereel/SimpleDependentTest.java b/tests/src/test/java/org/treblereel/SimpleDependentTest.java deleted file mode 100644 index b760e8bd..00000000 --- a/tests/src/test/java/org/treblereel/SimpleDependentTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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 org.treblereel; - -import org.junit.Test; - -import static org.junit.Assert.assertNotEquals; - -/** - * @author Dmitrii Tikhomirov Created by treblereel 4/26/20 - */ -public class SimpleDependentTest extends AbstractTest { - - @Test - public void testDependent() { - int fieldOne = app.simpleDependentTest.getFieldOne().getRandom(); - int fieldTwo = app.simpleDependentTest.getFieldTwo().getRandom(); - int constrOne = app.simpleDependentTest.getConstrOne().getRandom(); - int constrTwo = app.simpleDependentTest.getConstrTwo().getRandom(); - - assertNotEquals(fieldOne, fieldTwo); - assertNotEquals(constrOne, constrTwo); - } -} diff --git a/ui/databinding/api/pom.xml b/ui/databinding/api/pom.xml index e2b4dd9f..b90657c2 100644 --- a/ui/databinding/api/pom.xml +++ b/ui/databinding/api/pom.xml @@ -5,7 +5,7 @@ io.crysknife databinding-parent - 0.1-SNAPSHOT + 0.3-SNAPSHOT databinding-api @@ -49,7 +49,6 @@ org.gwtproject.widgets gwt-widgets - 1.0-SNAPSHOT org.jboss.elemento @@ -58,19 +57,16 @@ io.crysknife crysknife-annotations - ${project.version} provided io.crysknife crysknife-core - ${project.version} provided io.crysknife templates-api - ${project.version} diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/BindableListWrapper.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/BindableListWrapper.java index 8d707948..5fb683c6 100644 --- a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/BindableListWrapper.java +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/BindableListWrapper.java @@ -14,6 +14,12 @@ package io.crysknife.ui.databinding.client; +import io.crysknife.client.internal.Assert; +import io.crysknife.ui.databinding.client.api.handler.list.BindableListChangeHandler; +import io.crysknife.ui.databinding.client.api.handler.property.PropertyChangeEvent; +import io.crysknife.ui.databinding.client.api.handler.property.PropertyChangeHandler; +import org.gwtproject.event.shared.HandlerRegistration; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -24,12 +30,6 @@ import java.util.ListIterator; import java.util.Map; -import org.gwtproject.event.shared.HandlerRegistration; -import io.crysknife.client.internal.Assert; -import io.crysknife.ui.databinding.client.api.handler.list.BindableListChangeHandler; -import io.crysknife.ui.databinding.client.api.handler.property.PropertyChangeEvent; -import io.crysknife.ui.databinding.client.api.handler.property.PropertyChangeHandler; - /** * Wraps a List to notify change handlers of all operations that mutate the underlying list. * @@ -51,10 +51,10 @@ public class BindableListWrapper implements List, BindableProxy> { Collections.newSetFromMap(new IdentityHashMap<>()); private final Map, PropertyChangeHandler> elementChangeHandlers = - new HashMap<>(); + new HashMap, PropertyChangeHandler>(); private final Map, PropertyChangeUnsubscribeHandle> unsubscribeHandlesByHandler = - new HashMap<>(); + new HashMap, PropertyChangeUnsubscribeHandle>(); private final BindableProxyAgent> agent; @@ -460,6 +460,11 @@ public void add(M e) { } } + @Override + public Object unwrap() { + return list; + } + @Override public Object get(String propertyName) { if ("this".equals(propertyName)) { diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/BindableProxy.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/BindableProxy.java index 6db265c0..7fcdbdf2 100644 --- a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/BindableProxy.java +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/BindableProxy.java @@ -16,20 +16,22 @@ import io.crysknife.ui.databinding.client.api.Bindable; import io.crysknife.ui.databinding.client.api.Converter; +import io.crysknife.ui.databinding.client.api.WrappedPortable; +import org.gwtproject.user.client.ui.Widget; /** * This interface is implemented by the generated proxies for {@link Bindable} types. - * + * * @author Christian Sadilek */ -public interface BindableProxy extends HasProperties { +public interface BindableProxy extends WrappedPortable, HasProperties { /** * Returns the {@link BindableProxyAgent} of this proxy. - * + * * @return the proxy's agent, never null. */ - BindableProxyAgent getBindableProxyAgent(); + public BindableProxyAgent getBindableProxyAgent(); /** * Updates all widgets bound to the model instance associated with this proxy (see @@ -37,13 +39,13 @@ public interface BindableProxy extends HasProperties { * model instance has undergone changes that were not caused by calls to methods on this proxy and * were therefore not visible to this proxy (e.g direct field access by JPA). */ - void updateWidgets(); + public void updateWidgets(); /** * Returns a new non-proxied instance with state copied recursively from this target. - * + * * @return A recursively unwrapped (i.e. non-proxied) instance with state copied from the proxy * target. */ - T deepUnwrap(); + public T deepUnwrap(); } diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/MapBindableProxy.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/MapBindableProxy.java index c64dc29d..90fccaca 100644 --- a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/MapBindableProxy.java +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/MapBindableProxy.java @@ -14,6 +14,9 @@ package io.crysknife.ui.databinding.client; +import io.crysknife.ui.databinding.client.api.DataBinder; +import io.crysknife.ui.databinding.client.api.StateSync; + import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -21,9 +24,6 @@ import java.util.Map; import java.util.Set; -import io.crysknife.ui.databinding.client.api.DataBinder; -import io.crysknife.ui.databinding.client.api.StateSync; - /** * A custom {@link BindableProxy} allowing data-binding to a {@link Map}. This allows data-binding * to be used with a collection of properties that is not known at compile-time. @@ -43,6 +43,11 @@ public MapBindableProxy(final Map propertyTypes) { DataBinder.forMap(((MapPropertyType) entry.getValue()).getPropertyTypes()))); } + @Override + public Object unwrap() { + return agent.target; + } + @Override public Object get(final String propertyName) { if (!agent.propertyTypes.containsKey(propertyName)) { @@ -148,7 +153,7 @@ public Object put(final String key, Object value) { @Override public Object remove(final Object key) { - throw new UnsupportedOperationException(this.getClass().getCanonicalName() + " remove"); + throw new UnsupportedOperationException(); } @Override @@ -158,7 +163,7 @@ public void putAll(final Map m) { @Override public void clear() { - throw new UnsupportedOperationException(this.getClass().getCanonicalName() + " clear"); + throw new UnsupportedOperationException(); } @Override diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/AutoBound.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/AutoBound.java new file mode 100644 index 00000000..a6fa1478 --- /dev/null +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/AutoBound.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 Red Hat, Inc. and/or its affiliates. + * + * 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.databinding.client.api; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation is only meaningful on a {@link DataBinder} field or constructor/method parameter. + *

+ * It indicates that the annotated {@link DataBinder} is used to automatically bind all + * corresponding widgets to properties of a data model (the model instance associated with the data + * binder instance). The widgets are inferred from all enclosing fields and methods annotated with + * {@link org.jboss.errai.ui.shared.api.annotations.Bound} of the class that defines the + * {@link DataBinder} and all its super classes. + *

+ * There can only be one auto bound {@link DataBinder} per class. + * + * @author Christian Sadilek + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface AutoBound { + +} diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/Bound.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/Bound.java new file mode 100644 index 00000000..5e903a9e --- /dev/null +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/Bound.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 Red Hat, Inc. and/or its affiliates. + * + * 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.databinding.client.api; + +import elemental2.dom.Element; +import jsinterop.annotations.JsType; +import org.gwtproject.event.dom.client.KeyUpEvent; +import org.gwtproject.event.logical.shared.ValueChangeEvent; +import org.gwtproject.user.client.ui.HasText; +import org.gwtproject.user.client.ui.HasValue; +import org.gwtproject.user.client.ui.Widget; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that an annotated component (a {@link Widget}, {@link Element}, or native + * {@link JsType} wrapping a DOM element) should automatically be bound to a property of a data + * model associated with a {@link DataBinder} (see {@link AutoBound} and {@link Model}). + *

+ * The annotated component can either be a field, method or constructor parameter or a method return + * value. If it is a {@link Widget} or a templated Errai UI bean then it must implement either + * {@link HasText}, {@link HasValue} or {@link TakesValue}. Note that a {@link Bound} field can but + * does not have to be injected. The following example shows all valid use cases for the + * {@link Bound} annotation. + * + *

+ *      public class MyBean {
+ *        {@code @Inject} {@code @Model}
+ *        private MyModel model;
+ *
+ *        {@code @Bound}
+ *        private Label boundLabel = new Label();
+ *
+ *        {@code @Inject} {@code @Bound}
+ *        private TextBox injectedBoundTextBox;
+ *
+ *        {@code @Inject}
+ *        public MyBean({@code @Bound} SomeWidget boundWidget) {
+ *          this.boundWidget = boundWidget;
+ *        }
+ *
+ *        {@code @Inject}
+ *        public void setWidget({@code @Bound} SomeWidget boundWidget) {
+ *          this.boundWidget = boundWidget;
+ *        }
+ *
+ *        {@code @Bound}
+ *        public SomeWidget getWidget() {
+ *          ...
+ *        }
+ *      }
+ * 
+ * + * If no property is specified, the component is bound to the data model property with the same name + * as the field, parameter, or method which is the target of this annotation. + *

+ * + * @author Christian Sadilek + */ +@Documented +@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@SuppressWarnings("rawtypes") +public @interface Bound { + + /** + * The name of the data model property (or a property chain) to bind the component to, following + * Java bean conventions. If omitted, the widget will be bound to the data model property with the + * same name as the field, parameter or method which is the target of this annotation. + */ + String property() default ""; + + /** + * The {@link Converter} to use when setting values on the model or component. + */ + // The NO_CONVERTER class needs to be fully qualified here to work around a + // JDK bug: http://bugs.sun.com/view_bug.do?bug_id=6512707 + Class converter() default NO_CONVERTER.class; + + static abstract class NO_CONVERTER implements Converter { + } + + /** + * A flag indicating whether or not the data model property should be updated when the widget + * fires a {@link KeyUpEvent}, in addition to the default {@link ValueChangeEvent}. + */ + boolean onKeyUp() default false; +} diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/DataBinder.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/DataBinder.java index bc2ab084..508bb687 100644 --- a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/DataBinder.java +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/DataBinder.java @@ -20,10 +20,6 @@ import java.util.Optional; import java.util.Set; -import org.gwtproject.event.dom.client.KeyUpEvent; -import org.gwtproject.event.logical.shared.ValueChangeEvent; -import org.gwtproject.user.client.ui.HasValue; -import org.gwtproject.user.client.ui.Widget; import io.crysknife.client.internal.Assert; import io.crysknife.client.internal.collections.Multimap; import io.crysknife.ui.databinding.client.BindableProxy; @@ -41,6 +37,10 @@ import io.crysknife.ui.databinding.client.PropertyType; import io.crysknife.ui.databinding.client.api.handler.property.PropertyChangeEvent; import io.crysknife.ui.databinding.client.api.handler.property.PropertyChangeHandler; +import org.gwtproject.event.dom.client.KeyUpEvent; +import org.gwtproject.event.logical.shared.ValueChangeEvent; +import org.gwtproject.user.client.ui.HasValue; +import org.gwtproject.user.client.ui.Widget; /** * Provides an API to programmatically bind properties of a data model instance (any POJO annotated @@ -132,9 +132,7 @@ public static DataBinder forModel(final T model) { * @param property The name of the model property that should be used for the binding, following * Java bean conventions. Chained (nested) properties are supported and must be dot (.) * delimited (e.g. customer.address.street). Must not be null. - * * @return the same {@link DataBinder} instance to support call chaining. - * * @throws NonExistingPropertyException If the {@code model} does not have a property with the * given name. * @throws InvalidPropertyExpressionException If the provided property chain expression is @@ -158,9 +156,7 @@ public DataBinder bind(final Object component, final String property) { * @param converter The converter to use for the binding, null if default conversion should be * used (see {@link Convert#getConverter(Class, Class)} or * {@link Convert#identityConverter(Class)} for possible arguments). - * * @return the same {@link DataBinder} instance to support call chaining. - * * @throws NonExistingPropertyException If the {@code model} does not have a property with the * given name. * @throws InvalidPropertyExpressionException If the provided property chain expression is @@ -188,9 +184,7 @@ public DataBinder bind(final Object component, final String property, * {@link Convert#identityConverter(Class)} for possible arguments). * @param initialState Specifies the origin of the initial state of both model and UI component. * Null if no initial state synchronization should be carried out. - * * @return the same {@link DataBinder} instance to support call chaining. - * * @throws NonExistingPropertyException If the {@code model} does not have a property with the * given name. * @throws InvalidPropertyExpressionException If the provided property chain expression is @@ -220,9 +214,7 @@ public DataBinder bind(final Object component, final String property, * Null if no initial state synchronization should be carried out. * @param bindOnKeyUp A boolean value that allows models bound to text-based components to be * updated on a {@link KeyUpEvent} as well as the default {@link ValueChangeEvent} - * * @return the same {@link DataBinder} instance to support call chaining. - * * @throws NonExistingPropertyException If the {@code model} does not have a property with the * given name. * @throws InvalidPropertyExpressionException If the provided property chain expression is @@ -255,7 +247,6 @@ public DataBinder bind(final Object component, final String property, * @param property The name of the property (or a property chain) to unbind, Must not be null. * * @return the same {@link DataBinder} instance to support call chaining. - * * @throws InvalidPropertyExpressionException If the provided property chain expression is * invalid. */ @@ -271,6 +262,7 @@ public DataBinder unbind(final String property) { // BindableProxyFactory#removeCachedProxyForModel). We throw away the // reference to the proxy to force a new lookup in case this data binder // will be reused. + unwrapProxy(); } return this; } @@ -300,6 +292,7 @@ private DataBinder unbind(final boolean clearBindings) { // BindableProxyFactory#removeCachedProxyForModel). We throw away the // reference to the proxy to force a new lookup in case this data binder // will be reused. + unwrapProxy(); return this; } @@ -340,7 +333,6 @@ public T getWorkingModel() { * be resumed if they are currently paused. * * @param model The instance of a {@link Bindable} type, must not be null. - * * @return The model instance which has to be used in place of the provided model (see * {@link #forModel(Object)} and {@link #forType(Class)}) if changes should be * automatically synchronized with the UI (also accessible using {@link #getModel()}). @@ -356,7 +348,6 @@ public T setModel(final T model) { * * @param model The instance of a {@link Bindable} type, must not be null. * @param initialState Specifies the origin of the initial state of both model and UI widget. - * * @return The model instance which has to be used in place of the provided model (see * {@link #forModel(Object)} and {@link #forType(Class)}) if changes should be * automatically synchronized with the UI (also accessible using {@link #getModel()}). @@ -374,7 +365,6 @@ public T setModel(final T model, final StateSync initialState) { * @param initialState Specifies the origin of the initial state of both model and UI widget. * @param fireChangeEvents Specifies whether or not {@link PropertyChangeEvent}s should be fired * as a consequence of the model change. - * * @return The model instance which has to be used in place of the provided model (see * {@link #forModel(Object)} and {@link #forType(Class)}) if changes should be * automatically synchronized with the UI (also accessible using {@link #getModel()}). @@ -423,7 +413,6 @@ public T setModel(final T model, final StateSync initialState, final boolean fir * {@link #bind(Widget, String)}). * * @param property The name of the property (or a property chain). Must not be null. - * * @return the list of widgets currently bound to the provided property or an empty list if no * widget was bound to the property. */ @@ -521,6 +510,13 @@ private BindableProxyAgent getAgent() { return ((BindableProxy) this.proxy).getBindableProxyAgent(); } + @SuppressWarnings("unchecked") + private void unwrapProxy() { + if (proxy instanceof BindableProxy) { + proxy = (T) ((BindableProxy) proxy).unwrap(); + } + } + private void ensureProxied() { if (!(proxy instanceof BindableProxy)) { proxy = BindableProxyFactory.getBindableProxy(Assert.notNull(proxy)); diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/HasModel.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/HasModel.java new file mode 100644 index 00000000..2512b362 --- /dev/null +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/HasModel.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. and/or its affiliates. + * + * 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.databinding.client.api; + +/** + * Indicates that the implementing widget displays an instance of type . + * + * @author Christian Sadilek + * + * @param the model type. + */ +public interface HasModel { + + /** + * Returns the model instance associated with this widget. + * + * @return the model instance, or null if no instance is associated with this widget. + */ + public M getModel(); + + /** + * Associate the model instance with this widget. + * + * @param model the model instance. + */ + public void setModel(M model); +} diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/Model.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/Model.java new file mode 100644 index 00000000..adda865b --- /dev/null +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/Model.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. and/or its affiliates. + * + * 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.databinding.client.api; + +import javax.inject.Qualifier; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that the annotated model should be managed by a {@link DataBinder} and therefore + * automatically bound to all enclosing widgets. + *

+ * The widgets are inferred from all enclosing fields and methods annotated with + * {@link org.jboss.errai.ui.shared.api.annotations.Bound} of the class that defines the + * {@link Model} and all its super classes. + *

+ * The annotated model can be a field and a method or constructor parameter. The following example + * shows all use cases for the {@link Model} annotation. + * + *

+ *      public class MyBean {
+ *        {@code @Inject} {@code @Model}
+ *        private MyModel model;
+ *
+ *        {@code @Inject}
+ *        public MyBean({@code @Model} MyModel model) {
+ *          this.model = model;
+ *        }
+ *
+ *        {@code @Inject}
+ *        public void setModel({@code @Model} MyModel model) {
+ *          this.model = model;
+ *        }
+ *      }
+ * 
+ * + * There can only be one {@link Model} per class. + *

+ * + * @author Christian Sadilek + * @author Mike Brock + */ +@Qualifier +@Documented +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Model { + +} diff --git a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentQualifierOne.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/ModelSetter.java similarity index 62% rename from tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentQualifierOne.java rename to ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/ModelSetter.java index bc32d6fc..6cff9ddc 100644 --- a/tests/j2cl-tests/src/main/java/org/treblereel/managedinstance/ComponentQualifierOne.java +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/ModelSetter.java @@ -1,5 +1,5 @@ /* - * Copyright © 2021 Treblereel + * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. * * 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 @@ -12,23 +12,26 @@ * the License. */ -package org.treblereel.managedinstance; +package io.crysknife.ui.databinding.client.api; +import javax.inject.Qualifier; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.inject.Qualifier; - /** - * @author Dmitrii Tikhomirov Created by treblereel 4/25/21 + * Indicates that the annotated method is used to replace a model instance managed by a + * {@link DataBinder}. The method is required to have a single parameter. The parameter type needs + * to correspond to the type of the managed model (see {@link Model} and {@link AutoBound}). + * + * @author Christian Sadilek + * @author Mike Brock */ -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) @Documented @Qualifier -public @interface ComponentQualifierOne { - +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ModelSetter { } diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/WrappedPortable.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/WrappedPortable.java new file mode 100644 index 00000000..6109d460 --- /dev/null +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/api/WrappedPortable.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. and/or its affiliates. + * + * 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.databinding.client.api; + +/** + * Wraps a {@link Portable} type. + * + * Generated classes (e.g proxies) can implement this interface to be serializable by Errai's + * marshalling framework. + * + * @author Christian Sadilek + */ +public interface WrappedPortable { + + /** + * Unwraps and returns the actual portable instance. + * + * @return the portable object to be marshalled, never null. + */ + public Object unwrap(); +} diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/DefaultListComponent.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/DefaultListComponent.java index f6264771..79150aaf 100644 --- a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/DefaultListComponent.java +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/DefaultListComponent.java @@ -24,9 +24,9 @@ import java.util.function.Function; import java.util.function.Supplier; +import elemental2.dom.Element; import elemental2.dom.HTMLElement; import jsinterop.base.Js; -import org.gwtproject.dom.client.Element; import org.gwtproject.event.shared.HandlerRegistration; import org.gwtproject.user.client.TakesValue; import io.crysknife.client.internal.Assert; @@ -79,7 +79,7 @@ public HandlerRegistration addComponentDestructionHandler(final Consumer hand } @Override - public HTMLElement element() { + public HTMLElement getElement() { return Js.uncheckedCast(root); } @@ -180,10 +180,9 @@ private void addComponent(final int index, final M item) { final C component = createComponent(item); final HTMLElement element = Assert.notNull(elementAccessor.apply(component)); if (index < components.size()) { - root.insertBefore(Js.uncheckedCast(element), - Js.uncheckedCast(Assert.notNull(elementAccessor.apply(components.get(index))))); + root.insertBefore(element, Assert.notNull(elementAccessor.apply(components.get(index)))); } else { - root.appendChild(Js.uncheckedCast(element)); + root.appendChild(element); } components.add(index, component); for (final Consumer handler : creationHandlers) { diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/ListComponent.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/ListComponent.java index 0cb06379..5ae55a6d 100644 --- a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/ListComponent.java +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/ListComponent.java @@ -23,15 +23,14 @@ import java.util.function.Function; import java.util.function.Supplier; +import elemental2.dom.DomGlobal; +import elemental2.dom.Element; +import io.crysknife.client.IsElement; import jsinterop.base.Js; -import org.gwtproject.dom.client.DivElement; -import org.gwtproject.dom.client.Document; -import org.gwtproject.dom.client.Element; import org.gwtproject.dom.client.TableSectionElement; import org.gwtproject.event.shared.HandlerRegistration; import org.gwtproject.user.client.TakesValue; import org.gwtproject.user.client.ui.IsWidget; -import org.jboss.elemento.IsElement; import io.crysknife.ui.databinding.client.api.Bindable; import io.crysknife.ui.databinding.client.api.handler.list.BindableListChangeHandler; @@ -101,7 +100,7 @@ default Optional getComponent(final M model) { void setSelector(Consumer selector); /** - * @param selector A {@link Consumer} called for every component that is unselected via + * @param deselector A {@link Consumer} called for every component that is unselected via * {@link #deselectComponent(TakesValue)}, {@link #deselectComponents(Collection)}, or * {@link #deselectAll()} . */ @@ -233,7 +232,7 @@ default void deselectAll() { static & IsElement> Builder forIsElementComponent( final Supplier supplier, final Consumer destroyer) { return new Builder<>( - root -> new DefaultListComponent<>(root, supplier, destroyer, c -> c.element())); + root -> new DefaultListComponent<>(root, supplier, destroyer, c -> c.getElement())); } /** @@ -271,7 +270,7 @@ private Builder(final Function> factory) { * the given tag name. */ public ListComponent inElement(final String tagName) { - return factory.apply(Document.get().createElement(tagName)); + return factory.apply(DomGlobal.document.createElement(tagName)); } /** @@ -279,7 +278,7 @@ public ListComponent inElement(final String tagName) { * tag. */ public ListComponent inDiv() { - return inElement(DivElement.TAG); + return inElement("div"); } /** diff --git a/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/ListComponentProvider.java b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/ListComponentProvider.java new file mode 100644 index 00000000..461c811b --- /dev/null +++ b/ui/databinding/api/src/main/java/io/crysknife/ui/databinding/client/components/ListComponentProvider.java @@ -0,0 +1,104 @@ +/** + * Copyright (C) 2016 Red Hat, Inc. and/or its affiliates. + *

+ * 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.databinding.client.components; + +import elemental2.dom.DomGlobal; +import elemental2.dom.HTMLElement; +import io.crysknife.client.BeanManager; +import io.crysknife.client.IsElement; +import io.crysknife.client.SyncBeanDef; +import io.crysknife.client.ioc.ContextualTypeProvider; +import io.crysknife.client.ioc.IOCProvider; +import jsinterop.base.Js; +import org.gwtproject.user.client.ui.IsWidget; + +import javax.enterprise.inject.Instance; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * Provides {@link ListComponent} instances that lookup displayed components through Errai IoC. Any + * qualifiers on the injection site are used when looking up displayed components. + * + * @author Max Barkley + */ +@SuppressWarnings("rawtypes") +@IOCProvider +public class ListComponentProvider implements ContextualTypeProvider { + + public final BeanManager beanManager; + + public ListComponentProvider(BeanManager beanManager) { + this.beanManager = beanManager; + } + + @SuppressWarnings("unchecked") + @Override + public ListComponent provide(final Class[] typeargs, final Annotation[] qualifiers) { + final Annotation[] filteredQualifiers = filterQualifiers(qualifiers); + final Optional listContainer = getListContainer(qualifiers); + final HTMLElement root = (HTMLElement) DomGlobal.document + .createElement(listContainer.map(anno -> anno.value()).orElse("div")); + final SyncBeanDef beanDef = + (SyncBeanDef) beanManager.lookupBean(typeargs[1], filteredQualifiers); + final Supplier supplier = () -> beanDef.getInstance(); + // final Consumer destroyer = (!Dependent.class.equals(beanDef.getScope()) ? c -> {} : c -> + // IOC.getBeanManager().destroyBean(c)); + final Consumer destroyer = (Consumer) o -> { + DomGlobal.console.log("destroyer is not supported yet"); + }; + + final Function elementAccessor; + if (beanDef.getInstance() instanceof IsElement) { + elementAccessor = (Function) c -> ((IsElement) c).getElement(); + } else if (beanDef.getInstance() instanceof IsWidget) { + elementAccessor = + c -> Js.uncheckedCast(((IsWidget) beanDef.getInstance()).asWidget().getElement()); + } else { + throw new RuntimeException("Cannot create element accessor for " + + beanDef.getInstance().getClass().getCanonicalName() + + ". Must implement IsElement or IsWidget."); + } + + return new DefaultListComponent(root, supplier, destroyer, elementAccessor); + } + + private Optional getListContainer(final Annotation[] qualifiers) { + for (final Annotation qual : qualifiers) { + if (qual.annotationType().equals(ListContainer.class)) { + return Optional.ofNullable((ListContainer) qual); + } + } + + return Optional.empty(); + } + + private Annotation[] filterQualifiers(final Annotation[] qualifiers) { + final List filtered = new ArrayList<>(qualifiers.length); + for (final Annotation qual : qualifiers) { + if (!qual.annotationType().equals(ListContainer.class)) { + filtered.add(qual); + } + } + + return filtered.toArray(new Annotation[filtered.size()]); + } + +} diff --git a/ui/databinding/generator/dependency-reduced-pom.xml b/ui/databinding/generator/dependency-reduced-pom.xml new file mode 100644 index 00000000..d3778587 --- /dev/null +++ b/ui/databinding/generator/dependency-reduced-pom.xml @@ -0,0 +1,56 @@ + + + + databinding-parent + io.crysknife + 0.3-SNAPSHOT + + 4.0.0 + databinding-generator + databinding generator + + + treblereel + Dmitrii Tikhomirov + chani.liet@gmail.com + + + + + Apache License Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo + + + + Treblereel + https://github.com/treblereel + + + + + maven-shade-plugin + + + package + + shade + + + true + + + *:*:*:* + + **/*.java + **/*.js + + + + + + + + + + diff --git a/ui/databinding/generator/pom.xml b/ui/databinding/generator/pom.xml index 462d79bf..d46d994d 100644 --- a/ui/databinding/generator/pom.xml +++ b/ui/databinding/generator/pom.xml @@ -5,7 +5,7 @@ io.crysknife databinding-parent - 0.1-SNAPSHOT + 0.3-SNAPSHOT databinding-generator @@ -46,7 +46,6 @@ io.crysknife crysknife-processor ${project.version} - compile io.crysknife @@ -59,14 +58,25 @@ org.apache.maven.plugins - maven-source-plugin + maven-shade-plugin - attach-sources package - jar + shade + + true + + + *:*:*:* + + **/*.java + **/*.js + + + + diff --git a/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/AutoBoundGenerator.java b/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/AutoBoundGenerator.java new file mode 100644 index 00000000..6934ee4a --- /dev/null +++ b/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/AutoBoundGenerator.java @@ -0,0 +1,210 @@ +/* + * Copyright © 2021 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.databinding.generator; + +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.ast.expr.NullLiteralExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.ast.expr.StringLiteralExpr; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.google.auto.common.MoreTypes; +import io.crysknife.annotation.Generator; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.exception.GenerationException; +import io.crysknife.generator.IOCGenerator; +import io.crysknife.generator.WiringElementType; +import io.crysknife.generator.api.ClassBuilder; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.ui.databinding.client.api.AutoBound; +import io.crysknife.ui.databinding.client.api.Bound; +import io.crysknife.ui.databinding.client.api.Convert; +import io.crysknife.ui.databinding.client.api.DataBinder; +import io.crysknife.ui.databinding.client.api.handler.list.BindableListChangeHandler; +import io.crysknife.util.Utils; +import jsinterop.base.Js; +import org.gwtproject.user.client.TakesValue; + +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 9/1/21 + */ +@Generator(priority = 100003) +public class AutoBoundGenerator extends IOCGenerator { + + public AutoBoundGenerator(IOCContext iocContext) { + super(iocContext); + } + + /** + * @param bindableType The root type the given property chain is resolved against. Not null. + * @param propertyChain The data binding property chain to validate. Not null. + * @return The type of the given property within the given bindable type. + */ + public static TypeMirror getPropertyType(final TypeMirror bindableType, + final String propertyChain) { + if ("this".equals(propertyChain)) { + return bindableType; + } + final int dotPos = propertyChain.indexOf('.'); + if (dotPos >= 0) { + final String firstProp = propertyChain.substring(0, dotPos); + final String subChain = propertyChain.substring(dotPos + 1); + return getPropertyType(getMethod(bindableType, firstProp).asType(), subChain); + } else { + return getMethod(bindableType, propertyChain).asType(); + } + } + + private static VariableElement getMethod(TypeMirror element, String name) { + return ElementFilter.fieldsIn(MoreTypes.asElement(element).getEnclosedElements()).stream() + .filter(variableElement -> variableElement.getSimpleName().toString().equals(name)) + .findFirst().orElseThrow((Supplier) () -> { + throw new RuntimeException("Cannot process bindable " + element); + }); + } + + @Override + public void register() { + iocContext.register(AutoBound.class, WiringElementType.FIELD_DECORATOR, this); // PARAMETER + } + + public void generate(ClassBuilder classBuilder, InjectableVariableDefinition field) { + Set autoBound = ElementFilter + .fieldsIn(MoreTypes.asElement(field.getVariableElement().getEnclosingElement().asType()) + .getEnclosedElements()) + .stream().filter(elm -> elm.getAnnotation(AutoBound.class) != null) + .collect(Collectors.toSet()); + + Set bounds = ElementFilter + .fieldsIn(MoreTypes.asElement(field.getVariableElement().getEnclosingElement().asType()) + .getEnclosedElements()) + .stream().filter(elm -> elm.getAnnotation(Bound.class) != null).collect(Collectors.toSet()); + + if (autoBound.size() > 1) { + throw new GenerationException( + "only one elemental annotated with @AutoBound must be presented at " + + field.getBeanDefinition().getQualifiedName()); + } + + // bounds + classBuilder.getInitInstanceMethod().getBody().ifPresent( + body -> autoBound.stream().forEach(dataBinderVariableElement -> bounds.forEach(bound -> { + Expression fieldAccessExpr = generationUtils + .getFieldAccessCallExpr(field.getBeanDefinition(), dataBinderVariableElement); + MethodCallExpr call = + new MethodCallExpr(new NameExpr(Js.class.getCanonicalName()), "uncheckedCast") + .addArgument(fieldAccessExpr); + call.setTypeArguments( + new ClassOrInterfaceType().setName(DataBinder.class.getCanonicalName())); + MethodCallExpr bind = new MethodCallExpr(call, "bind"); + String boundName = bound.getAnnotation(Bound.class).property().equals("") + ? bound.getSimpleName().toString() + : bound.getAnnotation(Bound.class).property(); + + boolean onKeyUp = bound.getAnnotation(Bound.class).onKeyUp(); + + TypeMirror hasValues = iocContext.getTypeMirror(TakesValue.class); + TypeMirror check = iocContext.getGenerationContext().getTypes().erasure(bound.asType()); + TypeMirror genericType = + MoreTypes.asDeclared(dataBinderVariableElement.asType()).getTypeArguments().get(0); + + if (iocContext.getGenerationContext().getTypes().isAssignable(check, hasValues)) { + long count = Utils + .getAllMethodsIn(iocContext.getGenerationContext().getElements(), + MoreTypes.asTypeElement(bound.asType())) + .stream().filter(method -> method.getSimpleName().toString().equals("getValue")) + .map(e -> iocContext.getGenerationContext().getTypes() + .asMemberOf(MoreTypes.asDeclared(bound.asType()), e)) + .map(e -> (ExecutableType) e).count(); + if (count == 1) { + boundName = "this"; + } + } + + bind.addArgument( + generationUtils.getFieldAccessCallExpr(field.getBeanDefinition(), bound)); + bind.addArgument(new StringLiteralExpr(boundName)); + bind.addArgument(coverterStatement(bound.getAnnotation(Bound.class), bound.asType(), + getPropertyType(genericType, boundName))); + bind.addArgument(new NullLiteralExpr()); + bind.addArgument(new NameExpr(onKeyUp + "")); + body.addAndGetStatement(bind); + }))); + } + + private Expression coverterStatement(final Bound bound, final TypeMirror boundType, + final TypeMirror propertyType) { + TypeMirror converter = null; + try { + Class temp = bound.converter(); + } catch (javax.lang.model.type.MirroredTypeException e) { + converter = e.getTypeMirror(); + } + + TypeMirror NO_CONVERTER = iocContext.getGenerationContext().getElements() + .getTypeElement(Bound.NO_CONVERTER.class.getCanonicalName()).asType(); + if (iocContext.getGenerationContext().getTypes().isSameType(converter, NO_CONVERTER)) { + final Optional valueType; + TypeMirror boundTypeErased = iocContext.getGenerationContext().getTypes().erasure(boundType); + TypeMirror takesValue = iocContext.getGenerationContext().getElements() + .getTypeElement(TakesValue.class.getCanonicalName()).asType(); + + TypeMirror bindableListChangeHandler = iocContext.getGenerationContext().getElements() + .getTypeElement(BindableListChangeHandler.class.getCanonicalName()).asType(); + + iocContext.getGenerationContext().getTypes().isAssignable(boundTypeErased, takesValue); + + if (iocContext.getGenerationContext().getTypes().isAssignable(boundTypeErased, + iocContext.getGenerationContext().getTypes().erasure(takesValue))) { + valueType = Utils + .getAllMethodsIn(iocContext.getGenerationContext().getElements(), + MoreTypes.asTypeElement(boundType)) + .stream().filter(method -> method.getSimpleName().toString().equals("getValue")) + .filter(method -> method.getParameters().isEmpty()) + .map(e -> iocContext.getGenerationContext().getTypes() + .asMemberOf(MoreTypes.asDeclared(boundType), e)) + .map(method -> ((ExecutableType) method)).map(method -> method.getReturnType()) + .findFirst(); + } else if (iocContext.getGenerationContext().getTypes().isAssignable(boundTypeErased, + bindableListChangeHandler)) { + valueType = Optional.ofNullable(bindableListChangeHandler); + } else { + valueType = Optional.empty(); + } + + return valueType.map(type -> (Expression) new MethodCallExpr( + new NameExpr(Convert.class.getCanonicalName()), "getConverter") + .addArgument(new NameExpr( + iocContext.getGenerationContext().getTypes().erasure(propertyType).toString() + + ".class")) + .addArgument( + new NameExpr(iocContext.getGenerationContext().getTypes().erasure(type).toString() + + ".class"))) + .orElse(new NullLiteralExpr()); + } else { + return new ObjectCreationExpr().setType(bound.converter()); + } + } +} diff --git a/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/BindableGenerator.java b/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/BindableGenerator.java index e7eb3742..8d15c718 100644 --- a/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/BindableGenerator.java +++ b/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/BindableGenerator.java @@ -14,13 +14,6 @@ package io.crysknife.ui.databinding.generator; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.inject.Inject; -import javax.lang.model.element.TypeElement; - import com.github.javaparser.ast.Modifier; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.expr.AssignExpr; @@ -31,11 +24,21 @@ import com.github.javaparser.ast.expr.NullLiteralExpr; import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.stmt.IfStmt; import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.google.auto.common.MoreTypes; import io.crysknife.annotation.Generator; +import io.crysknife.client.BeanManager; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.exception.GenerationException; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.generator.ScopedBeanGenerator; +import io.crysknife.generator.WiringElementType; +import io.crysknife.generator.api.ClassBuilder; +import io.crysknife.generator.context.IOCContext; import io.crysknife.ui.databinding.client.BindableProxy; import io.crysknife.ui.databinding.client.BindableProxyAgent; import io.crysknife.ui.databinding.client.BindableProxyFactory; @@ -43,14 +46,22 @@ import io.crysknife.ui.databinding.client.NonExistingPropertyException; import io.crysknife.ui.databinding.client.PropertyType; import io.crysknife.ui.databinding.client.api.Bindable; +import io.crysknife.ui.databinding.client.api.Convert; +import io.crysknife.ui.databinding.client.api.Converter; import io.crysknife.ui.databinding.client.api.DataBinder; -import io.crysknife.generator.ScopedBeanGenerator; -import io.crysknife.generator.WiringElementType; -import io.crysknife.generator.api.ClassBuilder; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.point.FieldPoint; +import io.crysknife.ui.databinding.client.api.DefaultConverter; +import io.crysknife.util.Utils; + +import javax.inject.Inject; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; /** * @author Dmitrii Tikhomirov Created by treblereel 4/7/19 @@ -64,47 +75,108 @@ public BindableGenerator(IOCContext iocContext) { @Override public void register() { - // iocContext.register(Bindable.class, WiringElementType.CLASS_DECORATOR, this); //PARAMETER iocContext.register(Inject.class, DataBinder.class, WiringElementType.BEAN, this); // PARAMETER - TypeElement type = iocContext.getGenerationContext().getElements() - .getTypeElement(DataBinder.class.getCanonicalName()); - BeanDefinition beanDefinition = iocContext.getBeanDefinitionOrCreateAndReturn(type); - beanDefinition.setGenerator(this); - iocContext.getBlacklist().add(DataBinder.class.getCanonicalName()); } @Override - public void generateBeanFactory(ClassBuilder clazz, Definition definition) { - if (definition instanceof BeanDefinition) { - clazz.getClassCompilationUnit().addImport(((BeanDefinition) definition).getType().toString()); - - clazz.getClassCompilationUnit().addImport(DataBinder.class); - clazz.getClassCompilationUnit().addImport(Collections.class); - clazz.getClassCompilationUnit().addImport(HashMap.class); - clazz.getClassCompilationUnit().addImport(Map.class); - clazz.getClassCompilationUnit().addImport(PropertyType.class); - clazz.getClassCompilationUnit().addImport(NonExistingPropertyException.class); - clazz.getClassCompilationUnit().addImport(BindableProxyAgent.class); - clazz.getClassCompilationUnit().addImport(BindableProxy.class); - clazz.getClassCompilationUnit().addImport(BindableProxyProvider.class); - clazz.getClassCompilationUnit().addImport(BindableProxyFactory.class); - - BeanDefinition beanDefinition = (BeanDefinition) definition; - initClassBuilder(clazz, beanDefinition); - clazz.getImplementedTypes().clear(); - - MethodDeclaration methodDeclaration = - clazz.addMethod("loadBindableProxies", Modifier.Keyword.PRIVATE); - - iocContext.getTypeElementsByAnnotation(Bindable.class.getCanonicalName()).forEach(c -> { - clazz.getClassCompilationUnit().addImport(c.toString()); - generateBindableProxy(methodDeclaration, MoreTypes.asTypeElement(c.asType())); - }); + public Expression generateBeanLookupCall(ClassBuilder classBuilder, + InjectableVariableDefinition fieldPoint) { + classBuilder.getClassCompilationUnit().addImport(DataBinder.class); + return generationUtils.wrapCallInstanceImpl(classBuilder, new MethodCallExpr( + new MethodCallExpr( + new NameExpr("io.crysknife.ui.databinding.client.api.DataBinder_Factory"), "get"), + "forType") + .addArgument(new NameExpr(iocContext + .getGenerationContext().getTypes().erasure(MoreTypes + .asDeclared(fieldPoint.getVariableElement().asType()).getTypeArguments().get(0)) + + ".class"))); + } - generateFactoryCreateMethod(clazz, beanDefinition); - generateFactoryForTypeMethod(clazz, beanDefinition); - write(clazz, beanDefinition, iocContext.getGenerationContext()); + @Override + public void generate(ClassBuilder clazz, BeanDefinition beanDefinition) + throws GenerationException { + clazz.getClassCompilationUnit().addImport((beanDefinition).getType().toString()); + + clazz.getClassCompilationUnit().addImport(DataBinder.class); + clazz.getClassCompilationUnit().addImport(Collections.class); + clazz.getClassCompilationUnit().addImport(HashMap.class); + clazz.getClassCompilationUnit().addImport(Map.class); + clazz.getClassCompilationUnit().addImport(PropertyType.class); + clazz.getClassCompilationUnit().addImport(NonExistingPropertyException.class); + clazz.getClassCompilationUnit().addImport(BindableProxyAgent.class); + clazz.getClassCompilationUnit().addImport(BindableProxy.class); + clazz.getClassCompilationUnit().addImport(BindableProxyProvider.class); + clazz.getClassCompilationUnit().addImport(BindableProxyFactory.class); + + initClassBuilder(clazz, beanDefinition); + clazz.getImplementedTypes().clear(); + + MethodDeclaration methodDeclaration = + clazz.addMethod("loadBindableProxies", Modifier.Keyword.PRIVATE); + + Set errors = new HashSet<>(); + + iocContext.getTypeElementsByAnnotation(Bindable.class.getCanonicalName()).forEach(c -> { + clazz.getClassCompilationUnit().addImport(c.toString()); + try { + generateBindableProxy(methodDeclaration, MoreTypes.asTypeElement(c.asType())); + } catch (UnableToCompleteException e) { + errors.add(e); + } + }); + + if (!errors.isEmpty()) { + printErrors(errors); + throw new GenerationException(getClass().getCanonicalName() + ".generate"); } + + maybeAddDefaultConverters(clazz, methodDeclaration); + generateFactoryCreateMethod(clazz, beanDefinition); + generateFactoryForTypeMethod(clazz, beanDefinition); + // TODO + clazz.addConstructorDeclaration() + .addParameter(new ClassOrInterfaceType().setName(BeanManager.class.getCanonicalName()), + "beanManager") + .getBody().addAndGetStatement(new MethodCallExpr("super").addArgument("beanManager")); + + MethodDeclaration getMethodDeclaration = + clazz.addMethod("getInstance", Modifier.Keyword.PUBLIC); + + getMethodDeclaration.addAnnotation(Override.class); + getMethodDeclaration.setType(Utils.getSimpleClassName(clazz.beanDefinition.getType())); + getMethodDeclaration.getBody().get().addAndGetStatement(new ReturnStmt(new NullLiteralExpr())); + + write(clazz, beanDefinition, iocContext.getGenerationContext()); + } + + private void maybeAddDefaultConverters(ClassBuilder clazz, MethodDeclaration methodDeclaration) { + TypeMirror converter = + iocContext.getGenerationContext().getTypes().erasure(iocContext.getGenerationContext() + .getElements().getTypeElement(Converter.class.getCanonicalName()).asType()); + + iocContext.getTypeElementsByAnnotation(DefaultConverter.class.getCanonicalName()).stream() + .filter(type -> iocContext.getGenerationContext().getTypes().isAssignable(type.asType(), + converter)) + .collect(Collectors.toSet()).forEach(con -> { + con.getInterfaces().forEach(i -> { + if (iocContext.getGenerationContext().getTypes().isSameType(converter, + iocContext.getGenerationContext().getTypes().erasure(i))) { + methodDeclaration.getBody().ifPresent(body -> { + body.addAndGetStatement(new ExpressionStmt( + new MethodCallExpr(new NameExpr(Convert.class.getCanonicalName()), + "registerDefaultConverter") + .addArgument(new NameExpr( + MoreTypes.asDeclared(i).getTypeArguments().get(0).toString() + + ".class")) + .addArgument(new NameExpr( + MoreTypes.asDeclared(i).getTypeArguments().get(1).toString() + + ".class")) + .addArgument(new ObjectCreationExpr() + .setType(con.getQualifiedName().toString())))); + }); + } + }); + }); } public void generateFactoryCreateMethod(ClassBuilder classBuilder, @@ -119,6 +191,7 @@ public void generateFactoryCreateMethod(ClassBuilder classBuilder, new NullLiteralExpr(), BinaryExpr.Operator.EQUALS)); ObjectCreationExpr newInstance = new ObjectCreationExpr(); newInstance.setType(new ClassOrInterfaceType().setName("DataBinder_Factory")); + newInstance.addArgument(new NullLiteralExpr()); BlockStmt initialization = new BlockStmt(); initialization.addAndGetStatement( @@ -143,19 +216,25 @@ public void generateFactoryForTypeMethod(ClassBuilder classBuilder, new MethodCallExpr(new NameExpr("DataBinder"), "forType").addArgument("modelType"))); } - private void generateBindableProxy(MethodDeclaration methodDeclaration, TypeElement type) { + private void generateBindableProxy(MethodDeclaration methodDeclaration, TypeElement type) + throws UnableToCompleteException { new BindableProxyGenerator( + iocContext.getGenerationContext().getProcessingEnvironment().getElementUtils(), iocContext.getGenerationContext().getProcessingEnvironment().getTypeUtils(), methodDeclaration, type).generate(); } - @Override - public Expression generateBeanCall(ClassBuilder classBuilder, FieldPoint fieldPoint, - BeanDefinition beanDefinition) { - classBuilder.getClassCompilationUnit().addImport(DataBinder.class); - MoreTypes.asDeclared(fieldPoint.getField().asType()).getTypeArguments(); - return new NameExpr("io.crysknife.databinding.client.api.DataBinder_Factory.get().forType(" - + MoreTypes.asDeclared(fieldPoint.getField().asType()).getTypeArguments().get(0) - + ".class)"); + private void printErrors(Set errors) { + + errors.forEach(error -> { + if (error.errors != null) { + printErrors(error.errors); + } else if (error.getMessage() != null) { + System.out.println("Error: " + error.getMessage()); + iocContext.getGenerationContext().getProcessingEnvironment().getMessager() + .printMessage(Diagnostic.Kind.ERROR, error.getMessage()); + } + }); } + } diff --git a/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/BindableProxyGenerator.java b/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/BindableProxyGenerator.java index c4ef2e5c..94134f56 100644 --- a/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/BindableProxyGenerator.java +++ b/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/BindableProxyGenerator.java @@ -14,18 +14,28 @@ package io.crysknife.ui.databinding.generator; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.google.auto.common.MoreElements; +import com.google.auto.common.MoreTypes; +import io.crysknife.exception.GenerationException; +import io.crysknife.exception.UnableToCompleteException; +import io.crysknife.ui.databinding.client.api.Bindable; +import io.crysknife.util.Utils; +import org.apache.commons.lang3.StringUtils; + import javax.lang.model.element.ElementKind; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; import javax.lang.model.util.Types; - -import com.github.javaparser.ast.body.MethodDeclaration; -import com.google.auto.common.MoreTypes; -import org.apache.commons.lang3.StringUtils; -import io.crysknife.ui.databinding.client.api.Bindable; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; /** * @author Dmitrii Tikhomirov Created by treblereel 11/21/19 @@ -36,18 +46,37 @@ public class BindableProxyGenerator { private TypeElement type; private String newLine = System.lineSeparator(); private Types types; + private Elements elements; + + private final TypeMirror listTypeMirror; + private final TypeMirror objectTypeMirror; + private final Set errors = new HashSet<>(); - BindableProxyGenerator(Types types, MethodDeclaration methodDeclaration, TypeElement type) { + + BindableProxyGenerator(Elements elements, Types types, MethodDeclaration methodDeclaration, + TypeElement type) { this.methodDeclaration = methodDeclaration; this.type = type; this.types = types; + this.elements = elements; + + listTypeMirror = elements.getTypeElement(List.class.getCanonicalName()).asType(); + objectTypeMirror = elements.getTypeElement(Object.class.getCanonicalName()).asType(); + + errors.clear(); } - void generate() { + void generate() throws UnableToCompleteException { String clazzName = type.getQualifiedName().toString().replaceAll("\\.", "_") + "Proxy"; StringBuffer sb = new StringBuffer(); + Set fields = + Utils.getAllFieldsIn(elements, type).stream().filter(elm -> elm.getKind().isField()) + .filter(e -> !e.getModifiers().contains(Modifier.FINAL)) + .filter(e -> !e.getModifiers().contains(Modifier.STATIC)) + .map(e -> MoreElements.asVariable(e)).collect(Collectors.toSet()); + sb.append(String.format("class %s extends %s implements BindableProxy { ", clazzName, type.getSimpleName())); sb.append(newLine); @@ -77,6 +106,8 @@ void generate() { sb.append(String.format(" p.put(\"this\", new PropertyType(%s.class, true, false));", type.getSimpleName())); + + sb.append(newLine); sb.append(" agent.copyValues();"); sb.append(newLine); @@ -84,39 +115,45 @@ void generate() { sb.append("}"); sb.append(newLine); + sb.append(newLine); sb.append("public BindableProxyAgent getBindableProxyAgent() {"); sb.append(newLine); sb.append(" return agent;"); sb.append(newLine); sb.append("}"); + sb.append(newLine); sb.append("public void updateWidgets() {"); sb.append(newLine); sb.append(" agent.updateWidgetsAndFireEvents();"); sb.append(newLine); sb.append("}"); + sb.append(newLine); sb.append(String.format("public %s unwrap() {", type.getSimpleName())); sb.append(newLine); sb.append(" return target;"); sb.append(newLine); sb.append("}"); - deepUnwrap(sb); + deepUnwrap(fields, sb); equals(clazzName, sb); + sb.append(newLine); sb.append("public int hashCode() {"); sb.append(newLine); sb.append(" return target.hashCode();"); sb.append(newLine); sb.append("}"); + sb.append(newLine); sb.append("public String toString() {"); sb.append(newLine); sb.append(" return target.toString();"); sb.append(newLine); sb.append("}"); + sb.append(newLine); sb.append("private void changeAndFire(String property, Object value) {"); sb.append(newLine); sb.append(" final Object oldValue = get(property);"); @@ -127,9 +164,9 @@ void generate() { sb.append(newLine); sb.append("}"); - getterAndSetter(sb); - get(sb); - set(sb); + getterAndSetter(type, fields, sb); + get(fields, sb); + set(type, fields, sb); getBeanProperties(sb); sb.append("}"); @@ -138,6 +175,10 @@ void generate() { addBindableProxy(clazzName, sb); methodDeclaration.getBody().get().addAndGetStatement(sb.toString()); + + if (!errors.isEmpty()) { + throw new UnableToCompleteException(errors); + } } private void addBindableProxy(String clazzName, StringBuffer sb) { @@ -158,7 +199,7 @@ private void addBindableProxy(String clazzName, StringBuffer sb) { sb.append(newLine); sb.append(" }"); sb.append(newLine); - sb.append("});"); + sb.append("})"); sb.append(newLine); } @@ -175,16 +216,20 @@ private void getBeanProperties(StringBuffer sb) { sb.append(newLine); } - private void set(StringBuffer sb) { + private void set(TypeElement type, Set fields, StringBuffer sb) { sb.append("public void set(String property, Object value) {"); sb.append(newLine); sb.append(" switch (property) {"); sb.append(newLine); - type.getEnclosedElements().stream().filter(elm -> elm.getKind().isField()).forEach(f -> { - VariableElement elm = (VariableElement) f; - sb.append(String.format("case \"%s\": target.%s((%s) value);", f.getSimpleName().toString(), - getSetter(elm), getFieldType(f.asType()))); + fields.forEach(elm -> { + + try { + sb.append(String.format("case \"%s\": target.%s((%s) value);", + elm.getSimpleName().toString(), getSetter(elm), getFieldType(getType(type, elm)))); + } catch (UnableToCompleteException e) { + errors.add(e); + } sb.append(newLine); sb.append("break;"); sb.append(newLine); @@ -206,22 +251,31 @@ private void set(StringBuffer sb) { } private String getFieldType(TypeMirror mirror) { + TypeMirror collection = elements.getTypeElement(Collection.class.getCanonicalName()).asType(); + + if (types.isSubtype(mirror, collection)) { + return types.erasure(mirror).toString(); + } if (mirror.getKind().isPrimitive()) { return types.boxedClass(MoreTypes.asPrimitiveType(mirror)).toString(); } - return mirror.toString(); + return types.erasure(mirror).toString(); } - private void get(StringBuffer sb) { + private void get(Set fields, StringBuffer sb) { + sb.append(newLine); sb.append("public Object get(String property) {"); sb.append(newLine); sb.append(" switch (property) {"); sb.append(newLine); - type.getEnclosedElements().stream().filter(elm -> elm.getKind().isField()).forEach(f -> { - VariableElement elm = (VariableElement) f; - sb.append( - String.format("case \"%s\": return %s();", f.getSimpleName().toString(), getGetter(elm))); + fields.forEach(elm -> { + try { + sb.append(String.format("case \"%s\": return %s();", elm.getSimpleName().toString(), + getGetter(elm))); + } catch (UnableToCompleteException e) { + errors.add(e); + } sb.append(newLine); }); @@ -236,28 +290,49 @@ private void get(StringBuffer sb) { sb.append(newLine); } - private void getterAndSetter(StringBuffer sb) { - type.getEnclosedElements().stream().filter(elm -> elm.getKind().isField()).forEach(f -> { - VariableElement elm = (VariableElement) f; - sb.append(String.format("public %s %s() {", f.asType(), getGetter(elm))); - sb.append(newLine); - sb.append(String.format(" return target.%s();", getGetter(elm))); - sb.append(newLine); - sb.append("}"); - sb.append(newLine); - - sb.append(String.format("public void %s(%s %s) {", getGetter(elm), f.asType(), - f.getSimpleName().toString())); - sb.append(newLine); - sb.append(String.format(" changeAndFire(\"%s\", %s);", f.getSimpleName().toString(), - f.getSimpleName().toString())); - sb.append(newLine); - sb.append("}"); - sb.append(newLine); + private void getterAndSetter(TypeElement type, Set fields, StringBuffer sb) { + fields.forEach(elm -> { + try { + getterAndSetter(type, elm, sb); + } catch (UnableToCompleteException e) { + errors.add(e); + } }); } + private void getterAndSetter(TypeElement type, VariableElement elm, StringBuffer sb) + throws UnableToCompleteException { + sb.append(newLine); + sb.append(String.format("public %s %s() {", getType(type, elm), getGetter(elm))); + sb.append(newLine); + sb.append(String.format(" return target.%s();", getGetter(elm))); + sb.append(newLine); + sb.append("}"); + sb.append(newLine); + + sb.append(newLine); + sb.append(String.format("public void %s(%s value) {", getSetter(elm), getType(type, elm))); + sb.append(newLine); + sb.append(String.format(" changeAndFire(\"%s\", value);", elm.getSimpleName().toString())); + sb.append(newLine); + sb.append("}"); + sb.append(newLine); + } + + + private TypeMirror getType(TypeElement parent, VariableElement elm) { + if (elm.asType().getKind().equals(TypeKind.TYPEVAR)) { + TypeMirror typeMirror = types.asMemberOf(MoreTypes.asDeclared(parent.asType()), elm); + if (typeMirror.getKind().equals(TypeKind.TYPEVAR)) { + return objectTypeMirror; + } + return typeMirror; + } + return elm.asType(); + } + private void equals(String clazzName, StringBuffer sb) { + sb.append(newLine); sb.append("public boolean equals(Object obj) {"); sb.append(newLine); sb.append(String.format(" if (obj instanceof %s) {", clazzName)); @@ -271,7 +346,8 @@ private void equals(String clazzName, StringBuffer sb) { sb.append("}"); } - private void deepUnwrap(StringBuffer sb) { + private void deepUnwrap(Set fields, StringBuffer sb) { + sb.append(newLine); sb.append(String.format("public %s deepUnwrap() {", type.getSimpleName())); sb.append(newLine); sb.append( @@ -280,33 +356,13 @@ private void deepUnwrap(StringBuffer sb) { sb.append(String.format(" final %s t = unwrap();", type.getSimpleName())); sb.append(newLine); - type.getEnclosedElements().stream().filter(elm -> elm.getKind().isField()).forEach(f -> { - - VariableElement elm = (VariableElement) f; - if (!isBindableType(elm)) { - sb.append(" "); - sb.append(String.format("clone.%s(t.%s());", getSetter(elm), getGetter(elm))); - sb.append(newLine); - } else { - sb.append(String.format("if (t.%s() instanceof BindableProxy) {", getGetter(elm), - type.getSimpleName())); - sb.append(newLine); - sb.append(String.format(" clone.%s((%s) ((BindableProxy) %s()).deepUnwrap());", - getSetter(elm), f.asType(), getGetter(elm))); - sb.append(newLine); - sb.append(String.format("} else if (BindableProxyFactory.isBindableType(t.%s())) {", - getGetter(elm))); - sb.append(newLine); - sb.append(String.format( - " clone.%s((%s) ((BindableProxy) BindableProxyFactory.getBindableProxy(t.%s())).deepUnwrap());", - getSetter(elm), f.asType(), getGetter(elm))); - sb.append(newLine); - sb.append("} else {"); - sb.append(newLine); - sb.append(String.format(" clone.%s(t.%s());", getSetter(elm), getGetter(elm))); - sb.append(newLine); - sb.append("}"); - sb.append(newLine); + Set errors = new HashSet<>(); + + fields.forEach(elm -> { + try { + deepUnwrap(elm, sb); + } catch (UnableToCompleteException e) { + errors.add(e); } }); @@ -314,21 +370,60 @@ private void deepUnwrap(StringBuffer sb) { sb.append(newLine); sb.append("}"); sb.append(newLine); + + } + + private void deepUnwrap(VariableElement elm, StringBuffer sb) throws UnableToCompleteException { + if (!isBindableType(elm)) { + sb.append(" "); + sb.append(String.format("clone.%s(t.%s());", getSetter(elm), getGetter(elm))); + sb.append(newLine); + } else { + sb.append(String.format("if (t.%s() instanceof BindableProxy) {", getGetter(elm), + type.getSimpleName())); + sb.append(newLine); + sb.append(String.format(" clone.%s((%s) ((BindableProxy) %s()).deepUnwrap());", + getSetter(elm), elm.asType(), getGetter(elm))); + sb.append(newLine); + sb.append(String.format("} else if (BindableProxyFactory.isBindableType(t.%s())) {", + getGetter(elm))); + sb.append(newLine); + sb.append(String.format( + " clone.%s((%s) ((BindableProxy) BindableProxyFactory.getBindableProxy(t.%s())).deepUnwrap());", + getSetter(elm), elm.asType(), getGetter(elm))); + sb.append(newLine); + sb.append("} else {"); + sb.append(newLine); + sb.append(String.format(" clone.%s(t.%s());", getSetter(elm), getGetter(elm))); + sb.append(newLine); + sb.append("}"); + sb.append(newLine); + } + + + } private boolean isBindableType(VariableElement elm) { if (elm.asType().getKind().isPrimitive()) { return false; } - return MoreTypes.asTypeElement(elm.asType()).getAnnotation(Bindable.class) != null; + + if (elm.asType().getKind().equals(TypeKind.ARRAY)) { + return false; + } + + return MoreTypes.asElement(elm.asType()).getAnnotation(Bindable.class) != null; } - private String getGetter(VariableElement variable) { + private String getGetter(VariableElement variable) throws UnableToCompleteException { String method = compileGetterMethodName(variable); - return type.getEnclosedElements().stream().filter(e -> e.getKind().equals(ElementKind.METHOD)) + return Utils.getAllMethodsIn(elements, type).stream() + .filter(e -> e.getKind().equals(ElementKind.METHOD)) .filter(e -> e.toString().equals(method)) .filter(e -> e.getModifiers().contains(Modifier.PUBLIC)).findFirst() - .map(e -> e.getSimpleName().toString()).orElseThrow(() -> new Error(String + .map(e -> e.getSimpleName().toString()) + .orElseThrow(() -> new UnableToCompleteException(String .format("Unable to find getter [%s] in [%s]", method, variable.getEnclosingElement()))); } @@ -338,6 +433,9 @@ private String compileGetterMethodName(VariableElement variable) { } private String compileSetterMethodName(VariableElement variable) { + + MoreElements.asType(variable.getEnclosingElement()).getTypeParameters(); + String varName = variable.getSimpleName().toString(); StringBuffer sb = new StringBuffer(); sb.append("set"); @@ -348,27 +446,31 @@ private String compileSetterMethodName(VariableElement variable) { return sb.toString(); } - private String getSetter(VariableElement variable) { + private String getSetter(VariableElement variable) throws UnableToCompleteException { String method = compileSetterMethodName(variable); - return type.getEnclosedElements().stream().filter(e -> e.getKind().equals(ElementKind.METHOD)) + return Utils.getAllMethodsIn(elements, type).stream() + .filter(e -> e.getKind().equals(ElementKind.METHOD)) .filter(e -> e.toString().equals(method)) .filter(e -> e.getModifiers().contains(Modifier.PUBLIC)).findFirst() - .map(e -> e.getSimpleName().toString()).orElseThrow(() -> new Error(String + .map(e -> e.getSimpleName().toString()) + .orElseThrow(() -> new UnableToCompleteException(String .format("Unable to find setter [%s] in [%s]", method, variable.getEnclosingElement()))); } private boolean isBoolean(VariableElement variable) { - return variable.getKind().equals(TypeKind.BOOLEAN); + return variable.asType().getKind().equals(TypeKind.BOOLEAN) + || variable.asType().toString().equals(Boolean.class.getCanonicalName()); } private void generatePropertyType(StringBuffer sb, TypeElement type) { - type.getEnclosedElements().stream().filter(elm -> elm.getKind().isField()) - .forEach(field -> generatePropertyType(sb, ((VariableElement) field))); + Utils.getAllFieldsIn(elements, type).stream() + .forEach(field -> generatePropertyType(type, sb, field)); } - private void generatePropertyType(StringBuffer sb, VariableElement field) { - sb.append(String.format(" p.put(\"%s\", new PropertyType(%s.class, %s, false));", - field.getSimpleName(), getFieldType(field.asType()), isBindableType(field))); + private void generatePropertyType(TypeElement type, StringBuffer sb, VariableElement field) { + boolean isList = types.isSubtype(listTypeMirror, types.erasure(field.asType())); + sb.append(String.format(" p.put(\"%s\", new PropertyType(%s.class, %s, %b));", + field.getSimpleName(), getFieldType(getType(type, field)), isBindableType(field), isList)); sb.append(newLine); } } diff --git a/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/ListComponentGenerator.java b/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/ListComponentGenerator.java new file mode 100644 index 00000000..fbb8a8ad --- /dev/null +++ b/ui/databinding/generator/src/main/java/io/crysknife/ui/databinding/generator/ListComponentGenerator.java @@ -0,0 +1,154 @@ +/* + * Copyright © 2021 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.databinding.generator; + +import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.BodyDeclaration; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.expr.ArrayCreationExpr; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.FieldAccessExpr; +import com.github.javaparser.ast.expr.LambdaExpr; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.ast.expr.StringLiteralExpr; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.github.javaparser.ast.stmt.ReturnStmt; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.google.auto.common.MoreTypes; +import io.crysknife.annotation.Generator; +import io.crysknife.client.internal.InstanceImpl; +import io.crysknife.definition.Definition; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.generator.BeanIOCGenerator; +import io.crysknife.generator.WiringElementType; +import io.crysknife.generator.api.ClassBuilder; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.ui.databinding.client.components.DefaultListComponent; +import io.crysknife.ui.databinding.client.components.ListComponent; +import io.crysknife.ui.databinding.client.components.ListComponentProvider; +import io.crysknife.ui.databinding.client.components.ListContainer; + +import javax.enterprise.inject.Default; +import javax.inject.Inject; +import javax.inject.Named; +import java.lang.annotation.Annotation; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 8/27/21 + */ +@Generator(priority = 100000) +public class ListComponentGenerator extends BeanIOCGenerator { + + public ListComponentGenerator(IOCContext iocContext) { + super(iocContext); + } + + @Override + public void register() { + iocContext.register(Inject.class, ListComponent.class, WiringElementType.FIELD_TYPE, this); + } + + @Override + public void generate(ClassBuilder clazz, Definition beanDefinition) { + + } + + @Override + public Expression generateBeanLookupCall(ClassBuilder classBuilder, + InjectableVariableDefinition fieldPoint) { + classBuilder.getClassCompilationUnit().addImport(DefaultListComponent.class); + classBuilder.getClassCompilationUnit().addImport(ListComponentProvider.class); + + ArrayCreationExpr types = new ArrayCreationExpr().setElementType("Class[]"); + types.getInitializer().ifPresent(init -> { + MoreTypes.asDeclared(fieldPoint.getVariableElement().asType()).getTypeArguments() + .forEach(typeArguments -> { + init.getValues() + .add(new FieldAccessExpr(new NameExpr(typeArguments.toString()), "class")); + }); + }); + + ArrayCreationExpr annotations = + new ArrayCreationExpr().setElementType("java.lang.annotation.Annotation[]"); + + annotations.getInitializer().ifPresent(init -> { + init.getValues().add(addDefaultAnnotation()); + maybeAddListContainerAnnotation(init.getValues(), fieldPoint); + }); + + + MethodCallExpr instance = new MethodCallExpr(new ObjectCreationExpr() + .setType(ListComponentProvider.class).addArgument(new NameExpr("beanManager")), "provide") + .addArgument(types).addArgument(annotations); + return new ObjectCreationExpr().setType(InstanceImpl.class).addArgument(instance); + } + + private void maybeAddListContainerAnnotation(NodeList annotations, + InjectableVariableDefinition fieldPoint) { + + if (fieldPoint.getVariableElement().getAnnotation(ListContainer.class) != null) { + ObjectCreationExpr annotation = new ObjectCreationExpr(); + annotation + .setType(new ClassOrInterfaceType().setName(ListContainer.class.getCanonicalName())); + NodeList> anonymousClassBody = new NodeList<>(); + + MethodDeclaration annotationType = new MethodDeclaration(); + annotationType.setModifiers(Modifier.Keyword.PUBLIC); + annotationType.addAnnotation(Override.class); + annotationType.setName("annotationType"); + annotationType.setType( + new ClassOrInterfaceType().setName("Class")); + annotationType.getBody().get().addAndGetStatement( + new ReturnStmt(new NameExpr(ListContainer.class.getCanonicalName() + ".class"))); + anonymousClassBody.add(annotationType); + + MethodDeclaration value = new MethodDeclaration(); + value.setModifiers(Modifier.Keyword.PUBLIC); + value.addAnnotation(Override.class); + value.setName("value"); + value.setType(new ClassOrInterfaceType().setName("String")); + value.getBody().get().addAndGetStatement(new ReturnStmt(new StringLiteralExpr( + fieldPoint.getVariableElement().getAnnotation(ListContainer.class).value()))); + anonymousClassBody.add(value); + + annotation.setAnonymousClassBody(anonymousClassBody); + + annotations.add(annotation); + } + } + + private ObjectCreationExpr addDefaultAnnotation() { + ObjectCreationExpr annotation = new ObjectCreationExpr(); + annotation.setType(new ClassOrInterfaceType().setName(Default.class.getCanonicalName())); + NodeList> anonymousClassBody = new NodeList<>(); + + MethodDeclaration annotationType = new MethodDeclaration(); + annotationType.setModifiers(Modifier.Keyword.PUBLIC); + annotationType.addAnnotation(Override.class); + annotationType.setName("annotationType"); + annotationType.setType( + new ClassOrInterfaceType().setName("Class")); + annotationType.getBody().get().addAndGetStatement( + new ReturnStmt(new NameExpr(Default.class.getCanonicalName() + ".class"))); + anonymousClassBody.add(annotationType); + + annotation.setAnonymousClassBody(anonymousClassBody); + return annotation; + } + +} diff --git a/ui/databinding/pom.xml b/ui/databinding/pom.xml index 0ae83569..16c3158e 100644 --- a/ui/databinding/pom.xml +++ b/ui/databinding/pom.xml @@ -5,7 +5,7 @@ io.crysknife ui-parent - 0.1-SNAPSHOT + 0.3-SNAPSHOT databinding-parent diff --git a/ui/elemental2/dependency-reduced-pom.xml b/ui/elemental2/dependency-reduced-pom.xml index eb628756..b6b70d20 100644 --- a/ui/elemental2/dependency-reduced-pom.xml +++ b/ui/elemental2/dependency-reduced-pom.xml @@ -3,7 +3,7 @@ ui-parent io.crysknife - 0.2-SNAPSHOT + 0.3-SNAPSHOT 4.0.0 elemental2-generator @@ -33,18 +33,6 @@ - - maven-source-plugin - - - attach-sources - package - - jar - - - - maven-shade-plugin @@ -56,18 +44,6 @@ true - - com.google.guava:guava - - com/google/common/base - - - com/google/common/collect - - - io/crysknife/client/** - - *:*:*:* @@ -92,13 +68,13 @@ io.crysknife crysknife-annotations - 0.2-SNAPSHOT + 0.3-SNAPSHOT provided io.crysknife crysknife-processor - 0.2-SNAPSHOT + 0.3-SNAPSHOT provided diff --git a/ui/elemental2/pom.xml b/ui/elemental2/pom.xml index 4b1e0679..6093cc15 100644 --- a/ui/elemental2/pom.xml +++ b/ui/elemental2/pom.xml @@ -42,24 +42,20 @@ io.crysknife crysknife-annotations - ${project.version} provided io.crysknife crysknife-processor - ${project.version} provided com.google.guava guava - ${google.guava.version} com.github.javaparser javaparser-core - ${javaparser.core.version} provided @@ -73,14 +69,25 @@ org.apache.maven.plugins - maven-source-plugin + maven-shade-plugin - attach-sources package - jar + shade + + true + + + *:*:*:* + + **/*.java + **/*.js + + + + diff --git a/ui/elemental2/src/main/java/io/crysknife/ui/elemental2/Elemenatal2FactoryGenerator.java b/ui/elemental2/src/main/java/io/crysknife/ui/elemental2/Elemenatal2FactoryGenerator.java index 9c1bce7e..4b0efef2 100644 --- a/ui/elemental2/src/main/java/io/crysknife/ui/elemental2/Elemenatal2FactoryGenerator.java +++ b/ui/elemental2/src/main/java/io/crysknife/ui/elemental2/Elemenatal2FactoryGenerator.java @@ -14,11 +14,12 @@ package io.crysknife.ui.elemental2; -import javax.inject.Inject; -import javax.inject.Provider; - import com.github.javaparser.ast.expr.Expression; +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 com.google.common.collect.HashMultimap; import com.google.common.collect.SetMultimap; import elemental2.dom.DomGlobal; @@ -65,19 +66,26 @@ import elemental2.dom.HTMLTableColElement; import elemental2.dom.HTMLTableElement; import elemental2.dom.HTMLTableRowElement; +import elemental2.dom.HTMLTableSectionElement; import elemental2.dom.HTMLTextAreaElement; import elemental2.dom.HTMLTrackElement; import elemental2.dom.HTMLUListElement; import elemental2.dom.HTMLVideoElement; import io.crysknife.annotation.Generator; -import io.crysknife.client.internal.InstanceImpl; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.exception.GenerationException; import io.crysknife.generator.BeanIOCGenerator; import io.crysknife.generator.WiringElementType; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.point.FieldPoint; +import io.crysknife.definition.Definition; + +import javax.inject.Inject; +import javax.inject.Named; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; /** * @author Dmitrii Tikhomirov Created by treblereel 4/7/19 @@ -104,8 +112,14 @@ public class Elemenatal2FactoryGenerator extends BeanIOCGenerator { HTML_ELEMENTS.put(HTMLEmbedElement.class, "embed"); HTML_ELEMENTS.put(HTMLFieldSetElement.class, "fieldset"); HTML_ELEMENTS.put(HTMLFormElement.class, "form"); - HTML_ELEMENTS.put(HTMLHeadingElement.class, "named"); - HTML_ELEMENTS.put(HTMLElement.class, "named"); + HTML_ELEMENTS.put(HTMLHeadingElement.class, "h1"); + HTML_ELEMENTS.put(HTMLHeadingElement.class, "h2"); + HTML_ELEMENTS.put(HTMLHeadingElement.class, "h3"); + HTML_ELEMENTS.put(HTMLHeadingElement.class, "h4"); + HTML_ELEMENTS.put(HTMLHeadingElement.class, "h5"); + HTML_ELEMENTS.put(HTMLHeadingElement.class, "h6"); + HTML_ELEMENTS.put(HTMLElement.class, ""); + HTML_ELEMENTS.put(HTMLElement.class, "span"); HTML_ELEMENTS.put(HTMLHRElement.class, "hr"); HTML_ELEMENTS.put(HTMLImageElement.class, "img"); HTML_ELEMENTS.put(HTMLInputElement.class, "input"); @@ -136,6 +150,10 @@ public class Elemenatal2FactoryGenerator extends BeanIOCGenerator { HTML_ELEMENTS.put(HTMLTrackElement.class, "track"); HTML_ELEMENTS.put(HTMLUListElement.class, "ul"); HTML_ELEMENTS.put(HTMLVideoElement.class, "video"); + + HTML_ELEMENTS.put(HTMLTableSectionElement.class, "thead"); + HTML_ELEMENTS.put(HTMLTableSectionElement.class, "tfoot"); + HTML_ELEMENTS.put(HTMLTableSectionElement.class, "tbody"); } public Elemenatal2FactoryGenerator(IOCContext iocContext) { @@ -146,46 +164,65 @@ public Elemenatal2FactoryGenerator(IOCContext iocContext) { public void register() { HTML_ELEMENTS.keySet().forEach(clazz -> { iocContext.register(Inject.class, clazz, WiringElementType.FIELD_TYPE, this); - iocContext.getBlacklist().add(clazz.getCanonicalName()); }); } @Override - public void generateBeanFactory(ClassBuilder classBuilder, Definition definition) { + public void generate(ClassBuilder clazz, Definition beanDefinition) { } @Override - public Expression generateBeanCall(ClassBuilder classBuilder, FieldPoint fieldPoint, - BeanDefinition beanDefinition) { + public Expression generateBeanLookupCall(ClassBuilder classBuilder, + InjectableVariableDefinition fieldPoint) { classBuilder.getClassCompilationUnit().addImport(DomGlobal.class); - classBuilder.getClassCompilationUnit().addImport(InstanceImpl.class); - classBuilder.getClassCompilationUnit().addImport(Provider.class); - classBuilder.getClassCompilationUnit() - .addImport(beanDefinition.getType().getQualifiedName().toString()); - - return new NameExpr("(" + beanDefinition.getType().getSimpleName() - + ")DomGlobal.document.createElement(" + getTagFromType(fieldPoint, beanDefinition) + ")"); + classBuilder.getClassCompilationUnit().addImport(MoreTypes + .asTypeElement(fieldPoint.getVariableElement().asType()).getQualifiedName().toString()); + return generationUtils.wrapCallInstanceImpl(classBuilder, + new MethodCallExpr( + new FieldAccessExpr(new NameExpr(DomGlobal.class.getSimpleName()), "document"), + "createElement").addArgument(getTagFromType(fieldPoint))); } - private String getTagFromType(FieldPoint fieldPoint, BeanDefinition beanDefinition) { - if (fieldPoint.isNamed()) { - return "\"" + fieldPoint.getNamed() + "\""; + private StringLiteralExpr getTagFromType(InjectableVariableDefinition fieldPoint) { + if (fieldPoint.getVariableElement().getAnnotation(Named.class) != null + && !fieldPoint.getVariableElement().getAnnotation(Named.class).value().equals("")) { + return new StringLiteralExpr(fieldPoint.getVariableElement().getAnnotation(Named.class) + .value().toLowerCase(Locale.ROOT)); } Class clazz; try { - clazz = Class.forName(beanDefinition.getType().getQualifiedName().toString()); + clazz = Class.forName(MoreTypes.asTypeElement(fieldPoint.getVariableElement().asType()) + .getQualifiedName().toString()); } catch (ClassNotFoundException e) { - throw new Error("Unable to process " + beanDefinition.getType().getQualifiedName().toString() - + " " + e.getMessage()); + throw new Error( + "Unable to process " + MoreTypes.asTypeElement(fieldPoint.getVariableElement().asType()) + .getQualifiedName().toString() + " " + e.getMessage()); } if (!HTML_ELEMENTS.containsKey(clazz)) { - throw new Error( - "Unable to process " + beanDefinition.getType().getQualifiedName().toString()); + throw new GenerationException("Unable to process " + MoreTypes + .asTypeElement(fieldPoint.getVariableElement().asType()).getQualifiedName().toString()); + } + + long count = HTML_ELEMENTS.get(clazz).stream().count(); + + if (count > 1) { + throw new GenerationException("Unable to process " + + MoreTypes.asTypeElement(fieldPoint.getVariableElement().asType()).getQualifiedName() + .toString() + + ", " + + MoreTypes.asTypeElement(fieldPoint.getVariableElement().asType()).getEnclosingElement() + + "." + fieldPoint.getVariableElement().getSimpleName() + + " must be annotated with @Named(\"tag_name\")"); } - return "\"" + HTML_ELEMENTS.get(clazz).stream().findFirst().get() + "\""; + return new StringLiteralExpr(HTML_ELEMENTS.get(clazz).stream().findFirst().get()); + } + + public static Set> getHTMLElementByTag(String tag) { + return HTML_ELEMENTS.entries().stream().filter(elm -> elm.getValue().equals(tag)) + .collect(Collectors.toSet()); } } diff --git a/ui/gwt-dom/dependency-reduced-pom.xml b/ui/gwt-dom/dependency-reduced-pom.xml new file mode 100644 index 00000000..93db5df9 --- /dev/null +++ b/ui/gwt-dom/dependency-reduced-pom.xml @@ -0,0 +1,87 @@ + + + + ui-parent + io.crysknife + 0.3-SNAPSHOT + + 4.0.0 + gwt-dom-generator + gwt-dom factories generator + + + treblereel + Dmitrii Tikhomirov + chani.liet@gmail.com + + + + + Apache License Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo + + + + Treblereel + https://github.com/treblereel + + + + + src/main/resources + + + + + maven-shade-plugin + + + package + + shade + + + true + + + *:*:*:* + + **/*.java + **/*.js + + + + + + + + + + + + com.google.elemental2 + elemental2-dom + 1.1.0 + provided + + + io.crysknife + crysknife-annotations + 0.3-SNAPSHOT + provided + + + io.crysknife + crysknife-processor + 0.3-SNAPSHOT + provided + + + com.github.javaparser + javaparser-core + 3.15.18 + provided + + + diff --git a/ui/gwt-dom/pom.xml b/ui/gwt-dom/pom.xml new file mode 100644 index 00000000..c6fcc8e4 --- /dev/null +++ b/ui/gwt-dom/pom.xml @@ -0,0 +1,96 @@ + + + 4.0.0 + + + io.crysknife + ui-parent + 0.3-SNAPSHOT + + + gwt-dom-generator + gwt-dom factories generator + jar + + + + treblereel + Dmitrii Tikhomirov + chani.liet@gmail.com + + + + + + Apache License Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo + + + + + Treblereel + https://github.com/treblereel + + + + + com.google.elemental2 + elemental2-dom + provided + + + org.gwtproject.dom + gwt-dom + + + io.crysknife + crysknife-annotations + provided + + + io.crysknife + crysknife-processor + provided + + + com.github.javaparser + javaparser-core + provided + + + + + + + src/main/resources + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + true + + + *:*:*:* + + **/*.java + **/*.js + + + + + + + + + + \ No newline at end of file diff --git a/ui/gwt-dom/src/main/java/io/crysknife/ui/gwtproject/dom/GwtDomFactoryGenerator.java b/ui/gwt-dom/src/main/java/io/crysknife/ui/gwtproject/dom/GwtDomFactoryGenerator.java new file mode 100644 index 00000000..42a9089b --- /dev/null +++ b/ui/gwt-dom/src/main/java/io/crysknife/ui/gwtproject/dom/GwtDomFactoryGenerator.java @@ -0,0 +1,485 @@ +/* + * 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.ui.gwtproject.dom; + +import com.github.javaparser.ast.expr.CastExpr; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.LambdaExpr; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.NameExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.google.auto.common.MoreTypes; +import io.crysknife.annotation.Generator; +import io.crysknife.client.internal.InstanceImpl; +import io.crysknife.definition.InjectableVariableDefinition; +import io.crysknife.exception.GenerationException; +import io.crysknife.generator.BeanIOCGenerator; +import io.crysknife.generator.WiringElementType; +import io.crysknife.generator.api.ClassBuilder; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.definition.Definition; +import org.gwtproject.dom.client.AnchorElement; +import org.gwtproject.dom.client.AreaElement; +import org.gwtproject.dom.client.AudioElement; +import org.gwtproject.dom.client.BRElement; +import org.gwtproject.dom.client.BaseElement; +import org.gwtproject.dom.client.ButtonElement; +import org.gwtproject.dom.client.CanvasElement; +import org.gwtproject.dom.client.DListElement; +import org.gwtproject.dom.client.DivElement; +import org.gwtproject.dom.client.Document; +import org.gwtproject.dom.client.FieldSetElement; +import org.gwtproject.dom.client.FormElement; +import org.gwtproject.dom.client.FrameElement; +import org.gwtproject.dom.client.FrameSetElement; +import org.gwtproject.dom.client.HRElement; +import org.gwtproject.dom.client.HeadElement; +import org.gwtproject.dom.client.HeadingElement; +import org.gwtproject.dom.client.IFrameElement; +import org.gwtproject.dom.client.ImageElement; +import org.gwtproject.dom.client.InputElement; +import org.gwtproject.dom.client.LIElement; +import org.gwtproject.dom.client.LabelElement; +import org.gwtproject.dom.client.LegendElement; +import org.gwtproject.dom.client.LinkElement; +import org.gwtproject.dom.client.MapElement; +import org.gwtproject.dom.client.MediaElement; +import org.gwtproject.dom.client.MetaElement; +import org.gwtproject.dom.client.OListElement; +import org.gwtproject.dom.client.ObjectElement; +import org.gwtproject.dom.client.OptGroupElement; +import org.gwtproject.dom.client.OptionElement; +import org.gwtproject.dom.client.ParagraphElement; +import org.gwtproject.dom.client.ParamElement; +import org.gwtproject.dom.client.PreElement; +import org.gwtproject.dom.client.QuoteElement; +import org.gwtproject.dom.client.ScriptElement; +import org.gwtproject.dom.client.SelectElement; +import org.gwtproject.dom.client.SourceElement; +import org.gwtproject.dom.client.SpanElement; +import org.gwtproject.dom.client.StyleElement; +import org.gwtproject.dom.client.TableCaptionElement; +import org.gwtproject.dom.client.TableCellElement; +import org.gwtproject.dom.client.TableColElement; +import org.gwtproject.dom.client.TableElement; +import org.gwtproject.dom.client.TableRowElement; +import org.gwtproject.dom.client.TableSectionElement; +import org.gwtproject.dom.client.TextAreaElement; +import org.gwtproject.dom.client.TitleElement; +import org.gwtproject.dom.client.UListElement; +import org.gwtproject.dom.client.VideoElement; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.function.Function; + +/** + * @author Dmitrii Tikhomirov Created by treblereel 4/7/19 + */ +@Generator(priority = 100000) +public class GwtDomFactoryGenerator extends BeanIOCGenerator { + + private static final Map> HTML_ELEMENTS = + new HashMap<>(); + + static { + HTML_ELEMENTS.put(AnchorElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createAnchorElement")); + + HTML_ELEMENTS.put(AreaElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createAreaElement")); + + HTML_ELEMENTS.put(AudioElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createAudioElement")); + + HTML_ELEMENTS.put(BaseElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createBaseElement")); + + HTML_ELEMENTS.put(BRElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createBRElement")); + + HTML_ELEMENTS.put(BRElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createBRElement")); + + HTML_ELEMENTS.put(ButtonElement.class, fieldPoint -> { + if (isNamed(fieldPoint)) { + if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("submit")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createSubmitButtonElement"); + } else if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("reset")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createResetButtonElement"); + } + } + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createPushButtonElement"); + }); + + HTML_ELEMENTS.put(CanvasElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createCanvasElement")); + + HTML_ELEMENTS.put(DivElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createDivElement")); + + HTML_ELEMENTS.put(DListElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createDLElement")); + + HTML_ELEMENTS.put(FieldSetElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createFieldSetElement")); + + HTML_ELEMENTS.put(FormElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createFormElement")); + + HTML_ELEMENTS.put(FrameElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createFrameElement")); + + HTML_ELEMENTS.put(FrameSetElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createFrameSetElement")); + + HTML_ELEMENTS.put(HeadElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createHeadElement")); + + HTML_ELEMENTS.put(HeadingElement.class, fieldPoint -> { + if (isNamed(fieldPoint)) { + String h = getNamed(fieldPoint); + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createHElement").addArgument(h); + } else { + throw new GenerationException( + HeadingElement.class.getCanonicalName() + " must be annotated with @Named"); + } + }); + + HTML_ELEMENTS.put(HRElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createHRElement")); + + HTML_ELEMENTS.put(IFrameElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createIFrameElement")); + + HTML_ELEMENTS.put(ImageElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createImageElement")); + + HTML_ELEMENTS.put(InputElement.class, fieldPoint -> { + if (isNamed(fieldPoint)) { + + if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("checkbox")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createCheckInputElement"); + } else if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("file")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createFileInputElement"); + } else if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("hidden")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createHiddenInputElement"); + } else if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("image")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createImageInputElement"); + } else if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("password")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createPasswordInputElement"); + } else if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("radio")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createRadioInputElement"); + } else if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("reset")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createResetInputElement"); + } else if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("submit")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createSubmitInputElement"); + } else if (getNamed(fieldPoint).toLowerCase(Locale.ROOT).equals("text")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createTextInputElement"); + } + } + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createButtonInputElement"); + }); + + HTML_ELEMENTS.put(LabelElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createLabelElement")); + + HTML_ELEMENTS.put(LegendElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createLegendElement")); + + HTML_ELEMENTS.put(LIElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createLIElement")); + + HTML_ELEMENTS.put(LinkElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createLinkElement")); + + HTML_ELEMENTS.put(MapElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createMapElement")); + + HTML_ELEMENTS.put(MediaElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createMetaElement")); + + HTML_ELEMENTS.put(MetaElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createMetaElement")); + + HTML_ELEMENTS.put(ObjectElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createObjectElement")); + + HTML_ELEMENTS.put(OListElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createOLElement")); + + HTML_ELEMENTS.put(OptGroupElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createOptGroupElement")); + + HTML_ELEMENTS.put(OptionElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createOptionElement")); + + HTML_ELEMENTS.put(ParagraphElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createPElement")); + + HTML_ELEMENTS.put(ParamElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createParamElement")); + + HTML_ELEMENTS.put(PreElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createPreElement")); + + HTML_ELEMENTS.put(QuoteElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createQElement")); + + HTML_ELEMENTS.put(ScriptElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createScriptElement")); + + HTML_ELEMENTS.put(SelectElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createSelectElement")); + + HTML_ELEMENTS.put(SourceElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createSourceElement")); + + HTML_ELEMENTS.put(SpanElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createSpanElement")); + + HTML_ELEMENTS.put(SpanElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createSpanElement")); + + HTML_ELEMENTS.put(StyleElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createStyleElement")); + + HTML_ELEMENTS.put(TableCaptionElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createCaptionElement")); + + HTML_ELEMENTS.put(TableCellElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createTDElement")); + + HTML_ELEMENTS.put(TableColElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createColElement")); + + HTML_ELEMENTS.put(TableElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createTableElement")); + + HTML_ELEMENTS.put(TableRowElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createTRElement")); + + HTML_ELEMENTS.put(TableSectionElement.class, fieldPoint -> { + if (isNamed(fieldPoint)) { + String h = getNamed(fieldPoint).toLowerCase(Locale.ROOT); + if (h.equals("tbody")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createTBodyElement").addArgument(h); + } else if (h.equals("thead")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createTHeadElement").addArgument(h); + } else if (h.equals("tfoot")) { + return new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createTFootElement").addArgument(h); + } + throw new GenerationException( + TableSectionElement.class.getCanonicalName() + " must be annotated with valid @Named"); + } else { + throw new GenerationException( + TableSectionElement.class.getCanonicalName() + " must be annotated with @Named"); + } + }); + + HTML_ELEMENTS.put(TextAreaElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createTextAreaElement")); + + HTML_ELEMENTS.put(TitleElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createTitleElement")); + + HTML_ELEMENTS.put(UListElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createULElement")); + + HTML_ELEMENTS.put(VideoElement.class, + fieldPoint -> new MethodCallExpr( + new MethodCallExpr(new NameExpr(Document.class.getCanonicalName()), "get"), + "createVideoElement")); + } + + private static boolean isNamed(InjectableVariableDefinition fieldPoint) { + return fieldPoint.getVariableElement().getAnnotation(Named.class) != null + && !fieldPoint.getVariableElement().getAnnotation(Named.class).value().equals(""); + } + + private static String getNamed(InjectableVariableDefinition fieldPoint) { + return fieldPoint.getVariableElement().getAnnotation(Named.class).value(); + } + + public GwtDomFactoryGenerator(IOCContext iocContext) { + super(iocContext); + } + + @Override + public void register() { + HTML_ELEMENTS.keySet().forEach(clazz -> { + iocContext.register(Inject.class, clazz, WiringElementType.FIELD_TYPE, this); + }); + } + + @Override + public void generate(ClassBuilder clazz, Definition beanDefinition) { + + } + + @Override + public Expression generateBeanLookupCall(ClassBuilder classBuilder, + InjectableVariableDefinition fieldPoint) { + classBuilder.getClassCompilationUnit().addImport(InstanceImpl.class); + classBuilder.getClassCompilationUnit().addImport(Provider.class); + classBuilder.getClassCompilationUnit().addImport(MoreTypes + .asTypeElement(fieldPoint.getVariableElement().asType()).getQualifiedName().toString()); + + Class clazz; + try { + clazz = Class.forName(MoreTypes.asTypeElement(fieldPoint.getVariableElement().asType()) + .getQualifiedName().toString()); + } catch (ClassNotFoundException e) { + throw new Error( + "Unable to process " + MoreTypes.asTypeElement(fieldPoint.getVariableElement().asType()) + .getQualifiedName().toString() + " " + e.getMessage()); + } + return new ObjectCreationExpr().setType(InstanceImpl.class) + .addArgument(HTML_ELEMENTS.get(clazz).apply(fieldPoint)); + } + +} diff --git a/ui/gwt-resources/pom.xml b/ui/gwt-resources/pom.xml index f6693f49..a7fef8aa 100644 --- a/ui/gwt-resources/pom.xml +++ b/ui/gwt-resources/pom.xml @@ -43,22 +43,18 @@ org.gwtproject.resources gwt-resources-api - ${gwtproject.version} org.gwtproject.resources gwt-resources-core - ${gwtproject.version} org.gwtproject.resources gwt-resources-processor - ${gwtproject.version} io.crysknife crysknife-processor - ${project.version} diff --git a/ui/gwt-resources/src/main/java/io/crysknife/generator/ResourcesGenerator.java b/ui/gwt-resources/src/main/java/io/crysknife/generator/ResourcesGenerator.java index 0652c0db..a98c2bbc 100644 --- a/ui/gwt-resources/src/main/java/io/crysknife/generator/ResourcesGenerator.java +++ b/ui/gwt-resources/src/main/java/io/crysknife/generator/ResourcesGenerator.java @@ -52,7 +52,7 @@ public void register() { } @Override - public void generateBeanFactory(ClassBuilder classBuilder, Definition definition) { + public void generate(ClassBuilder classBuilder, Definition definition) { } diff --git a/ui/mutationobserver/api/pom.xml b/ui/mutationobserver/api/pom.xml index 9725b30e..55764d5e 100644 --- a/ui/mutationobserver/api/pom.xml +++ b/ui/mutationobserver/api/pom.xml @@ -37,7 +37,6 @@ io.crysknife crysknife-annotations - ${project.version} provided @@ -62,7 +61,6 @@ org.apache.maven.plugins maven-source-plugin - ${maven.source.plugin.version} attach-sources diff --git a/ui/mutationobserver/api/src/main/java/io/crysknife/ui/mutationobserver/client/api/MutationObserver.java b/ui/mutationobserver/api/src/main/java/io/crysknife/ui/mutationobserver/client/api/MutationObserver.java index e1d068a2..b77a87b2 100644 --- a/ui/mutationobserver/api/src/main/java/io/crysknife/ui/mutationobserver/client/api/MutationObserver.java +++ b/ui/mutationobserver/api/src/main/java/io/crysknife/ui/mutationobserver/client/api/MutationObserver.java @@ -18,6 +18,7 @@ import java.util.Map; import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; import javax.inject.Singleton; import elemental2.dom.DomGlobal; @@ -40,7 +41,7 @@ public class MutationObserver { private final Map detach = new HashMap<>(); - MutationObserver() { + public MutationObserver() { mutationObserverInit = MutationObserverInit.create(); mutationObserverInit.setChildList(true); mutationObserverInit.setSubtree(true); diff --git a/ui/mutationobserver/generator/dependency-reduced-pom.xml b/ui/mutationobserver/generator/dependency-reduced-pom.xml new file mode 100644 index 00000000..eaea573f --- /dev/null +++ b/ui/mutationobserver/generator/dependency-reduced-pom.xml @@ -0,0 +1,69 @@ + + + + mutationobserver-parent + io.crysknife + 0.3-SNAPSHOT + + 4.0.0 + mutationobserver-generator + mutationobserver generator + + + treblereel + Dmitrii Tikhomirov + chani.liet@gmail.com + + + + + Apache License Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo + + + + Treblereel + https://github.com/treblereel + + + + + src/main/resources + + + + + maven-shade-plugin + + + package + + shade + + + true + + + *:* + + **/*.java + jsinterop/base/** + + + + + + + + + + + + com.github.javaparser + javaparser-core + 3.15.18 + provided + + + diff --git a/ui/mutationobserver/generator/pom.xml b/ui/mutationobserver/generator/pom.xml index bede0247..07f6c0ed 100644 --- a/ui/mutationobserver/generator/pom.xml +++ b/ui/mutationobserver/generator/pom.xml @@ -37,17 +37,14 @@ io.crysknife mutationobserver-api - ${project.version} io.crysknife crysknife-processor - ${project.version} com.github.javaparser javaparser-core - ${javaparser.core.version} provided @@ -61,15 +58,25 @@ org.apache.maven.plugins - maven-source-plugin - ${maven.source.plugin.version} + maven-shade-plugin - attach-sources package - jar + shade + + true + + + *:* + + **/*.java + jsinterop/base/** + + + + diff --git a/ui/mutationobserver/generator/src/main/java/io/crysknife/ui/mutationobserver/generator/MutationObserverGenerator.java b/ui/mutationobserver/generator/src/main/java/io/crysknife/ui/mutationobserver/generator/MutationObserverGenerator.java index 202b8097..e8845c56 100644 --- a/ui/mutationobserver/generator/src/main/java/io/crysknife/ui/mutationobserver/generator/MutationObserverGenerator.java +++ b/ui/mutationobserver/generator/src/main/java/io/crysknife/ui/mutationobserver/generator/MutationObserverGenerator.java @@ -14,40 +14,38 @@ package io.crysknife.ui.mutationobserver.generator; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeMirror; - -import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.expr.CastExpr; import com.github.javaparser.ast.expr.EnclosedExpr; import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.google.auto.common.MoreElements; import elemental2.dom.HTMLElement; import elemental2.dom.MutationRecord; import io.crysknife.annotation.Generator; -import io.crysknife.generator.ScopedBeanGenerator; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.MethodDefinition; +import io.crysknife.generator.IOCGenerator; import io.crysknife.generator.WiringElementType; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.definition.ExecutableDefinition; import io.crysknife.ui.mutationobserver.client.api.MutationObserver; import io.crysknife.ui.mutationobserver.client.api.ObserverCallback; import io.crysknife.ui.mutationobserver.client.api.OnAttach; import io.crysknife.ui.mutationobserver.client.api.OnDetach; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; + /** * @author Dmitrii Tikhomirov Created by treblereel 4/7/19 */ @Generator(priority = 100002) -public class MutationObserverGenerator extends ScopedBeanGenerator { +public class MutationObserverGenerator extends IOCGenerator { private TypeMirror htmlElement; @@ -64,27 +62,13 @@ public void register() { htmlElement = iocContext.getGenerationContext().getElements() .getTypeElement(HTMLElement.class.getCanonicalName()).asType(); - - TypeElement mutationObserver = iocContext.getGenerationContext().getElements() - .getTypeElement(MutationObserver.class.getCanonicalName()); - - mutationObserverBeanDefinition = - iocContext.getBeanDefinitionOrCreateAndReturn(mutationObserver); - - iocContext.getBeans().put(mutationObserver, mutationObserverBeanDefinition); - if (!iocContext.getOrderedBeans().contains(mutationObserver)) { - iocContext.getOrderedBeans().add(mutationObserver); - } } - public void generateBeanFactory(ClassBuilder builder, Definition definition) { - if (definition instanceof ExecutableDefinition) { - ExecutableDefinition mutationObserver = (ExecutableDefinition) definition; - ifValid(mutationObserver); - VariableElement target = findField(mutationObserver); - isValid(target); - generateCallback(builder, mutationObserver); - } + public void generate(ClassBuilder builder, MethodDefinition mutationObserver) { + ifValid(mutationObserver); + VariableElement target = findField(mutationObserver); + isValid(target); + generateCallback(builder, mutationObserver); } private void isValid(VariableElement target) { @@ -104,7 +88,7 @@ private void isValid(VariableElement target) { } } - private VariableElement findField(ExecutableDefinition mutationObserver) { + private VariableElement findField(MethodDefinition mutationObserver) { String fieldName = findFieldName(mutationObserver.getExecutableElement()); Element target = mutationObserver.getExecutableElement().getEnclosingElement() @@ -129,7 +113,7 @@ private String findFieldName(ExecutableElement executableElement) { throw new Error("Unable to find field name"); } - private void ifValid(ExecutableDefinition mutationObserver) { + private void ifValid(MethodDefinition mutationObserver) { if (mutationObserver.getExecutableElement().getParameters().size() > 1 || mutationObserver.getExecutableElement().getParameters().isEmpty()) { throw new Error("Method [" + mutationObserver.getExecutableElement().getSimpleName() + " in " @@ -160,13 +144,9 @@ private void ifValid(ExecutableDefinition mutationObserver) { } } - public void generateCallback(ClassBuilder builder, ExecutableDefinition definition) { + public void generateCallback(ClassBuilder builder, MethodDefinition definition) { builder.getClassCompilationUnit().addImport(MutationObserver.class); builder.getClassCompilationUnit().addImport(ObserverCallback.class); - builder.getClassCompilationUnit().addImport("io.crysknife.client.BeanManagerImpl"); - - ClassOrInterfaceDeclaration factoryDeclaration = - new ClassOrInterfaceDeclaration().setName("BeanManagerImpl"); String callbackMethodName = definition.getExecutableElement().getAnnotation(OnAttach.class) != null @@ -179,12 +159,10 @@ public void generateCallback(ClassBuilder builder, ExecutableDefinition definiti EnclosedExpr castToAbstractEventHandler = new EnclosedExpr(new CastExpr(new ClassOrInterfaceType().setName("MutationObserver"), - new MethodCallExpr(new MethodCallExpr( - new MethodCallExpr(factoryDeclaration.getNameAsExpression(), "get"), "lookupBean") - .addArgument("MutationObserver.class"), - "get"))); + new MethodCallExpr(new MethodCallExpr(new NameExpr("beanManager"), "lookupBean") + .addArgument("MutationObserver.class"), "getInstance"))); - builder.getGetMethodDeclaration().getBody().get() + builder.getInitInstanceMethod().getBody().get() .addAndGetStatement(new MethodCallExpr(castToAbstractEventHandler, callbackMethodName) .addArgument("this.instance." + fieldName) .addArgument("(ObserverCallback) m -> this.instance." diff --git a/ui/navigation/api/pom.xml b/ui/navigation/api/pom.xml index 47c4cbb1..e88c4dfa 100644 --- a/ui/navigation/api/pom.xml +++ b/ui/navigation/api/pom.xml @@ -42,12 +42,10 @@ io.crysknife crysknife-annotations - ${project.version} io.crysknife crysknife-core - ${project.version} org.jboss.elemento @@ -63,7 +61,7 @@ org.gwtproject.event - gwt-logical-event + gwt-event-logical org.gwtproject.user.history diff --git a/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/Navigation.java b/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/Navigation.java index 26dcbf2f..3e2d54bb 100644 --- a/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/Navigation.java +++ b/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/Navigation.java @@ -543,10 +543,14 @@ private ElementsBag pageElements(Object page) { if (page != null) { if (page instanceof IsElement) { elements.add(((IsElement) page).element()); + } else if (page instanceof io.crysknife.client.IsElement) { + elements.add(((io.crysknife.client.IsElement) page).getElement()); } else if (page instanceof Iterable) { for (Object o : ((Iterable) page)) { if (o instanceof IsElement) { elements.add(((IsElement) o).element()); + } else if (page instanceof io.crysknife.client.IsElement) { + elements.add(((io.crysknife.client.IsElement) o).getElement()); } else if (o instanceof HTMLElement) { elements.add(((HTMLElement) o)); } diff --git a/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/spi/NavigationGraph.java b/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/spi/NavigationGraph.java index 94fabb09..215c935c 100644 --- a/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/spi/NavigationGraph.java +++ b/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/spi/NavigationGraph.java @@ -50,10 +50,15 @@ public abstract class NavigationGraph { @Inject protected BeanManager beanManager; - @Inject protected Event event; + + public NavigationGraph(BeanManager beanManager, Event event) { + this.beanManager = beanManager; + this.event = event; + } + /** * Maps page names to the classes that implement them. The subclass's constructor is responsible * for populating this map. diff --git a/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/spi/NavigationGraphImpl.java b/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/spi/NavigationGraphImpl.java index dd5394b3..4b0e69d4 100644 --- a/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/spi/NavigationGraphImpl.java +++ b/ui/navigation/api/src/main/java/io/crysknife/ui/navigation/client/local/spi/NavigationGraphImpl.java @@ -14,6 +14,11 @@ package io.crysknife.ui.navigation.client.local.spi; +import io.crysknife.client.BeanManager; +import io.crysknife.ui.navigation.client.shared.NavigationEvent; + +import javax.enterprise.event.Event; + /** * Fake implementation, ll be excluded on package/install * @@ -21,4 +26,7 @@ */ public class NavigationGraphImpl extends NavigationGraph { + public NavigationGraphImpl(BeanManager beanManager, Event event) { + super(beanManager, event); + } } diff --git a/ui/navigation/generator/dependency-reduced-pom.xml b/ui/navigation/generator/dependency-reduced-pom.xml new file mode 100644 index 00000000..4161a952 --- /dev/null +++ b/ui/navigation/generator/dependency-reduced-pom.xml @@ -0,0 +1,61 @@ + + + + navigation-parent + io.crysknife + 0.3-SNAPSHOT + + 4.0.0 + navigation-generator + navigation generator + + + treblereel + Dmitrii Tikhomirov + chani.liet@gmail.com + + + + + Apache License Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo + + + + Treblereel + https://github.com/treblereel + + + + + src/main/resources + + + + + maven-shade-plugin + + + package + + shade + + + true + + + *:* + + **/*.java + jsinterop/base/** + + + + + + + + + + diff --git a/ui/navigation/generator/pom.xml b/ui/navigation/generator/pom.xml index cf90bd38..53883f1f 100644 --- a/ui/navigation/generator/pom.xml +++ b/ui/navigation/generator/pom.xml @@ -1,62 +1,93 @@ - - 4.0.0 + + 4.0.0 - - io.crysknife - navigation-parent - 0.3-SNAPSHOT - + + io.crysknife + navigation-parent + 0.3-SNAPSHOT + - navigation-generator - navigation generator - jar + navigation-generator + navigation generator + jar - - - treblereel - Dmitrii Tikhomirov - chani.liet@gmail.com - - + + + treblereel + Dmitrii Tikhomirov + chani.liet@gmail.com + + - - - Apache License Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 - repo - - + + + Apache License Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + repo + + - - Treblereel - https://github.com/treblereel - + + Treblereel + https://github.com/treblereel + - - - com.google.auto - auto-common - - - com.google.elemental2 - elemental2-dom - - - org.jboss.elemento - elemento-core - - - io.crysknife - crysknife-processor - ${project.version} - compile - - - io.crysknife - navigation-api - ${project.version} - - + + + com.google.auto + auto-common + + + com.google.elemental2 + elemental2-dom + + + org.jboss.elemento + elemento-core + + + io.crysknife + crysknife-processor + + + io.crysknife + navigation-api + + + + + + src/main/resources + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + true + + + *:* + + **/*.java + jsinterop/base/** + + + + + + + + + \ No newline at end of file diff --git a/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/NavigationGenerator.java b/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/NavigationGenerator.java index c47c09b7..c7de2d38 100644 --- a/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/NavigationGenerator.java +++ b/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/NavigationGenerator.java @@ -14,29 +14,30 @@ package io.crysknife.ui.navigation.generator; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.inject.Inject; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.TypeElement; - +import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.google.auto.common.MoreElements; import io.crysknife.annotation.Generator; import io.crysknife.client.BeanManager; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.InjectableVariableDefinition; import io.crysknife.generator.SingletonGenerator; import io.crysknife.generator.WiringElementType; +import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; import io.crysknife.logger.PrintWriterTreeLogger; -import io.crysknife.ui.navigation.client.local.Navigation; import io.crysknife.ui.navigation.client.local.Page; import io.crysknife.ui.navigation.client.local.spi.NavigationGraph; import io.crysknife.ui.navigation.client.shared.NavigationEvent; -import io.crysknife.util.Utils; + +import javax.inject.Inject; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import java.util.Set; +import java.util.stream.Collectors; /** * @author Dmitrii Tikhomirov Created by treblereel 3/1/20 @@ -50,7 +51,9 @@ public NavigationGenerator(IOCContext iocContext) { @Override public void register() { - iocContext.register(Inject.class, NavigationGraph.class, WiringElementType.BEAN, this); + + iocContext.register(Inject.class, NavigationGraph.class, WiringElementType.FIELD_TYPE, this); + iocContext.getOrderedBeans().add(iocContext.getTypeMirror(NavigationGraph.class)); } @Override @@ -61,15 +64,6 @@ public void before() { .stream().filter(elm -> elm.getKind().equals(ElementKind.CLASS)) .map(elm -> MoreElements.asType(elm)).collect(Collectors.toSet()); - TypeElement type = iocContext.getGenerationContext().getElements() - .getTypeElement(Navigation.class.getCanonicalName()); - BeanDefinition navigation = iocContext.getBeanDefinitionOrCreateAndReturn(type); - - pages.forEach(elm -> { - BeanDefinition page = iocContext.getBeanDefinitionOrCreateAndReturn(elm); - navigation.getDependsOn().add(page); - }); - new NavigationGraphGenerator(pages).generate(new PrintWriterTreeLogger(), iocContext.getGenerationContext()); } @@ -77,14 +71,25 @@ public void before() { @Override protected ObjectCreationExpr generateNewInstanceCreationExpr(BeanDefinition definition) { ObjectCreationExpr newInstance = new ObjectCreationExpr(); - return newInstance + newInstance.setType(NavigationGraph.class.getPackage().getName() + ".GeneratedNavigationGraph"); + newInstance.addArgument("beanManager"); + newInstance.addArgument( + new MethodCallExpr(new MethodCallExpr(new NameExpr("_field_event"), "get"), "getInstance")); + return newInstance; + } + + @Override + public Expression generateBeanLookupCall(ClassBuilder classBuilder, + InjectableVariableDefinition fieldPoint) { + ObjectCreationExpr newInstance = new ObjectCreationExpr(); + + + return generationUtils.wrapCallInstanceImpl(classBuilder, newInstance .setType(NavigationGraph.class.getPackage().getName() + ".GeneratedNavigationGraph") .addArgument(new MethodCallExpr( - new MethodCallExpr( - new NameExpr(Utils.toVariableName(BeanManager.class.getCanonicalName())), "get"), - "get")) - .addArgument( - new MethodCallExpr(new MethodCallExpr(new NameExpr("Event_Factory"), "get"), "get") - .addArgument(NavigationEvent.class.getCanonicalName() + ".class")); + new NameExpr(BeanManager.class.getPackage().getName() + ".BeanManagerImpl"), "get")) + .addArgument(new MethodCallExpr( + new MethodCallExpr(new NameExpr("javax.enterprise.event.Event_Factory"), "get"), "get") + .addArgument(NavigationEvent.class.getCanonicalName() + ".class"))); } } diff --git a/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/NavigationGraphGenerator.java b/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/NavigationGraphGenerator.java index bc71b114..3e271519 100644 --- a/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/NavigationGraphGenerator.java +++ b/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/NavigationGraphGenerator.java @@ -124,6 +124,9 @@ public String generateSource(final GenerationContext context, final String fqcn) constructorDeclaration.addParameter(BeanManager.class.getSimpleName(), "beanManager"); constructorDeclaration.addParameter("Event", "event"); + MethodCallExpr superExpr = + new MethodCallExpr("super").addArgument("beanManager").addArgument("event"); + constructorDeclaration.getBody().addAndGetStatement(superExpr); generatePages(constructorDeclaration); try { @@ -159,9 +162,10 @@ protected void build(String fileName, String source, GenerationContext context) } private void generatePage(TypeElement page, ConstructorDeclaration ctor) { - if (!isAssignable(page.asType(), IsElement.class)) { - throw new GenerationException( - "Class " + page + " is annotated with @Page, so it must implement IsElement"); + if (!(isAssignable(page.asType(), IsElement.class) + || isAssignable(page.asType(), io.crysknife.client.IsElement.class))) { + throw new GenerationException("Class " + page + + " is annotated with @Page, so it must implement org.jboss.elemento.IsElement or io.crysknife.client.IsElement"); } compilationUnit.addImport(page.getQualifiedName().toString()); Page annotation = page.getAnnotation(Page.class); @@ -326,7 +330,7 @@ private void generateProduceContent(TypeElement page, String pageName, new MethodCallExpr(new NameExpr("callback"), "callback").addArgument( new MethodCallExpr(new MethodCallExpr(new NameExpr("beanManager"), "lookupBean") - .addArgument(page.getQualifiedName() + ".class"), "get"))); + .addArgument(page.getQualifiedName() + ".class"), "getInstance"))); anonymousClassBody.add(method); } diff --git a/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/TransitionToGenerator.java b/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/TransitionToGenerator.java index f3adefc4..8933e019 100644 --- a/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/TransitionToGenerator.java +++ b/ui/navigation/generator/src/main/java/io/crysknife/ui/navigation/generator/TransitionToGenerator.java @@ -16,19 +16,23 @@ import javax.inject.Inject; +import com.github.javaparser.ast.expr.CastExpr; import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.LambdaExpr; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.expr.ObjectCreationExpr; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.google.auto.common.MoreTypes; import io.crysknife.annotation.Generator; +import io.crysknife.client.internal.InstanceImpl; +import io.crysknife.definition.InjectableVariableDefinition; import io.crysknife.generator.ScopedBeanGenerator; import io.crysknife.generator.WiringElementType; import io.crysknife.generator.api.ClassBuilder; import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.point.FieldPoint; +import io.crysknife.definition.Definition; import io.crysknife.ui.navigation.client.local.Navigation; import io.crysknife.ui.navigation.client.local.TransitionTo; @@ -47,26 +51,28 @@ public TransitionToGenerator(IOCContext iocContext) { @Override public void register() { iocContext.register(Inject.class, TransitionTo.class, WiringElementType.BEAN, this); - iocContext.getBlacklist().add(TransitionTo.class.getCanonicalName()); } @Override - public void generateBeanFactory(ClassBuilder clazz, Definition definition) { + public void generate(ClassBuilder clazz, Definition beanDefinition) { } @Override - public Expression generateBeanCall(ClassBuilder clazz, FieldPoint fieldPoint, - BeanDefinition beanDefinition) { + public Expression generateBeanLookupCall(ClassBuilder clazz, + InjectableVariableDefinition fieldPoint) { clazz.getClassCompilationUnit().addImport(TransitionTo.class); + clazz.getClassCompilationUnit().addImport(Navigation.class); + clazz.getClassCompilationUnit().addImport(InstanceImpl.class); - return new ObjectCreationExpr().setType(TransitionTo.class) - .addArgument(MoreTypes.asDeclared(fieldPoint.getField().asType()).getTypeArguments().get(0) - .toString() + ".class") - .addArgument( - new MethodCallExpr( - new MethodCallExpr(new MethodCallExpr(new NameExpr("BeanManagerImpl"), "get"), - "lookupBean").addArgument(Navigation.class.getCanonicalName() + ".class"), - "get")); + return new ObjectCreationExpr().setType(InstanceImpl.class) + .addArgument(new ObjectCreationExpr().setType(TransitionTo.class) + .addArgument(MoreTypes.asDeclared(fieldPoint.getVariableElement().asType()) + .getTypeArguments().get(0).toString() + ".class") + .addArgument( + new CastExpr(new ClassOrInterfaceType().setName(Navigation.class.getSimpleName()), + new MethodCallExpr(new MethodCallExpr(new NameExpr("beanManager"), "lookupBean") + .addArgument(Navigation.class.getSimpleName() + ".class"), + "getInstance")))); } } diff --git a/ui/pom.xml b/ui/pom.xml index 0a8edf18..ba40f976 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -22,13 +22,12 @@ elemental2 + gwt-dom templates - mutationobserver navigation diff --git a/ui/templates/api/pom.xml b/ui/templates/api/pom.xml index 70bdbcf1..acb36b08 100644 --- a/ui/templates/api/pom.xml +++ b/ui/templates/api/pom.xml @@ -34,6 +34,10 @@ + + io.crysknife + crysknife-core + com.google.elemental2 elemental2-dom @@ -49,12 +53,12 @@ - org.gwtproject.dom - gwt-dom + org.gwtproject.event + gwt-event-dom org.gwtproject.event - gwt-event-dom + gwt-event org.jsoup diff --git a/ui/templates/api/src/main/java/io/crysknife/ui/templates/client/TemplateUtil.java b/ui/templates/api/src/main/java/io/crysknife/ui/templates/client/TemplateUtil.java index 23752c8c..e905e367 100644 --- a/ui/templates/api/src/main/java/io/crysknife/ui/templates/client/TemplateUtil.java +++ b/ui/templates/api/src/main/java/io/crysknife/ui/templates/client/TemplateUtil.java @@ -35,16 +35,19 @@ @SuppressWarnings("UnnecessaryLocalVariable") public final class TemplateUtil { - private static SelectorFunction DATA_ELEMENT = - (context, identifier) -> context.querySelector("[data-field=" + identifier + "]"); + private static SelectorFunction DATA_ELEMENT = (context, identifier) -> { + Element result = context.querySelector("[data-field=" + identifier + "]"); + if (result == null) { + result = context.querySelector("#" + identifier); + } + if (result == null) { + result = context.querySelector("." + identifier); + } - private TemplateUtil() {} + return result; + }; - // ------------------------------------------------------ HTMLElement methods - public static E resolveElement(HTMLElement context, String identifier) { - Element element = DATA_ELEMENT.select(context, identifier); - return Js.cast(element); - } + private TemplateUtil() {} public static E resolveElementAs(HTMLElement context, String identifier) { Element element = DATA_ELEMENT.select(context, identifier); @@ -52,6 +55,11 @@ public static E resolveElementAs(HTMLElement context, St return htmlElement; } + public static void replaceIsElement(HTMLElement context, String identifier, + IsElement newElement) { + replaceElement(context, identifier, newElement.element()); + } + // ------------------------------------------------------ IsElement / (Is)Widget methods public static void replaceElement(HTMLElement context, String identifier, @@ -78,9 +86,15 @@ public static void replaceElement(HTMLElement context, String identifier, // ------------------------------------------------------ custom elements + // ------------------------------------------------------ HTMLElement methods + public static E resolveElement(HTMLElement context, String identifier) { + Element element = DATA_ELEMENT.select(context, identifier); + return Js.cast(element); + } + public static void replaceIsElement(HTMLElement context, String identifier, - IsElement newElement) { - replaceElement(context, identifier, newElement.element()); + io.crysknife.client.IsElement newElement) { + replaceElement(context, identifier, newElement.getElement()); } public static E resolveCustomElement(HTMLElement context, String identifier) { diff --git a/ui/templates/generator/dependency-reduced-pom.xml b/ui/templates/generator/dependency-reduced-pom.xml index c0fa461d..153282c2 100644 --- a/ui/templates/generator/dependency-reduced-pom.xml +++ b/ui/templates/generator/dependency-reduced-pom.xml @@ -27,6 +27,14 @@ https://github.com/treblereel + + + src/main/java + + **/*.bak + + + maven-shade-plugin diff --git a/ui/templates/generator/pom.xml b/ui/templates/generator/pom.xml index e5132f02..20c66676 100644 --- a/ui/templates/generator/pom.xml +++ b/ui/templates/generator/pom.xml @@ -59,8 +59,8 @@ jsoup - org.lesscss - lesscss + de.inetsoftware + jlessc com.google.guava @@ -69,17 +69,24 @@ io.crysknife crysknife-processor - ${project.version} io.crysknife templates-api - ${project.version} + + + src/main/java + + **/*.bak + + + + org.apache.maven.plugins maven-shade-plugin diff --git a/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateWidget.java.bak b/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateWidget.java.bak new file mode 100644 index 00000000..c47dad50 --- /dev/null +++ b/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateWidget.java.bak @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2012 Red Hat, Inc. and/or its affiliates. + * + * 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.gwtproject.user.client.ui; + +import java.util.Collection; +import java.util.Iterator; + +import elemental2.dom.HTMLElement; +import io.crysknife.ui.templates.client.annotation.Templated; +import jsinterop.base.Js; +import org.gwtproject.dom.client.Element; + +/** + * Used to merge a {@link Templated} onto a {@link Composite} component. + * @author Lincoln Baxter, III + */ +public class TemplateWidget extends FocusPanel { + + private final Collection children; + + public TemplateWidget(final Element root, final Collection children) { + this.setElement(root); + this.children = children; + doInit(); + } + + public TemplateWidget(final IsWidget root, final Collection children) { + this.children = children; + doInit(); + } + + private void doInit() { + for (Widget child : children) { + if (!(child instanceof TemplateWidget) && child.getParent() instanceof TemplateWidget) { + child = child.getParent(); + } + child.removeFromParent(); + adopt(child); + //if (!child.isAttached()) { + // child.onAttach(); + //} + } + } + + public static void initTemplated(final Element wrapped, final Collection dataFields) { + // All template fragments are contained in a single element, during initialization. + wrapped.removeFromParent(); + final TemplateWidget widget = new TemplateWidget(wrapped, dataFields); + widget.onAttach(); + try { + RootPanel.detachOnWindowClose(widget); + } catch (Exception e) { + + } + } + + public static void initTemplated(final IsWidget component, final HTMLElement wrapped, final Collection dataFields) { + // All template fragments are contained in a single element, during initialization. + component.asWidget().removeFromParent(); + final TemplateWidget widget = new TemplateWidget(component, dataFields); + if(component instanceof Composite) { + ((Composite)component).initWidget(wrapElemental2(wrapped)); + } + + widget.onAttach(); + try { + RootPanel.detachOnWindowClose(widget); + } catch (Exception e) { + + } + } + + public static Widget wrapElemental2(HTMLElement element) { + return new FocusWidget(Js.uncheckedCast(element)) {}; + } + + @Override + public void onAttach() { + super.onAttach(); + } + + @Override + public Iterator iterator() { + return children.iterator(); + } + + @Override + public boolean remove(final Widget child) { + if (child.getParent() != this) { + return false; + } + orphan(child); + child.getElement().removeFromParent(); + return children.remove(child); + } +} diff --git a/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateWidgetGenerator.java b/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateWidgetGenerator.java index 2dbb3912..3ba68da2 100644 --- a/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateWidgetGenerator.java +++ b/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplateWidgetGenerator.java @@ -14,85 +14,45 @@ package io.crysknife.ui.templates.generator; -import java.io.IOException; -import java.io.PrintWriter; - -import javax.tools.JavaFileObject; - import io.crysknife.exception.GenerationException; import io.crysknife.generator.context.IOCContext; +import org.apache.commons.io.IOUtils; + +import javax.tools.JavaFileObject; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URL; +import java.nio.charset.Charset; /** * @author Dmitrii Tikhomirov Created by treblereel 6/25/20 */ public class TemplateWidgetGenerator { - private final String newLine = System.lineSeparator(); private IOCContext iocContext; private StringBuilder clazz; - private static final String dom2Package = "com.google.gwt.dom"; - private static final String widget2Package = "com.google.gwt.user"; - private static final String dom3Package = "org.gwtproject.dom"; - private static final String widget3Package = "org.gwtproject.user"; - TemplateWidgetGenerator(IOCContext iocContext) { this.iocContext = iocContext; } TemplateWidgetGenerator build(boolean isGWT2) { - this.clazz = new StringBuilder(); - clazz - .append("/*\n" + " * Copyright (C) 2012 Red Hat, Inc. and/or its affiliates.\n" + " *\n" - + " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" - + " * you may not use this file except in compliance with the License.\n" - + " * You may obtain a copy of the License at\n" + " *\n" - + " * http://www.apache.org/licenses/LICENSE-2.0\n" + " *\n" - + " * Unless required by applicable law or agreed to in writing, software\n" - + " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" - + " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" - + " * See the License for the specific language governing permissions and\n" - + " * limitations under the License.\n" + " */\n" + "\n" - + "package io.crysknife.templates.client;\n" + "\n" + "import java.util.Collection;\n" - + "import java.util.Iterator;\n" + "\n") - .append(newLine) + if (isGWT2) + throw new GenerationException("Unsupported operation"); + URL url = iocContext.getGenerationContext().getResourceOracle() + .findResource("io/crysknife/ui/templates/generator/TemplateWidget.java.bak"); - .append("import ").append(isGWT2 ? dom2Package : dom3Package).append(".client.Element;\n") - .append("import ").append(isGWT2 ? widget2Package : widget3Package) - .append(".client.ui.Composite;\n").append("import ") - .append(isGWT2 ? widget2Package : widget3Package).append(".client.ui.Panel;\n") - .append("import ").append(isGWT2 ? widget2Package : widget3Package) - .append(".client.ui.RootPanel;\n").append("import ") - .append(isGWT2 ? widget2Package : widget3Package).append(".client.ui.Widget;\n") - .append("import io.crysknife.ui.templates.client.annotation.Templated;\n" + "\n" + "/**\n" - + " * Used to merge a {@link Templated} onto a {@link Composite} component.\n" + " *\n" - + " * @author Lincoln Baxter, III\n" - + " */\n" + "public class TemplateWidget extends Panel {\n" - + " private final Collection children;\n" + "\n" - + " public TemplateWidget(final Element root, final Collection children) {\n" - + " this.setElement(root);\n" + " this.children = children;\n" + "\n" - + " for (Widget child : children) {\n" - + " if (!(child instanceof TemplateWidget) && child.getParent() instanceof TemplateWidget) {\n" - + " child = child.getParent();\n" + " }\n" - + " child.removeFromParent();\n" + " adopt(child);\n" - + " }\n" + " }\n" + "\n" + " @Override\n" - + " public void onAttach() {\n" + " super.onAttach();\n" + " }\n" + "\n" - + " @Override\n" + " public Iterator iterator() {\n" - + " return children.iterator();\n" + " }\n" + "\n" + " @Override\n" - + " public boolean remove(final Widget child) {\n" - + " if (child.getParent() != this)\n" + " {\n" - + " return false;\n" + " }\n" + " orphan(child);\n" - + " child.getElement().removeFromParent();\n" - + " return children.remove(child);\n" + " }\n" + "\n" - + " public static void initTemplated(final Element wrapped, final Collection dataFields) {\n" - + " // All template fragments are contained in a single element, during initialization.\n" - + " wrapped.removeFromParent();\n" - + " final TemplateWidget widget = new TemplateWidget(wrapped, dataFields);\n" - + " widget.onAttach();\n" + " try {\n" - + " RootPanel.detachOnWindowClose(widget);\n" - + " } catch (Exception e) {\n" + "\n" + " }\n" + " }\n" + "\n" - + "}\n"); + if (url == null) { + throw new GenerationException( + "Cannot find template for io.crysknife.ui.templates.generator.TemplateWidget.java"); + } + try { + this.clazz = new StringBuilder(IOUtils.toString(url, Charset.defaultCharset())); + } catch (IOException e) { + throw new GenerationException( + "Cannot find template for io.crysknife.ui.templates.generator.TemplateWidget.java"); + } return this; } @@ -100,7 +60,7 @@ void generate() { JavaFileObject builderFile = null; try { builderFile = iocContext.getGenerationContext().getProcessingEnvironment().getFiler() - .createSourceFile("io.crysknife.templates.client.TemplateWidget"); + .createSourceFile("org.gwtproject.user.client.ui.TemplateWidget"); try (PrintWriter out = new PrintWriter(builderFile.openWriter())) { out.append(clazz); } diff --git a/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplatedGenerator.java b/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplatedGenerator.java index 309007e4..959a348e 100644 --- a/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplatedGenerator.java +++ b/ui/templates/generator/src/main/java/io/crysknife/ui/templates/generator/TemplatedGenerator.java @@ -14,44 +14,10 @@ package io.crysknife.ui.templates.generator; -import java.io.File; -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringJoiner; -import java.util.stream.Collectors; - -import javax.annotation.processing.Messager; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.ElementFilter; -import javax.tools.Diagnostic; - import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.ConstructorDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.body.VariableDeclarator; import com.github.javaparser.ast.expr.AssignExpr; import com.github.javaparser.ast.expr.BinaryExpr; import com.github.javaparser.ast.expr.CastExpr; @@ -61,9 +27,12 @@ import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.expr.NullLiteralExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.github.javaparser.ast.expr.StringLiteralExpr; import com.github.javaparser.ast.expr.ThisExpr; +import com.github.javaparser.ast.expr.VariableDeclarationExpr; import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.stmt.IfStmt; import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.ast.type.ClassOrInterfaceType; @@ -77,6 +46,7 @@ import com.google.common.collect.SetMultimap; 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.Event; import elemental2.dom.HTMLAnchorElement; @@ -126,10 +96,23 @@ import elemental2.dom.HTMLTrackElement; import elemental2.dom.HTMLUListElement; import elemental2.dom.HTMLVideoElement; +import io.crysknife.annotation.Generator; +import io.crysknife.client.Reflect; +import io.crysknife.definition.BeanDefinition; +import io.crysknife.definition.InjectionParameterDefinition; +import io.crysknife.exception.GenerationException; import io.crysknife.generator.IOCGenerator; import io.crysknife.generator.WiringElementType; +import io.crysknife.generator.api.ClassBuilder; +import io.crysknife.generator.context.IOCContext; +import io.crysknife.ui.templates.client.StyleInjector; +import io.crysknife.ui.templates.client.TemplateUtil; +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.util.Utils; import jsinterop.base.Js; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.gwtproject.event.dom.client.BlurEvent; import org.gwtproject.event.dom.client.CanPlayThroughEvent; @@ -184,24 +167,37 @@ import org.jsoup.nodes.Attribute; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; -import org.lesscss.LessCompiler; -import org.lesscss.LessException; -import org.lesscss.LessSource; -import io.crysknife.annotation.Generator; -import io.crysknife.client.Reflect; -import io.crysknife.exception.GenerationException; -import io.crysknife.generator.api.ClassBuilder; -import io.crysknife.generator.context.IOCContext; -import io.crysknife.generator.definition.BeanDefinition; -import io.crysknife.generator.definition.Definition; -import io.crysknife.generator.point.FieldPoint; -import io.crysknife.ui.templates.client.StyleInjector; -import io.crysknife.ui.templates.client.TemplateUtil; -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.util.Utils; + +import javax.annotation.processing.Messager; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.tools.Diagnostic; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringJoiner; +import java.util.stream.Collectors; import static java.util.Arrays.asList; import static java.util.stream.Collectors.joining; @@ -210,7 +206,7 @@ * @author Dmitrii Tikhomirov Created by treblereel 4/7/19 */ @Generator -public class TemplatedGenerator extends IOCGenerator { +public class TemplatedGenerator extends IOCGenerator { private static final String QUOTE = "\""; private static final Escaper JAVA_STRING_ESCAPER = @@ -265,6 +261,7 @@ public class TemplatedGenerator extends IOCGenerator { HTML_ELEMENTS.put(HTMLSourceElement.class.getName(), "source"); HTML_ELEMENTS.put(HTMLTableElement.class.getName(), "table"); HTML_ELEMENTS.put(HTMLTableCellElement.class.getName(), "td"); + HTML_ELEMENTS.put(HTMLTableCellElement.class.getName(), "th"); HTML_ELEMENTS.put(HTMLTextAreaElement.class.getName(), "textarea"); HTML_ELEMENTS.put(HTMLTableRowElement.class.getName(), "tr"); HTML_ELEMENTS.put(HTMLTrackElement.class.getName(), "track"); @@ -313,9 +310,18 @@ public class TemplatedGenerator extends IOCGenerator { private ProcessingEnvironment processingEnvironment; private Messager messager; private BeanDefinition beanDefinition; + private TypeElement isWidget; + private TypeElement GWT3_Event; public TemplatedGenerator(IOCContext iocContext) { super(iocContext); + + isWidget = iocContext.getGenerationContext().getElements() + .getTypeElement("org.gwtproject.user.client.ui.IsWidget"); + + GWT3_Event = iocContext.getGenerationContext().getElements() + .getTypeElement("org.gwtproject.user.client.Event"); + } @Override @@ -324,17 +330,19 @@ public void register() { this.messager = processingEnvironment.getMessager(); iocContext.register(Templated.class, WiringElementType.CLASS_DECORATOR, this); + + if (isWidget != null) { + new TemplateWidgetGenerator(iocContext).build(false).generate(); + } } @Override - public void generateBeanFactory(ClassBuilder builder, Definition definition) { - if (definition instanceof BeanDefinition) { - beanDefinition = (BeanDefinition) definition; - validateType(beanDefinition.getType(), - beanDefinition.getType().getAnnotation(Templated.class)); - processType(builder, beanDefinition.getType(), - beanDefinition.getType().getAnnotation(Templated.class)); - } + public void generate(ClassBuilder builder, BeanDefinition beanDefinition) { + this.beanDefinition = beanDefinition; + validateType(MoreTypes.asTypeElement(beanDefinition.getType()), + MoreTypes.asTypeElement(beanDefinition.getType()).getAnnotation(Templated.class)); + processType(builder, MoreTypes.asTypeElement(beanDefinition.getType()), + MoreTypes.asTypeElement(beanDefinition.getType()).getAnnotation(Templated.class)); } // ------------------------------------------------------ root element / template @@ -342,13 +350,16 @@ private RootElementInfo createRootElementInfo(org.jsoup.nodes.Element root, Stri List attributes = root.attributes().asList().stream() .filter(attribute -> !attribute.getKey().equals("data-field")).collect(Collectors.toList()); + java.util.Optional dataField = root.attributes().asList().stream() + .filter(attribute -> attribute.getKey().equals("data-field")).findFirst(); + ExpressionParser expressionParser = new ExpressionParser(); String html = root.children().isEmpty() ? null : JAVA_STRING_ESCAPER.escape(root.html()); Map expressions = expressionParser.parse(html); expressions.putAll(expressionParser.parse(root.outerHtml())); - return new RootElementInfo(root.tagName(), subclass.toLowerCase() + "_root_element", attributes, - html, expressions); + return new RootElementInfo(root.tagName(), dataField, subclass.toLowerCase() + "_root_element", + attributes, html, expressions); } private TemplateSelector getTemplateSelector(TypeElement type, Templated templated) { @@ -368,29 +379,35 @@ private TemplateSelector getTemplateSelector(TypeElement type, Templated templat private StyleSheet getStylesheet(TypeElement type, Templated templated) { if (Strings.emptyToNull(templated.stylesheet()) == null) { List postfixes = Arrays.asList(".css", ".gss", ".less"); - String path = type.getQualifiedName().toString().replaceAll("\\.", "/"); + String path = MoreElements.getPackage(type).toString().replaceAll("\\.", "/"); for (String postfix : postfixes) { + String beanName = type.getSimpleName().toString() + postfix; URL file = - iocContext.getGenerationContext().getResourceOracle().findResource(path, postfix); - try { - if (file != null && new File(file.toURI()).exists()) { - return new StyleSheet(type.getSimpleName() + "" + postfix, new File(file.toURI())); - } - } catch (URISyntaxException e) { + iocContext.getGenerationContext().getResourceOracle().findResource(path, beanName); + if (file != null) { + return new StyleSheet(type.getSimpleName() + postfix, file); } } } else { try { - return new StyleSheet(templated.stylesheet(), - new File(iocContext.getGenerationContext().getResourceOracle() - .findResource(MoreElements.getPackage(type).getQualifiedName().toString(), - templated.stylesheet()) - .toURI())); - } catch (URISyntaxException e) { - throw new GenerationException(e); + String path = + MoreElements.getPackage(type).getQualifiedName().toString().replaceAll("\\.", "/") + "/" + + templated.stylesheet(); + + URL url = iocContext.getGenerationContext().getResourceOracle().findResource(path); + if (url != null) { + return new StyleSheet(templated.stylesheet(), url); + } + } catch (IllegalArgumentException e1) { + String path = + MoreElements.getPackage(type).getQualifiedName().toString().replaceAll("\\.", "/") + "/" + + templated.stylesheet(); + + throw new GenerationException(path, e1); } + throw new GenerationException( + String.format("Unable to find stylesheet defined at %s", type.getQualifiedName())); } - System.out.println(String.format("Unable to find stylesheet for %s", type.getQualifiedName())); return null; } @@ -399,7 +416,7 @@ private void processType(ClassBuilder builder, TypeElement type, Templated templ String isElementTypeParameter = getIsElementTypeParameter(type.getInterfaces()); String subclass = TypeSimplifier.simpleNameOf(generatedClassName(type, "Templated_", "")); TemplateContext context = new TemplateContext(TypeSimplifier.packageNameOf(type), - TypeSimplifier.classNameOf(type), subclass, isElementTypeParameter, "qwertyuiop"); + TypeSimplifier.classNameOf(type), subclass, isElementTypeParameter, type.asType()); // root element and template TemplateSelector templateSelector = getTemplateSelector(type, templated); org.jsoup.nodes.Element root = parseTemplate(type, templateSelector); @@ -425,104 +442,181 @@ private void code(ClassBuilder builder, TemplateContext templateContext) { addImports(builder); generateWrapper(builder, templateContext); setStylesheet(builder, templateContext); + + addInitTemplateCallMethod(builder); + maybeInitWidgets(builder, templateContext); + processDataFields(builder, templateContext); // maybeInitWidgets(builder, templateContext); processEventHandlers(builder, templateContext); } - /* - * private void maybeInitWidgets(ClassBuilder builder, TemplateContext templateContext) { - * List widgets = templateContext.getDataElements() .stream() .filter(elm -> - * elm.getKind().equals(DataElementInfo.Kind.IsWidget)) .collect(Collectors.toList()); if - * (!widgets.isEmpty()) { builder.getClassCompilationUnit().addImport(List.class); - * builder.getClassCompilationUnit().addImport(ArrayList.class); - * - * ExpressionStmt expressionStmt = new ExpressionStmt(); VariableDeclarationExpr - * variableDeclarationExpr = new VariableDeclarationExpr(); - * - * VariableDeclarator variableDeclarator = new VariableDeclarator(); - * variableDeclarator.setName("widgets"); - * - * ClassOrInterfaceType list = new ClassOrInterfaceType().setName(List.class.getSimpleName()); - * ClassOrInterfaceType arrayList = new - * ClassOrInterfaceType().setName(ArrayList.class.getSimpleName()); list.setTypeArguments(new - * ClassOrInterfaceType().setName(Widget.class.getSimpleName())); - * - * variableDeclarator.setType(list); variableDeclarator.setInitializer(new - * ObjectCreationExpr().setType(arrayList)); - * variableDeclarationExpr.getVariables().add(variableDeclarator); - * - * expressionStmt.setExpression(variableDeclarationExpr); - * - * builder.getGetMethodDeclaration() .getBody() .get() .addAndGetStatement(expressionStmt); - * - * widgets.forEach(widget -> { FieldAccessExpr instance = new FieldAccessExpr( new - * FieldAccessExpr( new ThisExpr(), "instance"), widget.getName()); - * - * MethodCallExpr methodCallExpr = new MethodCallExpr(new NameExpr("widgets"), "add") - * .addArgument(instance); - * - * builder.getGetMethodDeclaration() .getBody() .get().addAndGetStatement(methodCallExpr); }); - * - * MethodCallExpr doInit = new MethodCallExpr(new ClassOrInterfaceType() - * .setName("TemplateUtil").getNameAsExpression(), "initTemplated") - * .addArgument(Js.class.getCanonicalName() + ".uncheckedCast(this.instance.element())") - * .addArgument("widgets"); - * - * builder.getGetMethodDeclaration() .getBody() .get().addAndGetStatement(doInit); } } - */ + + private void maybeInitWidgets(ClassBuilder builder, TemplateContext templateContext) { + List widgets = templateContext.getDataElements().stream() + .filter(elm -> elm.getKind().equals(DataElementInfo.Kind.IsWidget)) + .collect(Collectors.toList()); + if (!widgets.isEmpty()) { + builder.getClassCompilationUnit().addImport(List.class); + builder.getClassCompilationUnit().addImport(ArrayList.class); + + ExpressionStmt expressionStmt = new ExpressionStmt(); + VariableDeclarationExpr variableDeclarationExpr = new VariableDeclarationExpr(); + + VariableDeclarator variableDeclarator = new VariableDeclarator(); + variableDeclarator.setName("widgets"); + + ClassOrInterfaceType list = new ClassOrInterfaceType().setName(List.class.getSimpleName()); + ClassOrInterfaceType arrayList = + new ClassOrInterfaceType().setName(ArrayList.class.getSimpleName()); + list.setTypeArguments( + new ClassOrInterfaceType().setName("org.gwtproject.user.client.ui.Widget")); + + variableDeclarator.setType(list); + variableDeclarator.setInitializer(new ObjectCreationExpr().setType(arrayList)); + variableDeclarationExpr.getVariables().add(variableDeclarator); + + expressionStmt.setExpression(variableDeclarationExpr); + + builder.getInitInstanceMethod().getBody().get().addAndGetStatement(expressionStmt); + + widgets.forEach(widget -> { + Expression instance = + new MethodCallExpr(new NameExpr(Js.class.getCanonicalName()), "uncheckedCast") + .addArgument(getFieldAccessCallExpr(widget.getName())); + + MethodCallExpr methodCallExpr = + new MethodCallExpr(new NameExpr("widgets"), "add").addArgument(instance); + builder.getInitInstanceMethod().getBody().get().addAndGetStatement(methodCallExpr); + }); + + DataElementInfo.Kind kind = getDataElementInfoKind(templateContext.getDataElementType()); + Expression instance = getInstanceMethodName(kind); + + MethodCallExpr doInit; + + if (kind.equals(DataElementInfo.Kind.IsWidget)) { + doInit = new MethodCallExpr(new ClassOrInterfaceType() + .setName("org.gwtproject.user.client.ui.TemplateWidget").getNameAsExpression(), + "initTemplated").addArgument(new NameExpr("instance")) + .addArgument(new FieldAccessExpr(new NameExpr("instance"), "root")) + .addArgument("widgets"); + } else { + doInit = new MethodCallExpr(new ClassOrInterfaceType() + .setName("org.gwtproject.user.client.ui.TemplateWidget").getNameAsExpression(), + "initTemplated") + .addArgument(Js.class.getCanonicalName() + ".uncheckedCast(" + instance + ")") + .addArgument("widgets"); + } + + builder.getInitInstanceMethod().getBody().get().addAndGetStatement(doInit); + } + } + private void generateWrapper(ClassBuilder builder, TemplateContext templateContext) { ClassOrInterfaceDeclaration wrapper = new ClassOrInterfaceDeclaration(); - wrapper.setName(beanDefinition.getClassName()); + wrapper.setName(MoreTypes.asTypeElement(beanDefinition.getType()).getSimpleName().toString()); wrapper.addExtendedType(beanDefinition.getQualifiedName()); wrapper.setModifier(com.github.javaparser.ast.Modifier.Keyword.FINAL, true); String element = getElementFromTag(templateContext); - wrapper.addFieldWithInitializer(element, "root", - new CastExpr(new ClassOrInterfaceType().setName(element), - new MethodCallExpr( - new FieldAccessExpr(new NameExpr("elemental2.dom.DomGlobal"), "document"), - "createElement") - .addArgument(new StringLiteralExpr(templateContext.getRoot().getTag()))), - com.github.javaparser.ast.Modifier.Keyword.PRIVATE, - com.github.javaparser.ast.Modifier.Keyword.FINAL); + wrapper.addField(element, "root", com.github.javaparser.ast.Modifier.Keyword.PRIVATE); ConstructorDeclaration constructor = wrapper.addConstructor(com.github.javaparser.ast.Modifier.Keyword.PUBLIC); - if (beanDefinition.getConstructorInjectionPoint() != null) { + if (beanDefinition.getConstructorParams() != null) { List args = new LinkedList<>(); - for (FieldPoint argument : beanDefinition.getConstructorInjectionPoint().getArguments()) { - constructor.addAndGetParameter(argument.getType().getQualifiedName().toString(), - argument.getName()); - args.add(argument.getName()); + for (InjectionParameterDefinition argument : beanDefinition.getConstructorParams()) { + constructor.addAndGetParameter(MoreTypes + .asTypeElement(argument.getVariableElement().asType()).getQualifiedName().toString(), + argument.getVariableElement().getSimpleName().toString()); + args.add(argument.getVariableElement().getSimpleName().toString()); } StringJoiner joiner = new StringJoiner(","); args.stream().forEach(joiner::add); - constructor.getBody().addStatement("super(" + joiner.toString() + ");"); + constructor.getBody().addStatement("super(" + joiner + ");"); } - setAttributes(constructor.getBody(), templateContext); - setInnerHTML(constructor.getBody(), templateContext); - addElementMethod(wrapper, templateContext); + DataElementInfo.Kind dataElementInfo = getDataElementInfoKind(beanDefinition.getType()); + + addElementMethod(wrapper, templateContext, dataElementInfo); + addInitMethod(wrapper, templateContext, dataElementInfo); builder.getClassDeclaration().addMember(wrapper); } private void addElementMethod(ClassOrInterfaceDeclaration wrapper, - TemplateContext templateContext) { - String element = getElementFromTag(templateContext); + TemplateContext templateContext, DataElementInfo.Kind kind) { + String element = getElementFromTag(templateContext); + Expression root; MethodDeclaration method = - wrapper.addMethod("element", com.github.javaparser.ast.Modifier.Keyword.PUBLIC); - method.addAnnotation(Override.class); - method.setType(element); - ReturnStmt _return = new ReturnStmt(new CastExpr(new ClassOrInterfaceType().setName(element), - new FieldAccessExpr(new ThisExpr(), "root"))); + wrapper.addMethod(getMethodName(kind), com.github.javaparser.ast.Modifier.Keyword.PUBLIC); + if (!kind.equals(DataElementInfo.Kind.IsWidget)) { + method.addAnnotation(Override.class); + method.setType(element); + root = new FieldAccessExpr(new ThisExpr(), "root"); + } else { + method.setType(HTMLElement.class.getCanonicalName()); + root = uncheckedCastCall(asWidgetGetElementCall(new ThisExpr()), + HTMLElement.class.getCanonicalName()); + + } + + ReturnStmt _return = + new ReturnStmt(new CastExpr(new ClassOrInterfaceType().setName(element), root)); method.getBody().get().addStatement(_return); } + private Expression asWidgetCall(Expression target) { + return new MethodCallExpr(target, "asWidget"); + } + + private Expression asWidgetGetElementCall(Expression target) { + return new MethodCallExpr(asWidgetCall(target), "getElement"); + } + + private Expression uncheckedCastCall(Expression target, String clazz) { + return new MethodCallExpr(new NameExpr(Js.class.getCanonicalName()), + "<" + clazz + ">uncheckedCast").addArgument(target); + } + + private void addInitMethod(ClassOrInterfaceDeclaration wrapper, TemplateContext templateContext, + DataElementInfo.Kind kind) { + String element = getElementFromTag(templateContext); + + MethodDeclaration method = wrapper.addMethod("_setAndInitTemplate", + com.github.javaparser.ast.Modifier.Keyword.PRIVATE); + + MethodCallExpr methodCallExpr = getDataFieldFieldAccessCallExpr(templateContext); + + Expression root = new FieldAccessExpr(new ThisExpr(), "root"); + method.getBody().get().addStatement(new AssignExpr().setTarget(root) + .setValue(new CastExpr(new ClassOrInterfaceType().setName(element), methodCallExpr))); + + setAttributes(method.getBody().get(), templateContext); + setInnerHTML(method.getBody().get(), templateContext); + + + } + + private MethodCallExpr getDataFieldFieldAccessCallExpr(TemplateContext templateContext) { + if (templateContext.getRoot().getDataField().isPresent()) { + String dataField = templateContext.getRoot().getDataField().get().getValue(); + java.util.Optional dataElementInfo = templateContext.getDataElements() + .stream().filter(e -> e.getSelector().equals(dataField)).findFirst(); + if (dataElementInfo.isPresent()) { + MethodCallExpr expr = getFieldAccessCallExpr(dataElementInfo.get().getName()); + return expr; + } + } + return new MethodCallExpr( + new FieldAccessExpr(new NameExpr("elemental2.dom.DomGlobal"), "document"), "createElement") + .addArgument(new StringLiteralExpr(templateContext.getRoot().getTag())); + } + private void setStylesheet(ClassBuilder builder, TemplateContext templateContext) { if (templateContext.getStylesheet() != null) { builder.getClassCompilationUnit().addImport(StyleInjector.class); @@ -533,44 +627,45 @@ private void setStylesheet(ClassBuilder builder, TemplateContext templateContext * builder.getClassCompilationUnit().addImport(CssResource.NotStrict.class); * builder.getClassCompilationUnit().addImport(Resource.class); * builder.getClassCompilationUnit().addImport(ClientBundle.Source.class); - * + * * ClassOrInterfaceDeclaration inner = new ClassOrInterfaceDeclaration(); * inner.setName("Stylesheet"); inner.setInterface(true); inner.addAnnotation("Resource"); - * + * * new JavaParser().parseBodyDeclaration("@Source(\"" + * templateContext.getStylesheet().getStyle() + * "\") @NotStrict CssResource getStyle();").ifSuccessful(inner::addMember); * builder.getClassDeclaration().addMember(inner); - * + * * String theName = Utils.getFactoryClassName(beanDefinition.getType()) + "_StylesheetImpl"; */ String css; try { - css = FileUtils.readFileToString(templateContext.getStylesheet().getFile(), - StandardCharsets.UTF_8); + css = + IOUtils.toString(templateContext.getStylesheet().getFile(), Charset.defaultCharset()); } catch (IOException e) { throw new GenerationException( - "Unable to process Css/Gss :" + templateContext.getStylesheet()); + "Unable to process Css/Gss :" + templateContext.getStylesheet(), e); } // TODO Temporary workaround, till gwt-dom StyleInjector ll be fixed - builder.getGetMethodDeclaration().getBody().get() + builder.getInitInstanceMethod().getBody().get() .addStatement(new MethodCallExpr(new MethodCallExpr( new ClassOrInterfaceType().setName("StyleInjector").getNameAsExpression(), "fromString").addArgument(new StringLiteralExpr(escape(css))), "inject")); } else { try { - final LessSource source = new LessSource(templateContext.getStylesheet().getFile()); - final LessCompiler compiler = new LessCompiler(); - final String compiledCss = compiler.compile(source); - builder.getGetMethodDeclaration().getBody().get() + String less = + IOUtils.toString(templateContext.getStylesheet().getFile(), Charset.defaultCharset()); + Less.compile(null, less, false); + final String compiledCss = Less.compile(null, less, false); + builder.getInitInstanceMethod().getBody().get() .addStatement(new MethodCallExpr( new MethodCallExpr( new ClassOrInterfaceType().setName("StyleInjector").getNameAsExpression(), "fromString").addArgument(new StringLiteralExpr(escape(compiledCss))), "inject")); - } catch (LessException | IOException e) { + } catch (IOException e) { throw new GenerationException( "Unable to process Less " + templateContext.getStylesheet()); } @@ -578,30 +673,53 @@ private void setStylesheet(ClassBuilder builder, TemplateContext templateContext } } + private void addInitTemplateCallMethod(ClassBuilder builder) { + builder.addField(MoreTypes.asTypeElement(beanDefinition.getType()).getSimpleName().toString(), + "instance", com.github.javaparser.ast.Modifier.Keyword.PRIVATE); + + builder.getInitInstanceMethod().getBody().get() + .addAndGetStatement(new MethodCallExpr(new NameExpr("instance"), "_setAndInitTemplate")); + } + + private Expression getInstanceCallExpression(TemplateContext templateContext) { + DataElementInfo.Kind kind = getDataElementInfoKind(templateContext.getDataElementType()); + Expression instance = getInstanceMethodName(kind); + + if (kind.equals(DataElementInfo.Kind.IsWidget)) { + instance = uncheckedCastCall(instance, HTMLElement.class.getCanonicalName()); + } + return instance; + } + private void processDataFields(ClassBuilder builder, TemplateContext templateContext) { + Expression instance = getInstanceCallExpression(templateContext); + templateContext.getDataElements().forEach(element -> { MethodCallExpr resolveElement; MethodCallExpr fieldAccessCallExpr = getFieldAccessCallExpr(element.getName()); IfStmt ifStmt = new IfStmt().setCondition( new BinaryExpr(fieldAccessCallExpr, new NullLiteralExpr(), BinaryExpr.Operator.EQUALS)); + + if (element.needsCast()) { resolveElement = new MethodCallExpr( new ClassOrInterfaceType().setName("TemplateUtil").getNameAsExpression(), "resolveElementAs") .setTypeArguments(new ClassOrInterfaceType().setName(element.getType())) - .addArgument("this.instance.element()") - .addArgument(new StringLiteralExpr(element.getSelector())); + .addArgument(instance).addArgument(new StringLiteralExpr(element.getSelector())); } else { resolveElement = new MethodCallExpr( new ClassOrInterfaceType().setName("TemplateUtil").getNameAsExpression(), - "resolveElement").addArgument("this.instance.element()") + "resolveElement").addArgument(instance) .addArgument(new StringLiteralExpr(element.getName())); } MethodCallExpr fieldSetCallExpr = null; if (iocContext.getGenerationContext().isGwt2()) { - fieldSetCallExpr = new MethodCallExpr(new NameExpr(beanDefinition.getClassName() + "Info"), + fieldSetCallExpr = new MethodCallExpr( + new NameExpr( + MoreTypes.asTypeElement(beanDefinition.getType()).getQualifiedName() + "Info"), element.getName()).addArgument("instance"); } else if (!iocContext.getGenerationContext().isJre()) { fieldSetCallExpr = new MethodCallExpr( @@ -618,13 +736,38 @@ private void processDataFields(ClassBuilder builder, TemplateContext templateCon new BlockStmt().addAndGetStatement(fieldSetCallExpr.addArgument(resolveElement))); ifStmt.setElseStmt(new BlockStmt().addAndGetStatement(new MethodCallExpr( new ClassOrInterfaceType().setName("TemplateUtil").getNameAsExpression(), - "replaceElement").addArgument("this.instance.element()") + "replaceElement").addArgument(instance) .addArgument(new StringLiteralExpr(element.getSelector())) .addArgument(getInstanceByElementKind(element, fieldAccessCallExpr)))); - builder.getGetMethodDeclaration().getBody().get().addAndGetStatement(ifStmt); + builder.getInitInstanceMethod().getBody().get().addAndGetStatement(ifStmt); }); } + private Expression getInstanceMethodName(DataElementInfo.Kind kind) { + MethodCallExpr expr = + new MethodCallExpr(new FieldAccessExpr(new ThisExpr(), "instance"), getMethodName(kind)); + if (kind.equals(DataElementInfo.Kind.IsWidget)) { + uncheckedCastCall(expr, isWidget.toString()); + } + return expr; + } + + private String getMethodName(DataElementInfo element) { + return getMethodName(element.getKind()); + } + + private String getMethodName(DataElementInfo.Kind kind) { + if (kind.equals(DataElementInfo.Kind.ElementoIsElement) + || kind.equals(DataElementInfo.Kind.HTMLElement)) { + return "element"; + } else if (kind.equals(DataElementInfo.Kind.CrysknifeIsElement)) { + return "getElement"; + } else if (kind.equals(DataElementInfo.Kind.IsWidget)) { + return "getIsWidgetElement"; + } + throw new GenerationException("Unable to find type of " + kind); + } + private MethodCallExpr getFieldAccessCallExpr(String fieldName) { VariableElement field = getVariableElement(fieldName); return getFieldAccessCallExpr(field); @@ -632,7 +775,9 @@ private MethodCallExpr getFieldAccessCallExpr(String fieldName) { private MethodCallExpr getFieldAccessCallExpr(VariableElement field) { if (iocContext.getGenerationContext().isGwt2()) { - return new MethodCallExpr(new NameExpr(beanDefinition.getClassName() + "Info"), + return new MethodCallExpr( + new NameExpr( + MoreTypes.asTypeElement(beanDefinition.getType()).getQualifiedName() + "Info"), field.getSimpleName().toString()).addArgument("instance"); } @@ -646,31 +791,38 @@ private MethodCallExpr getFieldAccessCallExpr(VariableElement field) { } private Expression getInstanceByElementKind(DataElementInfo element, Expression instance) { - if (element.getKind().equals(DataElementInfo.Kind.IsElement)) { + if (element.getKind().equals(DataElementInfo.Kind.ElementoIsElement)) { instance = new MethodCallExpr( new EnclosedExpr(new CastExpr( new ClassOrInterfaceType().setName(IsElement.class.getCanonicalName()), instance)), "element"); - } /* - * else if (element.getKind() .equals(DataElementInfo.Kind.IsWidget)) { - * - * return new MethodCallExpr(new NameExpr(Js.class.getCanonicalName()), "<" + - * HTMLElement.class.getCanonicalName() + ">uncheckedCast") .addArgument(new MethodCallExpr( - * new EnclosedExpr( new CastExpr( new - * ClassOrInterfaceType().setName(UIObject.class.getCanonicalName()), instance)), - * "getElement")); } - */ + } else if (element.getKind().equals(DataElementInfo.Kind.CrysknifeIsElement)) { + instance = new MethodCallExpr( + new EnclosedExpr(new CastExpr(new ClassOrInterfaceType() + .setName(io.crysknife.client.IsElement.class.getCanonicalName()), instance)), + "getElement"); + } else if (element.getKind().equals(DataElementInfo.Kind.IsWidget)) { + return new MethodCallExpr(new NameExpr(Js.class.getCanonicalName()), + "<" + HTMLElement.class.getCanonicalName() + ">uncheckedCast") + .addArgument( + new MethodCallExpr( + new EnclosedExpr(new CastExpr(new ClassOrInterfaceType() + .setName("org.gwtproject.user.client.ui.UIObject"), instance)), + "getElement")); + } + return new EnclosedExpr(new CastExpr( new ClassOrInterfaceType().setName(HTMLElement.class.getCanonicalName()), instance)); } private VariableElement getVariableElement(String elementName) { - return beanDefinition.getType().getEnclosedElements().stream() + return MoreTypes.asTypeElement(beanDefinition.getType()).getEnclosedElements().stream() .filter(elm -> elm.getKind().equals(ElementKind.FIELD)) .filter(elm -> elm.getSimpleName().toString().equals(elementName)) - .map(elm -> MoreElements.asVariable(elm)).findFirst().orElseThrow(() -> new Error( - "Unable to find @DataField " + elementName + " in " + beanDefinition.getClassName())); + .map(elm -> MoreElements.asVariable(elm)).findFirst() + .orElseThrow(() -> new Error("Unable to find @DataField " + elementName + " in " + + MoreTypes.asTypeElement(beanDefinition.getType()).getQualifiedName())); } private void processEventHandlers(ClassBuilder builder, TemplateContext templateContext) { @@ -684,7 +836,7 @@ private void processEventHandlers(ClassBuilder builder, TemplateContext template .addArgument(new NameExpr("e -> this.instance." + event.getMethodName() + "(jsinterop.base.Js.uncheckedCast(e))")); - builder.getGetMethodDeclaration().getBody().get().addAndGetStatement(methodCallExpr); + builder.getInitInstanceMethod().getBody().get().addAndGetStatement(methodCallExpr); } }); } @@ -697,9 +849,14 @@ private void addImports(ClassBuilder builder) { } private void setInnerHTML(BlockStmt block, TemplateContext templateContext) { - block.addAndGetStatement(new AssignExpr() - .setTarget(new FieldAccessExpr(new FieldAccessExpr(new ThisExpr(), "root"), "innerHTML")) - .setValue(new StringLiteralExpr(templateContext.getRoot().getInnerHtml()))); + + if (templateContext.getRoot().getInnerHtml() != null + && !templateContext.getRoot().getInnerHtml().isEmpty()) { + + block.addAndGetStatement(new AssignExpr() + .setTarget(new FieldAccessExpr(new FieldAccessExpr(new ThisExpr(), "root"), "innerHTML")) + .setValue(new StringLiteralExpr(templateContext.getRoot().getInnerHtml()))); + } } private void setAttributes(BlockStmt block, TemplateContext templateContext) { @@ -763,7 +920,8 @@ private List processDataElements(TypeElement type, // verify method if (method.getModifiers().contains(Modifier.PRIVATE)) { - abortWithError(method, "@%s method must not be private", + abortWithError(method, + "@%s method must not be private " + method.getEnclosingElement() + ".", DataField.class.getSimpleName()); } if (method.getModifiers().contains(Modifier.STATIC)) { @@ -853,6 +1011,8 @@ private List processEventHandlers(TypeElement type, .getTypeElement(Event.class.getCanonicalName()); if (!iocContext.getGenerationContext().getTypes().isSubtype(declaredType, event.asType()) + && !(GWT3_Event != null && iocContext.getGenerationContext().getTypes() + .isSubtype(declaredType, GWT3_Event.asType())) && !EVENTS.containsKey(declaredType.toString())) { abortWithError(method.getEnclosingElement(), "@%s method must have only one parameter and this parameter must be type or subtype of " @@ -909,9 +1069,15 @@ private void verifyHTMLElement(String htmlType, String selector, Element element private void verifySelector(String selector, Element element, TemplateSelector templateSelector, org.jsoup.nodes.Element root) { // make sure to use the same logic for finding matching elements as in TemplateUtils! + + if (root.getElementById(selector) != null) { + return; + } + Elements elements = root.getElementsByAttributeValue("data-field", selector); long matchCount = elements.stream() .filter(elem -> elem.attributes().getIgnoreCase("data-element").equals(selector)).count(); + if (elements.isEmpty() && matchCount == 0) { abortWithError(element, "Cannot find a matching element in %s using \"[data-field=%s]\" as selector", @@ -926,15 +1092,32 @@ private void verifySelector(String selector, Element element, TemplateSelector t private DataElementInfo.Kind getDataElementInfoKind(TypeMirror dataElementType) { if (isAssignable(dataElementType, HTMLElement.class)) { return DataElementInfo.Kind.HTMLElement; + } else if (isAssignable(dataElementType, io.crysknife.client.IsElement.class)) { + return DataElementInfo.Kind.CrysknifeIsElement; } else if (isAssignable(dataElementType, IsElement.class)) { - return DataElementInfo.Kind.IsElement; - // } else if (isAssignable(dataElementType, IsWidget.class)) { - // return DataElementInfo.Kind.IsWidget; + return DataElementInfo.Kind.ElementoIsElement; + } else if (maybeGwtWidget(dataElementType)) { + return DataElementInfo.Kind.IsWidget; + } else if (maybeGwtDom(dataElementType)) { + return DataElementInfo.Kind.GWT_DOM; } else { return DataElementInfo.Kind.Custom; } } + private boolean maybeGwtWidget(TypeMirror dataElementType) { + if (isWidget == null) { + return false; + } + return isAssignable(dataElementType, isWidget.asType()); + } + + private boolean maybeGwtDom(TypeMirror dataElementType) { + TypeElement element = iocContext.getGenerationContext().getElements() + .getTypeElement("org.gwtproject.dom.client.Element"); + return isAssignable(dataElementType, element.asType()); + } + private String getSelector(Element element) { String selector = null; @@ -980,9 +1163,8 @@ private org.jsoup.nodes.Element parseTemplate(TypeElement type, abortWithError(type, "Cannot find template \"%s\". Please make sure the template exists.", fqTemplate); } - Document document = Jsoup.parse(IOUtils.toString( - iocContext.getGenerationContext().getResourceOracle().findResource(fqTemplate), - Charset.defaultCharset())); + String html = IOUtils.toString(url, Charset.defaultCharset()); + Document document = Jsoup.parse(html); if (templateSelector.hasSelector()) { String query = "[data-field=" + templateSelector.selector + "]"; Elements selector = document.select(query); @@ -1043,9 +1225,12 @@ private void validateType(TypeElement type, Templated templated) { abortWithError(type, "@%s may not be used to implement an annotation interface", Templated.class.getSimpleName()); } - if (!isAssignable(type, IsElement.class)) { - abortWithError(type, "%s must implement %s", type.getSimpleName(), - IsElement.class.getSimpleName()); + if (!(isAssignable(type, IsElement.class) + || isAssignable(type, io.crysknife.client.IsElement.class) + || maybeGwtWidget(type.asType()))) { + abortWithError(type, "%s must implement %s", type.getQualifiedName(), + (IsElement.class.getCanonicalName() + " or " + + io.crysknife.client.IsElement.class.getCanonicalName() + " or " + isWidget)); } } diff --git a/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/DataElementInfo.java b/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/DataElementInfo.java index 7a7586d1..1e147277 100644 --- a/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/DataElementInfo.java +++ b/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/DataElementInfo.java @@ -21,7 +21,7 @@ public class DataElementInfo { public enum Kind { // Name them after the related type for nicer error messages - HTMLElement, IsElement, IsWidget, Custom + HTMLElement, CrysknifeIsElement, ElementoIsElement, IsWidget, Custom, GWT_DOM } private final String type; diff --git a/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/RootElementInfo.java b/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/RootElementInfo.java index 966a39c5..5d876cce 100644 --- a/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/RootElementInfo.java +++ b/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/RootElementInfo.java @@ -16,20 +16,24 @@ import java.util.List; import java.util.Map; +import java.util.Optional; import org.jsoup.nodes.Attribute; public class RootElementInfo { private final String tag; + private final java.util.Optional dataField; private final String member; private final List attributes; private final String innerHtml; private final Map expressions; - public RootElementInfo(final String tag, final String member, final List attributes, - final String innerHtml, final Map expressions) { + public RootElementInfo(final String tag, final java.util.Optional dataField, + final String member, final List attributes, final String innerHtml, + final Map expressions) { this.tag = tag; + this.dataField = dataField; this.member = member; this.attributes = attributes; this.innerHtml = innerHtml; @@ -38,7 +42,9 @@ public RootElementInfo(final String tag, final String member, final List" + member + ":" + attributes; + return "RootElementInfo{" + "tag='" + tag + '\'' + ", member='" + member + '\'' + + ", attributes=" + attributes + ", innerHtml='" + innerHtml + '\'' + ", expressions=" + + expressions + '}'; } public List getAttributes() { @@ -60,4 +66,8 @@ public String getTag() { public Map getExpressions() { return expressions; } + + public Optional getDataField() { + return dataField; + } } diff --git a/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/StyleSheet.java b/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/StyleSheet.java index 88e858c7..c375d44f 100644 --- a/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/StyleSheet.java +++ b/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/StyleSheet.java @@ -14,7 +14,7 @@ package org.jboss.gwt.elemento.processor.context; -import java.io.File; +import java.net.URL; /** * @author Dmitrii Tikhomirov Created by treblereel 6/2/19 @@ -22,9 +22,9 @@ public class StyleSheet { private String style; - private File file; + private URL file; - public StyleSheet(String style, File file) { + public StyleSheet(String style, URL file) { this.style = style; this.file = file; @@ -34,7 +34,7 @@ public String getStyle() { return style; } - public File getFile() { + public URL getFile() { return file; } diff --git a/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/TemplateContext.java b/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/TemplateContext.java index 3d8cf923..a4c65814 100644 --- a/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/TemplateContext.java +++ b/ui/templates/generator/src/main/java/org/jboss/gwt/elemento/processor/context/TemplateContext.java @@ -14,6 +14,7 @@ package org.jboss.gwt.elemento.processor.context; +import javax.lang.model.type.TypeMirror; import java.util.List; public class TemplateContext { @@ -22,7 +23,7 @@ public class TemplateContext { private final String base; private final String subclass; private final String isElementTypeParameter; - private final String inject; + private final TypeMirror dataElementType; private RootElementInfo root; private StyleSheet stylesheet; @@ -32,12 +33,12 @@ public class TemplateContext { private List events; public TemplateContext(String pkg, String base, String subclass, String isElementTypeParameter, - String inject) { + TypeMirror dataElementType) { this.pkg = pkg; this.base = base; this.subclass = subclass; this.isElementTypeParameter = isElementTypeParameter; - this.inject = inject; + this.dataElementType = dataElementType; } @Override @@ -53,10 +54,6 @@ public String getPackage() { return pkg; } - public String getInject() { - return inject; - } - public RootElementInfo getRoot() { return root; } @@ -112,4 +109,8 @@ public List getEvents() { public void setEvents(List events) { this.events = events; } + + public TypeMirror getDataElementType() { + return dataElementType; + } }