diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/inject/instance/InstanceImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/inject/instance/InstanceImpl.java index 1219a420c..c8eb74640 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/inject/instance/InstanceImpl.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/inject/instance/InstanceImpl.java @@ -32,9 +32,11 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.util.stream.Stream; import javax.enterprise.context.spi.AlterableContext; import javax.enterprise.context.spi.Context; +import javax.enterprise.inject.Any; import javax.enterprise.inject.Instance; import javax.enterprise.inject.spi.Annotated; import javax.enterprise.inject.spi.Bean; @@ -42,6 +44,7 @@ import javax.enterprise.util.TypeLiteral; import javax.inject.Provider; +import org.apache.webbeans.annotation.DefaultLiteral; import org.apache.webbeans.config.WebBeansContext; import org.apache.webbeans.container.BeanManagerImpl; import org.apache.webbeans.container.InjectionResolver; @@ -178,14 +181,16 @@ public boolean isUnsatisfied() * {@inheritDoc} */ @Override - public Instance select(Annotation... qualifiers) + public Instance select(final Annotation... qualifiers) { if (strictValidation) { webBeansContext.getAnnotationManager().checkQualifierConditions(qualifiers); } - Annotation[] newQualifiersArray = qualifiers; + final Annotation[] newQualifiersArray = qualifiers.length == 0? + qualifierAnnotations.toArray(new Annotation[0]) : + concatenateQualifiers(qualifiers); return new InstanceImpl<>( injectionClazz, injectionPoint == null ? null : new InstanceInjectionPoint(injectionPoint, newQualifiersArray), webBeansContext, newQualifiersArray); @@ -203,19 +208,14 @@ public Instance select(Class subtype, Annotation... qualifie } Type sub = subtype; - if(sub == null) { sub = injectionClazz; } - if (qualifiers== null || qualifiers.length == 0) - { - - } - Annotation[] effectiveQualifiers = qualifiers != null && qualifiers.length > 0 - ? qualifiers - : qualifierAnnotations.toArray(new Annotation[qualifierAnnotations.size()]); + final Annotation[] effectiveQualifiers = qualifiers != null && qualifiers.length > 0 + ? concatenateQualifiers(qualifiers) + : qualifierAnnotations.toArray(new Annotation[0]); return new InstanceImpl<>(sub, injectionPoint, webBeansContext, effectiveQualifiers); } @@ -250,6 +250,18 @@ public T next() }; } + private Annotation[] concatenateQualifiers(final Annotation[] additionalQualifiers) + { + return Stream.concat( + qualifierAnnotations.stream() + .filter(it -> it.annotationType() != Any.class) // no more relevant if there is another one + // see org.apache.webbeans.portable.InstanceProducer.produce + // NOT equals() to respect user request but == + .filter(it -> it != DefaultLiteral.INSTANCE), + Stream.of(additionalQualifiers)) + .toArray(Annotation[]::new); + } + public void destroy(T instance) { if (instance == null) diff --git a/webbeans-impl/src/test/java/org/apache/webbeans/test/instance/InstanceQualifierInjectionPointTest.java b/webbeans-impl/src/test/java/org/apache/webbeans/test/instance/InstanceQualifierInjectionPointTest.java index e82c9cb02..340952a1c 100644 --- a/webbeans-impl/src/test/java/org/apache/webbeans/test/instance/InstanceQualifierInjectionPointTest.java +++ b/webbeans-impl/src/test/java/org/apache/webbeans/test/instance/InstanceQualifierInjectionPointTest.java @@ -64,7 +64,7 @@ public void checkQualfiers() { Factory.class), Collections.emptyList(), true); assertNotNull(instance1.select(new AnnotationLiteral() {}).get()); - assertEquals(1, holder.getQualifiers().size()); + assertEquals(holder.getQualifiers().toString(), 1, holder.getQualifiers().size()); assertEquals(Qualifier1.class, holder.getQualifiers().iterator().next().annotationType()); assertNotNull(instance2.select(AnyLiteral.INSTANCE).get()); diff --git a/webbeans-impl/src/test/java/org/apache/webbeans/test/instance/InstanceSelectTest.java b/webbeans-impl/src/test/java/org/apache/webbeans/test/instance/InstanceSelectTest.java new file mode 100644 index 000000000..ae53f342d --- /dev/null +++ b/webbeans-impl/src/test/java/org/apache/webbeans/test/instance/InstanceSelectTest.java @@ -0,0 +1,147 @@ +/* + * 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.webbeans.test.instance; + +import org.apache.webbeans.test.AbstractUnitTest; +import org.junit.Before; +import org.junit.Test; + +import javax.enterprise.inject.Any; +import javax.enterprise.inject.Instance; +import javax.enterprise.util.AnnotationLiteral; +import javax.inject.Inject; +import javax.inject.Qualifier; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.Collection; +import java.util.stream.Stream; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +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 static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.toList; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class InstanceSelectTest extends AbstractUnitTest { + @Inject + @Any + private Instance allTypesOfFood; + + @Before + public void init() { + startContainer(asList(Cherry.class, Strawberry.class), emptyList(), true); + } + + @Test + public void findYummyFruit() { + final Instance fruits = allTypesOfFood.select(new LiteralFoodType(FoodType.FRUIT)); + final Instance jummyFruits = fruits.select(new LiteralTasteType(TasteType.JUMMY)); + assertTrue(jummyFruits.stream().findAny().isPresent()); + } + + @Test + public void thereIsNoJummyVegetable() { + final Instance vegetables = allTypesOfFood.select(new LiteralFoodType(FoodType.VEGETABLE)); + assertTrue(vegetables.isUnsatisfied()); + + final Instance jummyVegetables = vegetables.select(new LiteralTasteType(TasteType.JUMMY)); + final Collection selected = jummyVegetables.stream().collect(toList()); + assertFalse(selected.toString(), selected.stream().findAny().isPresent()); + } + + public static class LiteralTasteType extends AnnotationLiteral implements TasteQualifier { + private final TasteType taste; + + public LiteralTasteType(TasteType taste) { + this.taste = taste; + } + + @Override + public TasteType value() { + return taste; + } + } + + public static class LiteralFoodType extends AnnotationLiteral implements FoodQualifier { + private final FoodType food; + + public LiteralFoodType(FoodType food) { + this.food = food; + } + + @Override + public FoodType value() { + return food; + } + } + + @Qualifier + @Retention(RUNTIME) + @Target({FIELD, TYPE, METHOD, CONSTRUCTOR, PARAMETER}) + public @interface FoodQualifier { + FoodType value(); + } + + @Qualifier + @Retention(RUNTIME) + @Target({FIELD, TYPE, METHOD, CONSTRUCTOR, PARAMETER}) + public @interface TasteQualifier { + TasteType value(); + } + + public enum TasteType { + JUMMY, + DISGUSTING + } + + public enum FoodType { + VEGETABLE, + FRUIT + } + + @FoodQualifier(FoodType.FRUIT) + @TasteQualifier(TasteType.DISGUSTING) + public static class Cherry extends Food { + public Cherry() { + super("Cherry"); + } + } + + @FoodQualifier(FoodType.FRUIT) + @TasteQualifier(TasteType.JUMMY) + public static class Strawberry extends Food { + public Strawberry() { + super("Strawberry"); + } + } + + public static abstract class Food { + private final String name; + + protected Food(String name) { + this.name = name; + } + } +}