Skip to content

Commit 03c4c65

Browse files
committed
WELD-2824 Implement the concept of reserves
1 parent ee9316c commit 03c4c65

35 files changed

+516
-96
lines changed

impl/src/main/java/org/jboss/weld/bean/AbstractProducerBean.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.jboss.weld.bootstrap.api.ServiceRegistry;
3737
import org.jboss.weld.injection.CurrentInjectionPoint;
3838
import org.jboss.weld.logging.BeanLogger;
39+
import org.jboss.weld.logging.BootstrapLogger;
3940
import org.jboss.weld.manager.BeanManagerImpl;
4041
import org.jboss.weld.serialization.spi.BeanIdentifier;
4142
import org.jboss.weld.util.Beans;
@@ -225,9 +226,24 @@ public Integer getPriority() {
225226
return explicitPriority;
226227
}
227228

228-
// requires initialized getAnnotated() hence subclasses need to invoke this manually
229-
protected void processExplicitPriority() {
229+
/**
230+
* Searches for {@code @Priority} annotation declared either directly on the producer or via its stereotypes.
231+
* <p>
232+
* Requires initialized {@code getAnnotated()} hence subclasses need to invoke this manually.
233+
*/
234+
protected void processPriority() {
230235
Priority annotation = getAnnotated() == null ? null : getAnnotated().getAnnotation(Priority.class);
231236
this.explicitPriority = annotation == null ? null : annotation.value();
237+
238+
// no explicit priority, try searching through stereotypes
239+
if (explicitPriority == null) {
240+
Beans.AnnotationSearchResult annotationSearchResult = Beans.annotationSearch(getAnnotated());
241+
// multiple priorities within stereotypes are an error
242+
if (annotationSearchResult.getPriorities().size() > 1) {
243+
throw BootstrapLogger.LOG.multiplePriorityValuesDeclared(getAnnotated());
244+
} else if (annotationSearchResult.getPriorities().size() == 1) {
245+
this.explicitPriority = annotationSearchResult.getPriorities().iterator().next();
246+
}
247+
}
232248
}
233249
}

impl/src/main/java/org/jboss/weld/bean/ProducerField.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public Bean<T> getBean() {
9696
return ProducerField.this;
9797
}
9898
});
99-
processExplicitPriority();
99+
processPriority();
100100
}
101101

102102
@Override

impl/src/main/java/org/jboss/weld/bean/ProducerMethod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public Bean<T> getBean() {
9797
return ProducerMethod.this;
9898
}
9999
});
100-
processExplicitPriority();
100+
processPriority();
101101
}
102102

103103
@Override

impl/src/main/java/org/jboss/weld/bean/attributes/BeanAttributesFactory.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public static class BeanAttributesBuilder<T> {
6767

6868
private MergedStereotypes<T, ?> mergedStereotypes;
6969
private boolean alternative;
70+
private boolean reserve;
7071
private String name;
7172
private Set<Annotation> qualifiers;
7273
private Set<Type> types;
@@ -79,6 +80,7 @@ public BeanAttributesBuilder(EnhancedAnnotated<T, ?> annotated, Set<Type> types,
7980
this.annotated = annotated;
8081
initStereotypes(annotated, manager);
8182
initAlternative(annotated);
83+
initReserve(annotated);
8284
initName(annotated);
8385
initQualifiers(annotated);
8486
initScope(annotated);
@@ -97,6 +99,10 @@ protected void initAlternative(EnhancedAnnotated<T, ?> annotated) {
9799
this.alternative = Beans.isAlternative(annotated, mergedStereotypes);
98100
}
99101

102+
protected void initReserve(EnhancedAnnotated<T, ?> annotated) {
103+
this.reserve = Beans.isReserve(annotated, mergedStereotypes);
104+
}
105+
100106
/**
101107
* Initializes the name
102108
*/
@@ -234,8 +240,8 @@ protected boolean initScopeFromStereotype() {
234240
}
235241

236242
public BeanAttributes<T> build() {
237-
return new ImmutableBeanAttributes<T>(mergedStereotypes.getStereotypes(), alternative, name, qualifiers, types,
238-
scope);
243+
return new ImmutableBeanAttributes<T>(mergedStereotypes.getStereotypes(), alternative, reserve, name,
244+
qualifiers, types, scope);
239245
}
240246
}
241247
}

impl/src/main/java/org/jboss/weld/bean/attributes/ExternalBeanAttributesFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private ExternalBeanAttributesFactory() {
5252
public static <T> BeanAttributes<T> of(BeanAttributes<T> source, BeanManager manager) {
5353
validateBeanAttributes(source, manager);
5454
BeanAttributes<T> attributes = new ImmutableBeanAttributes<T>(defensiveCopy(source.getStereotypes()),
55-
source.isAlternative(), source.getName(),
55+
source.isAlternative(), source.isReserve(), source.getName(),
5656
defensiveCopy(source.getQualifiers()), defensiveCopy(source.getTypes()), source.getScope());
5757
return attributes;
5858
}

impl/src/main/java/org/jboss/weld/bean/attributes/ImmutableBeanAttributes.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,17 @@ public class ImmutableBeanAttributes<T> implements BeanAttributes<T> {
3535

3636
private final Set<Class<? extends Annotation>> stereotypes;
3737
private final boolean alternative;
38+
private final boolean reserve;
3839
private final String name;
3940
private final Set<Annotation> qualifiers;
4041
private final Set<Type> types;
4142
private final Class<? extends Annotation> scope;
4243

43-
public ImmutableBeanAttributes(Set<Class<? extends Annotation>> stereotypes, boolean alternative, String name,
44-
Set<Annotation> qualifiers, Set<Type> types,
45-
Class<? extends Annotation> scope) {
44+
public ImmutableBeanAttributes(Set<Class<? extends Annotation>> stereotypes, boolean alternative, boolean reserve,
45+
String name, Set<Annotation> qualifiers, Set<Type> types, Class<? extends Annotation> scope) {
4646
this.stereotypes = stereotypes;
4747
this.alternative = alternative;
48+
this.reserve = reserve;
4849
this.name = name;
4950
this.qualifiers = qualifiers;
5051
this.types = types;
@@ -55,7 +56,8 @@ public ImmutableBeanAttributes(Set<Class<? extends Annotation>> stereotypes, boo
5556
* Utility constructor used for overriding Bean qualifiers and name for specialization purposes.
5657
*/
5758
public ImmutableBeanAttributes(Set<Annotation> qualifiers, String name, BeanAttributes<T> attributes) {
58-
this(attributes.getStereotypes(), attributes.isAlternative(), name, qualifiers, attributes.getTypes(),
59+
this(attributes.getStereotypes(), attributes.isAlternative(), attributes.isReserve(), name, qualifiers,
60+
attributes.getTypes(),
5961
attributes.getScope());
6062
}
6163

@@ -69,6 +71,11 @@ public boolean isAlternative() {
6971
return alternative;
7072
}
7173

74+
@Override
75+
public boolean isReserve() {
76+
return reserve;
77+
}
78+
7279
@Override
7380
public String getName() {
7481
return name;

impl/src/main/java/org/jboss/weld/bean/builtin/AbstractBuiltInBean.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public boolean isDependentContextOptimizationAllowed() {
9898
protected static class BuiltInBeanAttributes<T> extends ImmutableBeanAttributes<T> {
9999

100100
public BuiltInBeanAttributes(Class<T> type) {
101-
super(Collections.<Class<? extends Annotation>> emptySet(), false, null, Bindings.DEFAULT_QUALIFIERS,
101+
super(Collections.<Class<? extends Annotation>> emptySet(), false, false, null, Bindings.DEFAULT_QUALIFIERS,
102102
ImmutableSet.of(Object.class, type), Dependent.class);
103103
}
104104
}

impl/src/main/java/org/jboss/weld/bootstrap/BeanDeployer.java

Lines changed: 16 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@
2222
import java.util.List;
2323
import java.util.Set;
2424

25-
import jakarta.annotation.Priority;
2625
import jakarta.decorator.Decorator;
27-
import jakarta.enterprise.inject.Stereotype;
26+
import jakarta.enterprise.inject.Reserve;
2827
import jakarta.enterprise.inject.spi.AnnotatedType;
2928
import jakarta.enterprise.inject.spi.Bean;
3029
import jakarta.enterprise.inject.spi.Extension;
@@ -100,64 +99,21 @@ private <T> SlimAnnotatedTypeContext<T> addIfNotNull(SlimAnnotatedTypeContext<T>
10099
return ctx;
101100
}
102101

103-
/**
104-
* Attempts to find a {@code @Priority} annotation declared on a stereotype(s) of given {@code AnnotatedType}.
105-
* Returns the value in this annotation, or {@code null} if none was found.
106-
*
107-
* If the {@code AnnotatedType} declares more than one stereotype and at least two of them declare different
108-
* {@code @Priority} values, a definition exception is thrown.
109-
*
110-
* If there are multiple {@code @Priority} values in a hierarchy of single stereotype, first annotation value is
111-
* used.
112-
*
113-
* @param type AnnotatedType to be searched
114-
* @return an Integer representing the priority value, null if none was found
115-
*/
116-
private Integer findPriorityInStereotypes(AnnotatedType<?> type) {
117-
// search all annotations
118-
Set<Integer> foundPriorities = new HashSet<>();
119-
for (Annotation annotation : type.getAnnotations()) {
120-
// identify stereotypes
121-
Class<? extends Annotation> annotationClass = annotation.annotationType();
122-
if (annotationClass.getAnnotation(Stereotype.class) != null) {
123-
recursiveStereotypeSearch(annotationClass, foundPriorities);
124-
}
125-
}
126-
// more than one value found, throw exception
127-
if (foundPriorities.size() > 1) {
128-
throw BootstrapLogger.LOG.multiplePriorityValuesDeclared(type);
129-
}
130-
// no priority found
131-
if (foundPriorities.isEmpty()) {
132-
return null;
133-
}
134-
// exactly one value found
135-
return foundPriorities.iterator().next();
136-
}
137-
138-
private void recursiveStereotypeSearch(Class<? extends Annotation> stereotype, Set<Integer> foundPriorities) {
139-
// search each stereotype for priority annotation, store all values found
140-
Priority priorityAnnotation = stereotype.getAnnotation(Priority.class);
141-
if (priorityAnnotation != null) {
142-
// if found, store the value
143-
foundPriorities.add(priorityAnnotation.value());
144-
}
145-
// perform a recursive search for more stereotypes
146-
for (Annotation annotation : stereotype.getAnnotations()) {
147-
Class<? extends Annotation> annotationClass = annotation.annotationType();
148-
if (annotationClass.getAnnotation(Stereotype.class) != null) {
149-
recursiveStereotypeSearch(annotationClass, foundPriorities);
150-
}
151-
}
152-
}
153-
154102
private void processPriority(AnnotatedType<?> type) {
155103
// check if @Priority is declared directly on the AnnotatedType
156104
Object priority = type.getAnnotation(annotationApi.PRIORITY_ANNOTATION_CLASS);
157-
Integer value;
105+
Integer value = null;
106+
// search stereotypes for priority/alternative/reserve annotations
107+
Beans.AnnotationSearchResult annSearchResult = Beans.annotationSearch(type);
158108
if (priority == null) {
159-
// if not declared, search in any stereotypes of given AnnotatedType
160-
value = findPriorityInStereotypes(type);
109+
Set<Integer> priorities = annSearchResult.getPriorities();
110+
// more than one value found and no priority on the class itself, throw an exception
111+
if (priorities.size() > 1) {
112+
throw BootstrapLogger.LOG.multiplePriorityValuesDeclared(type);
113+
} else if (priorities.size() == 1) {
114+
// exactly one value, we can use that
115+
value = priorities.iterator().next();
116+
}
161117
} else {
162118
value = annotationApi.getPriority(priority);
163119
}
@@ -168,6 +124,10 @@ private void processPriority(AnnotatedType<?> type) {
168124
} else if (type.isAnnotationPresent(Decorator.class)) {
169125
globalEnablementBuilder.addDecorator(type.getJavaClass(), value);
170126
} else {
127+
// Validation of a bean being both reserve and alternative happens in Validator for now, possibly register both
128+
if (type.isAnnotationPresent(Reserve.class) || annSearchResult.getReserve() != null) {
129+
globalEnablementBuilder.addReserve(type.getJavaClass(), value);
130+
}
171131
/*
172132
* An alternative may be given a priority for the application by placing the @Priority annotation on the bean
173133
* class that declares the producer method, field or resource.

impl/src/main/java/org/jboss/weld/bootstrap/Validator.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ protected void validateGeneralBean(Bean<?> bean, BeanManagerImpl beanManager) {
167167
if (beanManager.isPassivatingScope(bean.getScope()) && !Beans.isPassivationCapableBean(bean)) {
168168
throw ValidatorLogger.LOG.beanWithPassivatingScopeNotPassivationCapable(bean);
169169
}
170+
171+
// a bean cannot be an alternative and a reserve at the same time
172+
if (bean.isAlternative() && bean.isReserve()) {
173+
throw ValidatorLogger.LOG.beanReserveAndAlternative(bean);
174+
}
170175
}
171176

172177
/**
@@ -189,12 +194,12 @@ protected void validateRIBean(CommonBean<?> bean, BeanManagerImpl beanManager, C
189194
validateInterceptors(beanManager, classBean);
190195
}
191196
}
192-
// for each producer bean validate its disposer method
193197
if (bean instanceof AbstractProducerBean<?, ?, ?>) {
194198
AbstractProducerBean<?, ?, ?> producerBean = Reflections.<AbstractProducerBean<?, ?, ?>> cast(bean);
195199
if (producerBean.getProducer() instanceof AbstractMemberProducer<?, ?>) {
196200
AbstractMemberProducer<?, ?> producer = Reflections.<AbstractMemberProducer<?, ?>> cast(producerBean
197201
.getProducer());
202+
// for each producer bean validate its disposer method
198203
if (producer.getDisposalMethod() != null) {
199204
for (InjectionPoint ip : producer.getDisposalMethod().getInjectionPoints()) {
200205
// pass the producer bean instead of the disposal method bean
@@ -204,6 +209,14 @@ protected void validateRIBean(CommonBean<?> bean, BeanManagerImpl beanManager, C
204209
validateInjectionPointForDeploymentProblems(ip, null, beanManager);
205210
}
206211
}
212+
// if it's an alternative, declaring bean cannot be a reserve
213+
if (producerBean.isAlternative() && producerBean.getDeclaringBean().isReserve()) {
214+
throw ValidatorLogger.LOG.producedAlternativeOnReserveDeclaringBean(producerBean);
215+
}
216+
// if it's a reserve, declaring bean cannot be alternative
217+
if (producerBean.isReserve() && producerBean.getDeclaringBean().isAlternative()) {
218+
throw ValidatorLogger.LOG.producedReserveOnAlternativeDeclaringBean(producerBean);
219+
}
207220
}
208221
}
209222
}

impl/src/main/java/org/jboss/weld/bootstrap/enablement/EnablementListView.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ public void remove() {
269269
enum ViewType {
270270

271271
ALTERNATIVES("getAlternatives()"),
272+
RESERVES("getReserves()"),
272273
INTERCEPTORS("getInterceptors()"),
273274
DECORATORS("getDecorators()");
274275

0 commit comments

Comments
 (0)