This is an automated email from the ASF dual-hosted git repository.

rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openwebbeans.git

commit 1cde3d95b6407f8bfd553cfd25baf9a236760edf
Author: Romain Manni-Bucau <rmannibu...@gmail.com>
AuthorDate: Sun Jun 14 20:48:16 2020 +0200

    [OWB-1330] extract Cdi parameter resolver in its own extension
---
 .../java/org/apache/openwebbeans/junit5/Cdi.java   |  26 ++---
 .../openwebbeans/junit5/CdiMethodParameters.java   |  39 +++++++
 .../org/apache/openwebbeans/junit5/SkipInject.java |  36 ++++++
 .../openwebbeans/junit5/internal/CdiExtension.java |  63 +---------
 .../internal/CdiParametersResolverExtension.java   | 129 +++++++++++++++++++++
 .../junit5/CdiParameterResolversTest.java          |  96 +++++++++++++++
 6 files changed, 316 insertions(+), 73 deletions(-)

diff --git 
a/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/Cdi.java 
b/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/Cdi.java
index c6f6f2d..c5c7d7b 100644
--- a/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/Cdi.java
+++ b/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/Cdi.java
@@ -23,14 +23,11 @@ import org.junit.jupiter.api.extension.ExtendWith;
 
 import java.io.Closeable;
 import java.lang.annotation.Annotation;
-import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 import java.util.function.Supplier;
-import javax.inject.Qualifier;
 
 import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 /**
@@ -79,20 +76,14 @@ public @interface Cdi
     Class<?>[] recursivePackages() default {};
 
     /**
-     * @return if the automatic scanning must be disabled.
+     * @return SeContainer properties.
      */
-    boolean disableDiscovery() default false;
+    Property[] properties() default {};
 
     /**
-     * When present on a test method parameter, it will <em>not</em> be 
attempted to be resolved with a CDI bean.
+     * @return if the automatic scanning must be disabled.
      */
-    @Qualifier
-    @Target(PARAMETER)
-    @Retention(RUNTIME)
-    @Documented
-    @interface DontInject
-    {
-    }
+    boolean disableDiscovery() default false;
 
     /**
      * @return an array of callback to call before the container starts.
@@ -113,4 +104,13 @@ public @interface Cdi
     interface OnStart extends Supplier<Closeable>
     {
     }
+
+    /**
+     * A property set in SeContainer (as String).
+     */
+    @interface Property
+    {
+        String name();
+        String value();
+    }
 }
diff --git 
a/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/CdiMethodParameters.java
 
b/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/CdiMethodParameters.java
new file mode 100644
index 0000000..89e07f1
--- /dev/null
+++ 
b/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/CdiMethodParameters.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.openwebbeans.junit5;
+
+import org.apache.openwebbeans.junit5.internal.CdiParametersResolverExtension;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Enables method parameter injection using CDI lookups.
+ */
+@Target({TYPE, METHOD})
+@Retention(RUNTIME)
+@ExtendWith(CdiParametersResolverExtension.class)
+public @interface CdiMethodParameters
+{
+}
diff --git 
a/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/SkipInject.java 
b/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/SkipInject.java
new file mode 100644
index 0000000..b9b1af3
--- /dev/null
+++ 
b/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/SkipInject.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.openwebbeans.junit5;
+
+import javax.inject.Qualifier;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Qualifier you can put in method parameters to prevent the injection (adding 
an unresolved qualifier).
+ */
+@Qualifier
+@Target(PARAMETER)
+@Retention(RUNTIME)
+public @interface SkipInject
+{
+}
diff --git 
a/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/internal/CdiExtension.java
 
b/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/internal/CdiExtension.java
index 0dfe9ed..c5852c0 100644
--- 
a/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/internal/CdiExtension.java
+++ 
b/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/internal/CdiExtension.java
@@ -24,33 +24,24 @@ import org.junit.jupiter.api.extension.AfterEachCallback;
 import org.junit.jupiter.api.extension.BeforeAllCallback;
 import org.junit.jupiter.api.extension.BeforeEachCallback;
 import org.junit.jupiter.api.extension.ExtensionContext;
-import org.junit.jupiter.api.extension.ParameterContext;
-import org.junit.jupiter.api.extension.ParameterResolutionException;
-import org.junit.jupiter.api.extension.ParameterResolver;
 import org.junit.platform.commons.util.AnnotationUtils;
 
 import javax.enterprise.context.spi.CreationalContext;
 import javax.enterprise.inject.se.SeContainer;
 import javax.enterprise.inject.se.SeContainerInitializer;
 import javax.enterprise.inject.spi.AnnotatedType;
-import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
 import javax.enterprise.inject.spi.InjectionTarget;
 import java.io.Closeable;
 import java.io.IOException;
-import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Parameter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.Objects;
-import java.util.Set;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
 // todo: enhance the setup to be thread safe? see Meecrowave ClassLoaderLock 
class and friends
-public class CdiExtension implements BeforeAllCallback, AfterAllCallback, 
BeforeEachCallback, AfterEachCallback, ParameterResolver
+public class CdiExtension extends CdiParametersResolverExtension implements 
BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback
 {
     private static SeContainer reusableContainer;
 
@@ -93,6 +84,7 @@ public class CdiExtension implements BeforeAllCallback, 
AfterAllCallback, Before
                 
Stream.of(config.packages()).map(Class::getPackage).toArray(Package[]::new));
         initializer.addPackages(true,
                 
Stream.of(config.recursivePackages()).map(Class::getPackage).toArray(Package[]::new));
+        Stream.of(config.properties()).forEach(property -> 
initializer.addProperty(property.name(), property.value()));
         onStop = Stream.of(config.onStarts())
                 .map(it ->
                 {
@@ -110,7 +102,6 @@ public class CdiExtension implements BeforeAllCallback, 
AfterAllCallback, Before
                     }
                 })
                 .peek(Supplier::get)
-                .filter(Objects::nonNull)
                 .toArray(Closeable[]::new);
         SeContainer container = initializer.initialize();
         if (reusable)
@@ -160,6 +151,7 @@ public class CdiExtension implements BeforeAllCallback, 
AfterAllCallback, Before
     @Override
     public void afterEach(final ExtensionContext extensionContext)
     {
+        super.afterEach(extensionContext);
         if (!creationalContexts.isEmpty())
         {
             creationalContexts.forEach(CreationalContext::release);
@@ -194,53 +186,4 @@ public class CdiExtension implements BeforeAllCallback, 
AfterAllCallback, Before
             return reusableContainer;
         }
     }
-
-    @Override
-    public boolean supportsParameter(ParameterContext parameterContext, 
ExtensionContext extensionContext)
-            throws ParameterResolutionException
-    {
-        final SeContainer container = getContainer();
-        if (container == null)
-        {
-            return false;
-        }
-
-        Bean<?> bean = resolveParameterBean(container, parameterContext, 
extensionContext);
-        return bean != null;
-    }
-
-    @Override
-    public Object resolveParameter(ParameterContext parameterContext, 
ExtensionContext extensionContext)
-            throws ParameterResolutionException
-    {
-        final SeContainer container = getContainer();
-        if (container == null)
-        {
-            return false;
-        }
-
-        Bean<?> bean = resolveParameterBean(container, parameterContext, 
extensionContext);
-        BeanManager beanManager = container.getBeanManager();
-        CreationalContext<?> creationalContext = 
beanManager.createCreationalContext(bean);
-        creationalContexts.add(creationalContext);
-        return beanManager.getReference(bean, 
parameterContext.getParameter().getType(), creationalContext);
-    }
-
-    private Bean<?> resolveParameterBean(SeContainer container, 
ParameterContext parameterContext, ExtensionContext extensionContext)
-    {
-        BeanManager beanManager = container.getBeanManager();
-        Set<Bean<?>> beans = beanManager.getBeans(
-                parameterContext.getParameter().getType(),
-                getQualifiers(parameterContext.getParameter()));
-        return beanManager.resolve(beans);
-    }
-
-    private Annotation[] getQualifiers(Parameter parameter)
-    {
-        final BeanManager beanManager = getContainer().getBeanManager();
-        return Arrays.stream(parameter.getAnnotations())
-                .filter(annotation -> 
beanManager.isQualifier(annotation.annotationType()))
-                .toArray(Annotation[]::new);
-    }
-
 }
diff --git 
a/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/internal/CdiParametersResolverExtension.java
 
b/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/internal/CdiParametersResolverExtension.java
new file mode 100644
index 0000000..5bd9c62
--- /dev/null
+++ 
b/webbeans-junit5/src/main/java/org/apache/openwebbeans/junit5/internal/CdiParametersResolverExtension.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.openwebbeans.junit5.internal;
+
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.CDI;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Parameter;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class CdiParametersResolverExtension implements ParameterResolver, 
AfterEachCallback
+{
+    private static final ExtensionContext.Namespace NAMESPACE =
+            
ExtensionContext.Namespace.create(CdiParametersResolverExtension.class.getName());
+
+    @Override
+    public boolean supportsParameter(final ParameterContext parameterContext, 
final ExtensionContext extensionContext)
+            throws ParameterResolutionException
+    {
+        final Instances instances = 
extensionContext.getStore(NAMESPACE).getOrComputeIfAbsent(
+                Instances.class, k -> new Instances(), Instances.class);
+        if (instances != null && instances.instances != null &&
+                
instances.instances.containsKey(parameterContext.getParameter()))
+        {
+            return false; // already handled
+        }
+        try
+        {
+            final Parameter parameter = parameterContext.getParameter();
+            final BeanManager bm = CDI.current().getBeanManager();
+            final Bean<?> bean = resolveParameterBean(bm, parameter);
+            if (bean == null)
+            {
+                return false;
+            }
+            final CreationalContext<Object> creationalContext = 
bm.createCreationalContext(null);
+            final Object instance = bm.getReference(bean, parameter.getType(), 
creationalContext);
+            if (instances.instances == null)
+            {
+                instances.instances = new HashMap<>();
+            }
+            instances.instances.put(parameter, new Instance(instance, 
creationalContext));
+            return true;
+        }
+        catch (final IllegalStateException ise) // no cdi container
+        {
+            return false;
+        }
+    }
+
+    @Override
+    public void afterEach(final ExtensionContext context)
+    {
+        final Instances instances = 
context.getStore(NAMESPACE).get(Instances.class, Instances.class);
+        if (instances != null && instances.instances != null)
+        {
+            instances.instances.values().stream().map(i -> 
i.creationalContext).forEach(CreationalContext::release);
+        }
+    }
+
+    @Override
+    public Object resolveParameter(final ParameterContext parameterContext, 
final ExtensionContext extensionContext)
+            throws ParameterResolutionException
+    {
+        final Instances instances = 
extensionContext.getStore(NAMESPACE).get(Instances.class, Instances.class);
+        if (instances == null || instances.instances == null)
+        {
+            throw new ParameterResolutionException("No matching parameter: " + 
parameterContext.getParameter());
+        }
+        return 
instances.instances.get(parameterContext.getParameter()).instance;
+    }
+
+    private Bean<?> resolveParameterBean(final BeanManager beanManager, final 
Parameter parameter)
+    {
+        final Set<Bean<?>> beans = beanManager.getBeans(parameter.getType(), 
getQualifiers(beanManager, parameter));
+        return beanManager.resolve(beans);
+    }
+
+    private Annotation[] getQualifiers(final BeanManager beanManager, final 
Parameter parameter)
+    {
+        return Arrays.stream(parameter.getAnnotations())
+                .filter(annotation -> 
beanManager.isQualifier(annotation.annotationType()))
+                .toArray(Annotation[]::new);
+    }
+
+    private static class Instance
+    {
+        private final Object instance;
+        private final CreationalContext<?> creationalContext;
+
+        private Instance(final Object instance, final CreationalContext<?> 
creationalContext)
+        {
+            this.instance = instance;
+            this.creationalContext = creationalContext;
+        }
+    }
+
+    private static class Instances
+    {
+        private Map<Parameter, Instance> instances;
+    }
+}
diff --git 
a/webbeans-junit5/src/test/java/org/apache/openwebbeans/junit5/CdiParameterResolversTest.java
 
b/webbeans-junit5/src/test/java/org/apache/openwebbeans/junit5/CdiParameterResolversTest.java
new file mode 100644
index 0000000..73e2309
--- /dev/null
+++ 
b/webbeans-junit5/src/test/java/org/apache/openwebbeans/junit5/CdiParameterResolversTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.openwebbeans.junit5;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.spi.CDI;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@Cdi(classes = CdiParameterResolversTest.SomeBean.class, disableDiscovery = 
true)
+class CdiParameterResolversTest
+{
+    @Test
+    void noParam()
+    {
+        assertNotNull(CDI.current().getBeanManager());
+    }
+
+    @Test
+    @CdiMethodParameters
+    void cdiParam(final SomeBean someBean)
+    {
+        assertNotNull(someBean);
+        assertEquals("yes", someBean.ok());
+        assertTrue(someBean.getClass().getName().contains("$$Owb")); // it is 
cdi proxy
+    }
+
+    @Test
+    @CdiMethodParameters
+    @ExtendWith(CustomParamResolver.class)
+    void mixedParams(final SomeBean cdi, @SkipInject final SomeBean notCdi)
+    {
+        assertNotNull(cdi);
+        assertEquals("yes", cdi.ok());
+        assertEquals("custom", notCdi.ok());
+    }
+
+    @ApplicationScoped
+    public static class SomeBean
+    {
+        public String ok()
+        {
+            return "yes";
+        }
+    }
+
+    public static class CustomParamResolver implements ParameterResolver
+    {
+
+        @Override
+        public boolean supportsParameter(final ParameterContext 
parameterContext,
+                                         final ExtensionContext 
extensionContext) throws ParameterResolutionException
+        {
+            return parameterContext.getIndex() == 1;
+        }
+
+        @Override
+        public Object resolveParameter(final ParameterContext 
parameterContext, final ExtensionContext extensionContext)
+                throws ParameterResolutionException
+        {
+            return new SomeBean()
+            {
+                @Override
+                public String ok()
+                {
+                    return "custom";
+                }
+            };
+        }
+    }
+}

Reply via email to