You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2018/11/30 12:42:28 UTC

[isis] branch v2 updated: ISIS-2039: introduces _CDI (internal API) ...

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

ahuber pushed a commit to branch v2
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/v2 by this push:
     new b71b075  ISIS-2039: introduces _CDI (internal API) ...
b71b075 is described below

commit b71b0753e6ae34ad9ca8fa639fb0ce5f14fff8d9
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Nov 30 13:42:22 2018 +0100

    ISIS-2039: introduces _CDI (internal API) ...
    
    and allows for the ServicesInjector to also inject CDI managed beans
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-2039
---
 .../org/apache/isis/commons/internal/cdi/_CDI.java | 124 +++++++++++++++++++++
 .../apache/isis/commons/internal/cdi/CDITest.java  | 107 ++++++++++++++++++
 .../internal/cdi/ValidQualifierForTesting.java     |  17 +++
 .../org/apache/isis/config/AppConfigLocator.java   |  14 +--
 .../core/metamodel/services/ServicesInjector.java  |   6 +
 5 files changed, 256 insertions(+), 12 deletions(-)

diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java
new file mode 100644
index 0000000..0e26c48
--- /dev/null
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/cdi/_CDI.java
@@ -0,0 +1,124 @@
+/*
+ *  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.isis.commons.internal.cdi;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import javax.enterprise.inject.spi.CDI;
+import javax.inject.Qualifier;
+
+import org.apache.isis.commons.internal.base._NullSafe;
+
+/**
+ * <h1>- internal use only -</h1>
+ * <p>
+ * Framework internal CDI support.
+ * <p>
+ * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/>
+ * These may be changed or removed without notice!
+ *
+ * @since 2.0.0-M2
+ */
+public final class _CDI {
+    
+    /**
+     * Obtains a child Instance for the given required type and additional required qualifiers. 
+     * @param subType
+     * @param qualifiers
+     * @return an optional, empty if passed two instances of the same qualifier type, or an 
+     * instance of an annotation that is not a qualifier type
+     */
+    public static <T> Optional<T> getManagedBean(final Class<T> subType, List<Annotation> qualifiers) {
+        if(_NullSafe.isEmpty(qualifiers)) {
+            return getManagedBean(subType);
+        }
+        
+        final Annotation[] _qualifiers = qualifiers.toArray(new Annotation[] {});
+        
+        return cdi()
+                .map(cdi->tryGet(()->cdi.select(subType, _qualifiers)))
+                .map(instance->tryGet(instance::get));
+    }
+
+    /**
+     * Obtains a child Instance for the given required type and additional required qualifiers. 
+     * @param subType
+     * @param qualifiers
+     * @return an optional, empty if passed two instances of the same qualifier type, or an 
+     * instance of an annotation that is not a qualifier type
+     */
+    public static <T> Optional<T> getManagedBean(final Class<T> subType) {
+        return cdi()
+                .map(cdi->tryGet(()->cdi.select(subType)))
+                .map(instance->tryGet(instance::get));
+    }
+    
+    /**
+     * Get the CDI instance that provides access to the current container. 
+     * @return an optional
+     */
+    public static Optional<CDI<Object>> cdi() {
+        try {
+            CDI<Object> cdi = CDI.current();
+            return Optional.ofNullable(cdi);
+        } catch (Exception e) {
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * Filters the input array into a collection, such that only annotations are retained, 
+     * that are valid qualifiers for CDI.
+     * @param annotations
+     * @return non-null
+     */
+    public static List<Annotation> filterQualifiers(final Annotation[] annotations) {
+        return _NullSafe.stream(annotations)
+        .filter(_CDI::isQualifier)
+        .collect(Collectors.toList());
+    }
+    
+    /**
+     * @param annotation
+     * @return whether or not the annotation is a valid qualifier for CDI
+     */
+    public static boolean isQualifier(Annotation annotation) {
+        if(annotation==null) {
+            return false;
+        }
+        return annotation.annotationType().getAnnotationsByType(Qualifier.class).length>0;
+    }
+    
+    // -- HELPER
+    
+    private _CDI() {}
+    
+    private static <T> T tryGet(final Supplier<T> supplier) {
+        try { 
+            return supplier.get();  
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+}
diff --git a/core/commons/src/test/java/org/apache/isis/commons/internal/cdi/CDITest.java b/core/commons/src/test/java/org/apache/isis/commons/internal/cdi/CDITest.java
new file mode 100644
index 0000000..6365071
--- /dev/null
+++ b/core/commons/src/test/java/org/apache/isis/commons/internal/cdi/CDITest.java
@@ -0,0 +1,107 @@
+package org.apache.isis.commons.internal.cdi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.List;
+
+import javax.annotation.CheckForNull;
+import javax.inject.Inject;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class CDITest {
+
+    private Field stringField1;
+    private Field stringField2;
+    private Field stringField3;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        stringField1 = Customer.class.getDeclaredField("stringField1");
+        stringField2 = Customer.class.getDeclaredField("stringField2");
+        stringField3 = Customer.class.getDeclaredField("stringField3");
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+    }
+
+    // -- STAGED TEST CLASS
+    
+    static class Customer {
+        
+        @Inject  
+        String stringField1;
+        
+        @Inject @CheckForNull //arbitrary non qualifier
+        String stringField2;
+        
+        @Inject @ValidQualifierForTesting
+        String stringField3;
+    }
+    
+    // ---
+    
+    @Test
+    void qualifierDetection() {
+        
+        //when
+        ValidQualifierForTesting[] annotations = stringField3.getAnnotationsByType(ValidQualifierForTesting.class);
+
+        //then
+        assertNotNull(annotations);
+        assertEquals(1, annotations.length);
+        
+        //when 
+        ValidQualifierForTesting annotation = annotations[0];
+        
+        //then
+        assertNotNull(annotation);
+        assertTrue(_CDI.isQualifier(annotation));
+
+    }
+    
+    
+    @Test
+    void noQualifier() {
+        
+        //when
+        List<Annotation> qualifiers = _CDI.filterQualifiers(stringField1.getAnnotations());
+        
+        //then
+        assertNotNull(qualifiers);
+        assertEquals(0, qualifiers.size());
+
+    }
+
+    @Test
+    void noQualifier_arbitraryAnnotation() {
+        
+        //when
+        List<Annotation> qualifiers = _CDI.filterQualifiers(stringField2.getAnnotations());
+        
+        //then
+        assertNotNull(qualifiers);
+        assertEquals(0, qualifiers.size());
+
+    }
+    
+    @Test
+    void singleQualifier() {
+        
+        //when
+        List<Annotation> qualifiers = _CDI.filterQualifiers(stringField3.getAnnotations());
+        
+        //then
+        assertNotNull(qualifiers);
+        assertEquals(1, qualifiers.size());
+
+    }
+    
+}
diff --git a/core/commons/src/test/java/org/apache/isis/commons/internal/cdi/ValidQualifierForTesting.java b/core/commons/src/test/java/org/apache/isis/commons/internal/cdi/ValidQualifierForTesting.java
new file mode 100644
index 0000000..32ac449
--- /dev/null
+++ b/core/commons/src/test/java/org/apache/isis/commons/internal/cdi/ValidQualifierForTesting.java
@@ -0,0 +1,17 @@
+package org.apache.isis.commons.internal.cdi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Qualifier
+@Retention(RUNTIME)
+@Target(FIELD)
+@interface ValidQualifierForTesting {
+    
+
+}
diff --git a/core/config/src/main/java/org/apache/isis/config/AppConfigLocator.java b/core/config/src/main/java/org/apache/isis/config/AppConfigLocator.java
index 74e962d..0abdb01 100644
--- a/core/config/src/main/java/org/apache/isis/config/AppConfigLocator.java
+++ b/core/config/src/main/java/org/apache/isis/config/AppConfigLocator.java
@@ -1,12 +1,11 @@
 package org.apache.isis.config;
 
-import javax.enterprise.inject.spi.CDI;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.isis.applib.AppManifest;
 import org.apache.isis.commons.internal.base._Casts;
+import org.apache.isis.commons.internal.cdi._CDI;
 import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.commons.internal.context._Plugin;
 import org.apache.isis.config.builder.IsisConfigurationBuilder;
@@ -50,16 +49,7 @@ public final class AppConfigLocator {
     }
     
     private static AppConfig lookupAppConfig_UsingCDI() {
-        try {
-            final CDI<Object> cdi = CDI.current();
-            if(cdi==null) {
-                return null;
-            }
-            return cdi.select(AppConfig.class).get();
-        } catch (Exception e) {
-            // ignore
-        }
-        return null;        
+        return _CDI.getManagedBean(AppConfig.class).orElse(null);
     }
     
     private static AppConfig lookupAppConfig_UsingServiceLoader() {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
index 3644dd1..d7cfc36 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java
@@ -37,6 +37,7 @@ import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.base._Strings;
+import org.apache.isis.commons.internal.cdi._CDI;
 import org.apache.isis.commons.internal.collections._Collections;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.commons.internal.collections._Multimaps;
@@ -332,6 +333,11 @@ public class ServicesInjector implements ApplicationScopedComponent, ServiceRegi
                 return;
             }
         }
+        
+        // fallback and try CDI
+        _CDI.getManagedBean(typeToBeInjected, _CDI.filterQualifiers(field.getAnnotations()))
+        .ifPresent(bean->invokeInjectorField(field, object, bean));
+        
     }
 
     private void autowireViaPrefixedMethods(