Skip to content

Commit 28c7591

Browse files
committed
WELD-2824 Implement the concept of reserves
1 parent ee9316c commit 28c7591

27 files changed

+394
-91
lines changed

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,5 +229,14 @@ public Integer getPriority() {
229229
protected void processExplicitPriority() {
230230
Priority annotation = getAnnotated() == null ? null : getAnnotated().getAnnotation(Priority.class);
231231
this.explicitPriority = annotation == null ? null : annotation.value();
232+
233+
// no explicit priority, try searching through stereotypes
234+
// ATM we always perform this search, but we could limit it to when the bean is alternative/reserve only?
235+
if (explicitPriority == null) {
236+
Beans.AnnotationSearchResult annotationSearchResult = Beans.annotationSearch(getAnnotated());
237+
if (!annotationSearchResult.getPriorities().isEmpty()) {
238+
this.explicitPriority = annotationSearchResult.getPriorities().iterator().next();
239+
}
240+
}
232241
}
233242
}

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

Lines changed: 8 additions & 1 deletion
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,7 +240,8 @@ protected boolean initScopeFromStereotype() {
234240
}
235241

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

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 producer 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

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@
5656
public class GlobalEnablementBuilder extends AbstractBootstrapService {
5757

5858
private final List<Item> alternatives = Collections.synchronizedList(new ArrayList<Item>());
59+
private final List<Item> reserves = Collections.synchronizedList(new ArrayList<Item>());
5960
private final List<Item> interceptors = Collections.synchronizedList(new ArrayList<Item>());
6061
private final List<Item> decorators = Collections.synchronizedList(new ArrayList<Item>());
6162

6263
private volatile Map<Class<?>, Integer> cachedAlternativeMap;
64+
private volatile Map<Class<?>, Integer> cachedReserveMap;
6365
private volatile boolean sorted;
6466
private volatile boolean dirty;
6567

@@ -83,6 +85,10 @@ public void addAlternative(Class<?> javaClass, int priority) {
8385
addItem(alternatives, javaClass, priority);
8486
}
8587

88+
public void addReserve(Class<?> javaClass, int priority) {
89+
addItem(reserves, javaClass, priority);
90+
}
91+
8692
public void addInterceptor(Class<?> javaClass, int priority) {
8793
addItem(interceptors, javaClass, priority);
8894
}
@@ -112,6 +118,27 @@ protected List<Item> getDelegate() {
112118
};
113119
}
114120

121+
public List<Class<?>> getReserveList(final Extension extension) {
122+
initialize();
123+
return new EnablementListView() {
124+
125+
@Override
126+
protected Extension getExtension() {
127+
return extension;
128+
}
129+
130+
@Override
131+
protected ViewType getViewType() {
132+
return ViewType.ALTERNATIVES;
133+
}
134+
135+
@Override
136+
protected List<Item> getDelegate() {
137+
return reserves;
138+
}
139+
};
140+
}
141+
115142
public List<Class<?>> getInterceptorList(final Extension extension) {
116143
initialize();
117144
return new EnablementListView() {
@@ -180,9 +207,21 @@ private Map<Class<?>, Integer> getGlobalAlternativeMap() {
180207
return cachedAlternativeMap;
181208
}
182209

210+
private Map<Class<?>, Integer> getGlobalReserveMap() {
211+
if (cachedReserveMap == null || dirty) {
212+
Map<Class<?>, Integer> map = new HashMap<Class<?>, Integer>();
213+
for (Item item : reserves) {
214+
map.put(item.getJavaClass(), item.getPriority());
215+
}
216+
cachedReserveMap = ImmutableMap.copyOf(map);
217+
}
218+
return cachedReserveMap;
219+
}
220+
183221
private void initialize() {
184222
if (!sorted) {
185223
Collections.sort(alternatives);
224+
Collections.sort(reserves);
186225
Collections.sort(interceptors);
187226
Collections.sort(decorators);
188227
sorted = true;
@@ -236,26 +275,29 @@ public ModuleEnablement createModuleEnablement(BeanDeployment deployment) {
236275
}
237276

238277
Map<Class<?>, Integer> globalAlternatives = getGlobalAlternativeMap();
278+
Map<Class<?>, Integer> globalReserves = getGlobalReserveMap();
239279

240280
// We suppose that enablements are always created all at once
241281
dirty = false;
242282

243283
return new ModuleEnablement(moduleInterceptorsBuilder.build(), moduleDecoratorsBuilder.build(), globalAlternatives,
284+
globalReserves,
244285
alternativeClasses,
245286
alternativeStereotypes);
246287
}
247288

248289
@Override
249290
public void cleanupAfterBoot() {
250291
alternatives.clear();
292+
reserves.clear();
251293
interceptors.clear();
252294
decorators.clear();
253295
}
254296

255297
@Override
256298
public String toString() {
257-
return "GlobalEnablementBuilder [alternatives=" + alternatives + ", interceptors=" + interceptors + ", decorators="
258-
+ decorators + "]";
299+
return "GlobalEnablementBuilder [alternatives=" + alternatives + ", reserves=" + reserves + ", interceptors="
300+
+ interceptors + ", decorators=" + decorators + "]";
259301
}
260302

261303
private <T> void checkForDuplicates(List<Metadata<T>> list, MessageCallback<DeploymentException> messageCallback) {

0 commit comments

Comments
 (0)