You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by ar...@apache.org on 2020/09/13 09:22:10 UTC

[openwebbeans] branch master updated: OWB-1349: Use annotated type to check qualifier validation rules

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 4885d0a  OWB-1349: Use annotated type to check qualifier validation rules
4885d0a is described below

commit 4885d0a52b03e5a4c099c102036ff556ab8fa4bc
Author: arne <ar...@apache.org>
AuthorDate: Fri Sep 11 21:16:14 2020 +0200

    OWB-1349: Use annotated type to check qualifier validation rules
---
 .../webbeans/annotation/AnnotationManager.java     |  48 ++++-
 .../component/creation/BeanAttributesBuilder.java  |  18 +-
 .../apache/webbeans/container/BeanManagerImpl.java |   6 +-
 .../org/apache/webbeans/util/AnnotationUtil.java   |   5 +
 .../qualifier/CacheUsesQualifierOverridesTest.java | 205 ++++++++++++++++++++-
 5 files changed, 254 insertions(+), 28 deletions(-)

diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java b/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java
index b5442c4..b934ea9 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java
@@ -28,6 +28,7 @@ import org.apache.webbeans.exception.WebBeansConfigurationException;
 import org.apache.webbeans.util.AnnotationUtil;
 import org.apache.webbeans.util.ArrayUtil;
 import org.apache.webbeans.util.Asserts;
+import org.apache.webbeans.util.ClassUtil;
 
 import javax.enterprise.context.NormalScope;
 import javax.enterprise.inject.Any;
@@ -57,6 +58,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -459,7 +461,7 @@ public final class AnnotationManager
         }
     }
 
-    private void checkQualifierConditions(Annotation ann)
+    public void checkQualifierConditions(Annotation ann)
     {
         if (ann == DefaultLiteral.INSTANCE || ann == AnyLiteral.INSTANCE ||
             ann.annotationType().equals(Default.class) || ann.annotationType().equals(Any.class) ||
@@ -469,17 +471,49 @@ public final class AnnotationManager
             return;
         }
 
-        Method[] methods = webBeansContext.getSecurityService().doPrivilegedGetDeclaredMethods(ann.annotationType());
+        AnnotatedType annotatedType = webBeansContext.getBeanManagerImpl().getAdditionalAnnotatedTypeQualifiers().get(ann.annotationType());
+        if (annotatedType == null)
+        {
+            Iterator<AnnotatedType> annotatedTypes = (Iterator)webBeansContext.getBeanManagerImpl().getAnnotatedTypes(ann.annotationType()).iterator();
+            if (annotatedTypes.hasNext())
+            {
+                annotatedType = annotatedTypes.next();
+                // TODO what to do here, if we have more than one?
+            }
+        }
+        if (annotatedType != null)
+        {
+            Set<AnnotatedMethod> methods = annotatedType.getMethods();
 
-        for (Method method : methods)
+            for (AnnotatedMethod method : methods)
+            {
+                Type baseType = method.getBaseType();
+                Class<?> clazz = ClassUtil.getClass(baseType);
+                if (clazz.isArray() || clazz.isAnnotation())
+                {
+                    if (!AnnotationUtil.hasAnnotation(method.getAnnotations(), Nonbinding.class))
+                    {
+                        throw new WebBeansConfigurationException("WebBeans definition class : " + method.getJavaMember().getDeclaringClass().getName() + " @Qualifier : "
+                                                                 + ann.annotationType().getName()
+                                                                 + " must have @NonBinding valued members for its array-valued and annotation valued members");
+                    }
+                }
+            }
+        }
+        else
         {
-            Class<?> clazz = method.getReturnType();
-            if (clazz.isArray() || clazz.isAnnotation())
+            Method[] methods = webBeansContext.getSecurityService().doPrivilegedGetDeclaredMethods(ann.annotationType());
+
+            for (Method method : methods)
             {
-                if (!AnnotationUtil.hasAnnotation(method.getDeclaredAnnotations(), Nonbinding.class))
+                Class<?> clazz = method.getReturnType();
+                if (clazz.isArray() || clazz.isAnnotation())
                 {
-                    throw new WebBeansConfigurationException("@Qualifier : " + ann.annotationType().getName()
+                    if (!AnnotationUtil.hasAnnotation(method.getDeclaredAnnotations(), Nonbinding.class))
+                    {
+                        throw new WebBeansConfigurationException("@Qualifier : " + ann.annotationType().getName()
                                                              + " must have @NonBinding valued members for its array-valued and annotation valued members");
+                    }
                 }
             }
         }
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/component/creation/BeanAttributesBuilder.java b/webbeans-impl/src/main/java/org/apache/webbeans/component/creation/BeanAttributesBuilder.java
index db00d22..eb6693f 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/component/creation/BeanAttributesBuilder.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/component/creation/BeanAttributesBuilder.java
@@ -20,7 +20,6 @@ package org.apache.webbeans.component.creation;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.util.Collections;
@@ -42,7 +41,6 @@ import javax.enterprise.inject.spi.AnnotatedMember;
 import javax.enterprise.inject.spi.AnnotatedMethod;
 import javax.enterprise.inject.spi.AnnotatedParameter;
 import javax.enterprise.inject.spi.AnnotatedType;
-import javax.enterprise.util.Nonbinding;
 import javax.inject.Named;
 import javax.inject.Scope;
 import javax.interceptor.Interceptor;
@@ -217,21 +215,7 @@ public abstract class BeanAttributesBuilder<T, A extends Annotated>
 
             if (annotationManager.isQualifierAnnotation(type))
             {
-                Method[] methods = webBeansContext.getSecurityService().doPrivilegedGetDeclaredMethods(type);
-
-                for (Method method : methods)
-                {
-                    Class<?> clazz = method.getReturnType();
-                    if (clazz.isArray() || clazz.isAnnotation())
-                    {
-                        if (!AnnotationUtil.hasAnnotation(method.getDeclaredAnnotations(), Nonbinding.class))
-                        {
-                            throw new WebBeansConfigurationException("WebBeans definition class : " + method.getDeclaringClass().getName() + " @Qualifier : "
-                                                                     + annotation.annotationType().getName()
-                                                                     + " must have @NonBinding valued members for its array-valued and annotation valued members");
-                        }
-                    }
-                }
+                annotationManager.checkQualifierConditions(annotation);
 
                 if (qualifiedTypes.contains(annotation.annotationType()) && !isRepetable(annotated, annotation))
                 {
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanManagerImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanManagerImpl.java
index 082409b..4091b57 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanManagerImpl.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/container/BeanManagerImpl.java
@@ -1442,7 +1442,11 @@ public class BeanManagerImpl implements BeanManager, Referenceable
     public <T> Iterable<AnnotatedType<T>> getAnnotatedTypes(Class<T> type)
     {
         final Collection<AnnotatedType<T>> types = new ArrayList<>(2);
-        types.add(annotatedElementFactory.getAnnotatedType(type));
+        AnnotatedType<T> annotatedType = annotatedElementFactory.getAnnotatedType(type);
+        if (annotatedType != null)
+        {
+            types.add(annotatedType);
+        }
         final Collection<AnnotatedType<T>> userAnnotatedTypes = getUserAnnotatedTypes(type);
         if (userAnnotatedTypes != null)
         {
diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/util/AnnotationUtil.java b/webbeans-impl/src/main/java/org/apache/webbeans/util/AnnotationUtil.java
index 589344b..fba8093 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/util/AnnotationUtil.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/util/AnnotationUtil.java
@@ -479,6 +479,11 @@ public final class AnnotationUtil
         return getAnnotation(anns, annotation) != null;
     }
 
+    public static boolean hasAnnotation(Set<Annotation> anns, Class<? extends Annotation> annotation)
+    {
+        return getAnnotation(anns, annotation) != null;
+    }
+
     /**
      * get the annotation of the given type from the array. 
      * @param anns
diff --git a/webbeans-impl/src/test/java/org/apache/webbeans/test/qualifier/CacheUsesQualifierOverridesTest.java b/webbeans-impl/src/test/java/org/apache/webbeans/test/qualifier/CacheUsesQualifierOverridesTest.java
index c26ec46..5710794 100644
--- a/webbeans-impl/src/test/java/org/apache/webbeans/test/qualifier/CacheUsesQualifierOverridesTest.java
+++ b/webbeans-impl/src/test/java/org/apache/webbeans/test/qualifier/CacheUsesQualifierOverridesTest.java
@@ -24,12 +24,25 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
+import java.lang.annotation.Annotation;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 import java.util.function.Supplier;
 
 import javax.enterprise.context.Dependent;
 import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AnnotatedConstructor;
+import javax.enterprise.inject.spi.AnnotatedField;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedParameter;
+import javax.enterprise.inject.spi.AnnotatedType;
 import javax.enterprise.inject.spi.BeforeBeanDiscovery;
 import javax.enterprise.inject.spi.Extension;
 import javax.enterprise.util.AnnotationLiteral;
@@ -38,15 +51,18 @@ import javax.inject.Qualifier;
 
 import org.apache.webbeans.config.OwbParametrizedTypeImpl;
 import org.apache.webbeans.test.AbstractUnitTest;
+import org.apache.webbeans.util.GenericsUtil;
 import org.junit.Test;
 
 public class CacheUsesQualifierOverridesTest extends AbstractUnitTest
 {
     @Test
-    public void run()
+    public void configureExistingQualifier()
     {
-        addExtension(new Extension() {
-            void changeQualifier(@Observes final BeforeBeanDiscovery beforeBeanDiscovery) {
+        addExtension(new Extension()
+        {
+            void changeQualifier(@Observes final BeforeBeanDiscovery beforeBeanDiscovery)
+            {
                 beforeBeanDiscovery.configureQualifier(TheQualifier.class)
                         .methods().forEach(m -> m.remove(it -> it.annotationType() == Nonbinding.class));
             }
@@ -61,8 +77,42 @@ public class CacheUsesQualifierOverridesTest extends AbstractUnitTest
         assertNotEquals(uno.getClass(), due.getClass());
     }
 
+    @Test
+    public void addQualifierWithNonBinding()
+    {
+        addExtension(new Extension()
+        {
+            void changeQualifier(@Observes final BeforeBeanDiscovery beforeBeanDiscovery)
+            {
+                beforeBeanDiscovery.configureQualifier(QualifierWithoutMarker.class)
+                        .methods().forEach(m -> m.add(new Nonbinding.Literal()));
+            }
+        });
+        startContainer(Impl1.class, Impl2.class);
+        final OwbParametrizedTypeImpl type = new OwbParametrizedTypeImpl(null, Supplier.class, String.class);
+        final Supplier<String> uno = getInstance(type, new QualifierWithoutMarker.Literal("non-binding attribute"));
+        assertEquals("1", uno.get());
+    }
+
+    @Test
+    public void addQualifier()
+    {
+        addExtension(new Extension()
+        {
+            void addQualifier(@Observes final BeforeBeanDiscovery beforeBeanDiscovery)
+            {
+                beforeBeanDiscovery.addQualifier(new QualifierWithArrayAttributeType());
+            }
+        });
+        startContainer(Impl1.class, Impl2.class);
+        final OwbParametrizedTypeImpl type = new OwbParametrizedTypeImpl(null, Supplier.class, String.class);
+        final Supplier<String> uno = getInstance(type, new QualifierWithoutMarker.Literal("non-binding attribute"));
+        assertEquals("1", uno.get());
+    }
+
     @Dependent
     @TheQualifier("uno")
+    @QualifierWithoutMarker
     public static class Impl1 implements Supplier<String>
     {
         @Override
@@ -107,4 +157,153 @@ public class CacheUsesQualifierOverridesTest extends AbstractUnitTest
             }
         }
     }
+
+    @Target({FIELD, TYPE})
+    @Retention(RUNTIME)
+    public @interface QualifierWithoutMarker
+    {
+        String[] value() default {};
+
+        class Literal extends AnnotationLiteral<QualifierWithoutMarker> implements QualifierWithoutMarker
+        {
+            private final String[] value;
+
+            public Literal(final String... value)
+            {
+                this.value = value;
+            }
+
+            @Override
+            public String[] value()
+            {
+                return value;
+            }
+        }
+    }
+
+    class QualifierWithArrayAttributeType implements AnnotatedType<QualifierWithoutMarker>
+    {
+
+        @Override
+        public Type getBaseType()
+        {
+            return QualifierWithoutMarker.class;
+        }
+
+        @Override
+        public Set<Type> getTypeClosure()
+        {
+            return GenericsUtil.getTypeClosure(QualifierWithoutMarker.class);
+        }
+
+        @Override
+        public <T extends Annotation> T getAnnotation(Class<T> annotationType)
+        {
+            return QualifierWithoutMarker.class.getAnnotation(annotationType);
+        }
+
+        @Override
+        public Set<Annotation> getAnnotations()
+        {
+            return new HashSet<>(Arrays.asList(QualifierWithoutMarker.class.getAnnotations()));
+        }
+
+        @Override
+        public boolean isAnnotationPresent(Class<? extends Annotation> annotationType)
+        {
+            return QualifierWithoutMarker.class.isAnnotationPresent(annotationType);
+        }
+
+        @Override
+        public Class<QualifierWithoutMarker> getJavaClass()
+        {
+            return QualifierWithoutMarker.class;
+        }
+
+        @Override
+        public Set<AnnotatedConstructor<QualifierWithoutMarker>> getConstructors()
+        {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public Set<AnnotatedMethod<? super QualifierWithoutMarker>> getMethods()
+        {
+            AnnotatedType<QualifierWithoutMarker> declaringType = this;
+            return Collections.singleton(new AnnotatedMethod<QualifierWithoutMarker>()
+            {
+
+                @Override
+                public List<AnnotatedParameter<QualifierWithoutMarker>> getParameters()
+                {
+                    return Collections.emptyList();
+                }
+
+                @Override
+                public boolean isStatic()
+                {
+                    return false;
+                }
+
+                @Override
+                public AnnotatedType<QualifierWithoutMarker> getDeclaringType()
+                {
+                    return declaringType;
+                }
+
+                @Override
+                public Type getBaseType()
+                {
+                    return String[].class;
+                }
+
+                @Override
+                public Set<Type> getTypeClosure()
+                {
+                    return GenericsUtil.getTypeClosure(String[].class);
+                }
+
+                @Override
+                public <T extends Annotation> T getAnnotation(Class<T> annotationType)
+                {
+                    if (Nonbinding.class.equals(annotationType))
+                    { 
+                        return (T)new Nonbinding.Literal();
+                    }
+                    else
+                    {
+                        return null;
+                    }
+                }
+
+                @Override
+                public Set<Annotation> getAnnotations()
+                {
+                    return Collections.singleton(new Nonbinding.Literal());
+                }
+
+                @Override
+                public boolean isAnnotationPresent(Class<? extends Annotation> annotationType)
+                {
+                    return Nonbinding.class.equals(annotationType);
+                }
+
+                @Override
+                public Method getJavaMember() {
+                    try {
+                        return QualifierWithoutMarker.class.getMethod("value");
+                    } catch (NoSuchMethodException e) {
+                        throw new IllegalStateException(e);
+                    }
+                }
+                
+            });
+        }
+
+        @Override
+        public Set<AnnotatedField<? super QualifierWithoutMarker>> getFields() {
+            return Collections.emptySet();
+        }
+        
+    }
 }