Skip to content

Commit c84d537

Browse files
mkoubagsmet
authored andcommitted
ArC - introduce immutable bean archive index
- this is index is mandatory and is used to discover beans - the computing index is optional and can be used for other tasks, e.g. during type-safe resolution - if the computing index is not present the immutable index is used instead - fixes #29575 (cherry picked from commit c2ab342)
1 parent 0b15f5b commit c84d537

File tree

14 files changed

+128
-66
lines changed

14 files changed

+128
-66
lines changed

extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,8 @@ public void transform(TransformationContext transformationContext) {
277277
}
278278
});
279279

280-
builder.setBeanArchiveIndex(index);
280+
builder.setComputingBeanArchiveIndex(index);
281+
builder.setImmutableBeanArchiveIndex(beanArchiveIndex.getImmutableIndex());
281282
builder.setApplicationIndex(combinedIndex.getIndex());
282283
List<BeanDefiningAnnotation> beanDefiningAnnotations = additionalBeanDefiningAnnotations.stream()
283284
.map((s) -> new BeanDefiningAnnotation(s.getName(), s.getDefaultScope())).collect(Collectors.toList());

extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveIndexBuildItem.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,42 @@
1414
* Compared to {@link io.quarkus.deployment.builditem.CombinedIndexBuildItem} this index can contain additional classes
1515
* that were indexed while bean discovery was in progress.
1616
*
17-
* It also holds information about all programmatically registered beans and all generated bean classes.
18-
*
1917
* @see GeneratedBeanBuildItem
20-
* @see AdditionalBeanBuildItem
2118
* @see io.quarkus.deployment.builditem.CombinedIndexBuildItem
2219
*/
2320
public final class BeanArchiveIndexBuildItem extends SimpleBuildItem {
2421

2522
private final IndexView index;
23+
private final IndexView immutableIndex;
2624
private final Set<DotName> generatedClassNames;
2725

28-
public BeanArchiveIndexBuildItem(IndexView index, Set<DotName> generatedClassNames) {
26+
public BeanArchiveIndexBuildItem(IndexView index, IndexView immutableIndex, Set<DotName> generatedClassNames) {
2927
this.index = index;
28+
this.immutableIndex = immutableIndex;
3029
this.generatedClassNames = generatedClassNames;
3130
}
3231

32+
/**
33+
* This index is built on top of the immutable index.
34+
*
35+
* @return the computing index that can also index classes on demand
36+
*/
3337
public IndexView getIndex() {
3438
return index;
3539
}
3640

41+
/**
42+
*
43+
* @return an immutable index that represents the bean archive
44+
*/
45+
public IndexView getImmutableIndex() {
46+
return immutableIndex;
47+
}
48+
49+
/**
50+
*
51+
* @return the set of classes generated via {@link GeneratedBeanBuildItem}
52+
*/
3753
public Set<DotName> getGeneratedClassNames() {
3854
return generatedClassNames;
3955
}

extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveProcessor.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,12 @@ public BeanArchiveIndexBuildItem build(ArcConfig config, ApplicationArchivesBuil
8484
additionalClasses.put(knownMissingClass, Optional.empty());
8585
}
8686

87-
// Finally, index ArC/CDI API built-in classes
88-
return new BeanArchiveIndexBuildItem(
89-
BeanArchives.buildBeanArchiveIndex(Thread.currentThread().getContextClassLoader(), additionalClasses,
90-
applicationIndex,
91-
additionalBeanIndexer.complete()),
92-
generatedClassNames);
87+
IndexView immutableBeanArchiveIndex = BeanArchives.buildImmutableBeanArchiveIndex(applicationIndex,
88+
additionalBeanIndexer.complete());
89+
IndexView computingBeanArchiveIndex = BeanArchives.buildComputingBeanArchiveIndex(
90+
Thread.currentThread().getContextClassLoader(),
91+
additionalClasses, immutableBeanArchiveIndex);
92+
return new BeanArchiveIndexBuildItem(computingBeanArchiveIndex, immutableBeanArchiveIndex, generatedClassNames);
9393
}
9494

9595
private IndexView buildApplicationIndex(ArcConfig config, ApplicationArchivesBuildItem applicationArchivesBuildItem,

extensions/spring-di/deployment/src/test/java/io/quarkus/spring/di/deployment/SpringDIProcessorTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ public void getAnnotationsToAddBeanMethodWithScope() {
205205
private IndexView getIndex(final Class<?>... classes) {
206206
try {
207207
Index index = Index.of(classes);
208-
return BeanArchives.buildBeanArchiveIndex(getClass().getClassLoader(), new ConcurrentHashMap<>(), index);
208+
return BeanArchives.buildComputingBeanArchiveIndex(getClass().getClassLoader(), new ConcurrentHashMap<>(),
209+
BeanArchives.buildImmutableBeanArchiveIndex(index));
209210
} catch (IOException e) {
210211
throw new IllegalStateException("Failed to index classes", e);
211212
}

extensions/spring-scheduled/deployment/src/test/java/io/quarkus/spring/scheduled/deployment/SpringScheduledProcessorTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ public void testBuildDelayParamFromInvalidFormat() {
115115
private IndexView getIndex(final Class<?>... classes) {
116116
try {
117117
Index index = Index.of(classes);
118-
return BeanArchives.buildBeanArchiveIndex(getClass().getClassLoader(), new ConcurrentHashMap<>(), index);
118+
return BeanArchives.buildComputingBeanArchiveIndex(getClass().getClassLoader(), new ConcurrentHashMap<>(),
119+
BeanArchives.buildImmutableBeanArchiveIndex(index));
119120
} catch (IOException e) {
120121
throw new IllegalStateException("Failed to index classes", e);
121122
}

independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public class AnnotationLiteralProcessor {
4646
generateAnnotationLiteralClassName(key.annotationName()),
4747
applicationClassPredicate.test(key.annotationName()),
4848
key.annotationClass));
49-
this.beanArchiveIndex = beanArchiveIndex;
49+
this.beanArchiveIndex = Objects.requireNonNull(beanArchiveIndex);
5050
}
5151

5252
boolean hasLiteralsToGenerate() {

independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanArchives.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,23 @@ public final class BeanArchives {
5252
/**
5353
*
5454
* @param applicationIndexes
55-
* @return the final bean archive index
55+
* @return the immutable bean archive index
5656
*/
57-
public static IndexView buildBeanArchiveIndex(ClassLoader deploymentClassLoader,
58-
Map<DotName, Optional<ClassInfo>> additionalClasses, IndexView... applicationIndexes) {
57+
public static IndexView buildImmutableBeanArchiveIndex(IndexView... applicationIndexes) {
5958
List<IndexView> indexes = new ArrayList<>();
6059
Collections.addAll(indexes, applicationIndexes);
6160
indexes.add(buildAdditionalIndex());
62-
return new IndexWrapper(CompositeIndex.create(indexes), deploymentClassLoader, additionalClasses);
61+
return CompositeIndex.create(indexes);
62+
}
63+
64+
/**
65+
*
66+
* @param wrappedIndexes
67+
* @return the computing bean archive index
68+
*/
69+
public static IndexView buildComputingBeanArchiveIndex(ClassLoader deploymentClassLoader,
70+
Map<DotName, Optional<ClassInfo>> additionalClasses, IndexView immutableIndex) {
71+
return new IndexWrapper(immutableIndex, deploymentClassLoader, additionalClasses);
6372
}
6473

6574
private static IndexView buildAdditionalIndex() {

independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.List;
1515
import java.util.Map;
1616
import java.util.Map.Entry;
17+
import java.util.Objects;
1718
import java.util.Set;
1819
import java.util.concurrent.ConcurrentHashMap;
1920
import java.util.concurrent.CopyOnWriteArrayList;
@@ -55,8 +56,8 @@ public class BeanDeployment {
5556

5657
private final BuildContextImpl buildContext;
5758

58-
private final IndexView beanArchiveIndex;
59-
59+
private final IndexView beanArchiveComputingIndex;
60+
private final IndexView beanArchiveImmutableIndex;
6061
private final IndexView applicationIndex;
6162

6263
private final Map<DotName, ClassInfo> qualifiers;
@@ -124,7 +125,8 @@ public class BeanDeployment {
124125
}
125126
this.beanDefiningAnnotations = beanDefiningAnnotations;
126127
this.resourceAnnotations = new HashSet<>(builder.resourceAnnotations);
127-
this.beanArchiveIndex = builder.beanArchiveIndex;
128+
this.beanArchiveComputingIndex = builder.beanArchiveComputingIndex;
129+
this.beanArchiveImmutableIndex = Objects.requireNonNull(builder.beanArchiveImmutableIndex);
128130
this.applicationIndex = builder.applicationIndex;
129131
this.annotationStore = new AnnotationStore(initAndSort(builder.annotationTransformers, buildContext), buildContext);
130132
if (buildContext != null) {
@@ -141,11 +143,11 @@ public class BeanDeployment {
141143
this.excludeTypes = builder.excludeTypes != null ? new ArrayList<>(builder.excludeTypes) : Collections.emptyList();
142144

143145
qualifierNonbindingMembers = new HashMap<>();
144-
qualifiers = findQualifiers(this.beanArchiveIndex);
146+
qualifiers = findQualifiers();
145147
for (QualifierRegistrar registrar : builder.qualifierRegistrars) {
146148
for (Map.Entry<DotName, Set<String>> entry : registrar.getAdditionalQualifiers().entrySet()) {
147149
DotName dotName = entry.getKey();
148-
ClassInfo classInfo = getClassByName(this.beanArchiveIndex, dotName);
150+
ClassInfo classInfo = getClassByName(getBeanArchiveIndex(), dotName);
149151
if (classInfo != null) {
150152
Set<String> nonbindingMembers = entry.getValue();
151153
if (nonbindingMembers == null) {
@@ -156,15 +158,15 @@ public class BeanDeployment {
156158
}
157159
}
158160
}
159-
repeatingQualifierAnnotations = findContainerAnnotations(qualifiers, this.beanArchiveIndex);
161+
repeatingQualifierAnnotations = findContainerAnnotations(qualifiers);
160162
buildContextPut(Key.QUALIFIERS.asString(), Collections.unmodifiableMap(qualifiers));
161163

162164
interceptorNonbindingMembers = new HashMap<>();
163-
interceptorBindings = findInterceptorBindings(this.beanArchiveIndex);
165+
interceptorBindings = findInterceptorBindings();
164166
for (InterceptorBindingRegistrar registrar : builder.interceptorBindingRegistrars) {
165167
for (InterceptorBindingRegistrar.InterceptorBinding binding : registrar.getAdditionalBindings()) {
166168
DotName dotName = binding.getName();
167-
ClassInfo annotationClass = getClassByName(this.beanArchiveIndex, dotName);
169+
ClassInfo annotationClass = getClassByName(getBeanArchiveIndex(), dotName);
168170
if (annotationClass != null) {
169171
Set<String> nonbinding = new HashSet<>();
170172
for (MethodInfo method : annotationClass.methods()) {
@@ -177,20 +179,19 @@ public class BeanDeployment {
177179
interceptorBindings.put(dotName, annotationClass);
178180
}
179181
}
180-
repeatingInterceptorBindingAnnotations = findContainerAnnotations(interceptorBindings, this.beanArchiveIndex);
182+
repeatingInterceptorBindingAnnotations = findContainerAnnotations(interceptorBindings);
181183
buildContextPut(Key.INTERCEPTOR_BINDINGS.asString(), Collections.unmodifiableMap(interceptorBindings));
182184

183185
Set<DotName> additionalStereotypes = new HashSet<>();
184186
for (StereotypeRegistrar stereotypeRegistrar : builder.stereotypeRegistrars) {
185187
additionalStereotypes.addAll(stereotypeRegistrar.getAdditionalStereotypes());
186188
}
187189

188-
this.stereotypes = findStereotypes(this.beanArchiveIndex, interceptorBindings, customContexts, additionalStereotypes,
190+
this.stereotypes = findStereotypes(interceptorBindings, customContexts, additionalStereotypes,
189191
annotationStore);
190192
buildContextPut(Key.STEREOTYPES.asString(), Collections.unmodifiableMap(stereotypes));
191193

192194
this.transitiveInterceptorBindings = findTransitiveInterceptorBindings(interceptorBindings.keySet(),
193-
this.beanArchiveIndex,
194195
new HashMap<>(), interceptorBindings, annotationStore);
195196

196197
this.injectionPoints = new CopyOnWriteArrayList<>();
@@ -199,7 +200,7 @@ public class BeanDeployment {
199200
this.beans = new CopyOnWriteArrayList<>();
200201
this.observers = new CopyOnWriteArrayList<>();
201202

202-
this.assignabilityCheck = new AssignabilityCheck(beanArchiveIndex, applicationIndex);
203+
this.assignabilityCheck = new AssignabilityCheck(getBeanArchiveIndex(), applicationIndex);
203204
this.beanResolver = new BeanResolverImpl(this);
204205
this.delegateInjectionPointResolver = new DelegateInjectionPointResolverImpl(this);
205206
this.interceptorResolver = new InterceptorResolver(this);
@@ -517,12 +518,17 @@ public Collection<StereotypeInfo> getStereotypes() {
517518
}
518519

519520
/**
520-
* This index was used to discover components (beans, interceptors, qualifiers, etc.) and during type-safe resolution.
521+
* Returns the index that was used during discovery and type-safe resolution.
522+
* <p>
523+
* In general, the returned index is usually "computing" which means that it attempts to compute the information for the
524+
* classes that were not part of the initial bean archive index. I.e. the returned index corresponds to
525+
* {@link BeanProcessor.Builder#setComputingBeanArchiveIndex(IndexView)}. However, if the computing index was not set then
526+
* the index set by {@link BeanProcessor.Builder#setImmutableBeanArchiveIndex(IndexView)} is used instead.
521527
*
522528
* @return the bean archive index
523529
*/
524530
public IndexView getBeanArchiveIndex() {
525-
return beanArchiveIndex;
531+
return beanArchiveComputingIndex != null ? beanArchiveComputingIndex : beanArchiveImmutableIndex;
526532
}
527533

528534
/**
@@ -670,9 +676,9 @@ private void buildContextPut(String key, Object value) {
670676
}
671677
}
672678

673-
private Map<DotName, ClassInfo> findQualifiers(IndexView index) {
679+
private Map<DotName, ClassInfo> findQualifiers() {
674680
Map<DotName, ClassInfo> qualifiers = new HashMap<>();
675-
for (AnnotationInstance qualifier : index.getAnnotations(DotNames.QUALIFIER)) {
681+
for (AnnotationInstance qualifier : beanArchiveImmutableIndex.getAnnotations(DotNames.QUALIFIER)) {
676682
ClassInfo qualifierClass = qualifier.target().asClass();
677683
if (isExcluded(qualifierClass)) {
678684
continue;
@@ -682,23 +688,23 @@ private Map<DotName, ClassInfo> findQualifiers(IndexView index) {
682688
return qualifiers;
683689
}
684690

685-
private Map<DotName, ClassInfo> findContainerAnnotations(Map<DotName, ClassInfo> annotations, IndexView index) {
691+
private Map<DotName, ClassInfo> findContainerAnnotations(Map<DotName, ClassInfo> annotations) {
686692
Map<DotName, ClassInfo> containerAnnotations = new HashMap<>();
687693
for (ClassInfo annotation : annotations.values()) {
688694
AnnotationInstance repeatableMetaAnnotation = annotation.declaredAnnotation(DotNames.REPEATABLE);
689695
if (repeatableMetaAnnotation != null) {
690696
DotName containerAnnotationName = repeatableMetaAnnotation.value().asClass().name();
691-
ClassInfo containerClass = getClassByName(index, containerAnnotationName);
697+
ClassInfo containerClass = getClassByName(getBeanArchiveIndex(), containerAnnotationName);
692698
containerAnnotations.put(containerAnnotationName, containerClass);
693699
}
694700
}
695701
return containerAnnotations;
696702
}
697703

698-
private Map<DotName, ClassInfo> findInterceptorBindings(IndexView index) {
704+
private Map<DotName, ClassInfo> findInterceptorBindings() {
699705
Map<DotName, ClassInfo> bindings = new HashMap<>();
700706
// Note: doesn't use AnnotationStore, this will operate on classes without applying annotation transformers
701-
for (AnnotationInstance binding : index.getAnnotations(DotNames.INTERCEPTOR_BINDING)) {
707+
for (AnnotationInstance binding : beanArchiveImmutableIndex.getAnnotations(DotNames.INTERCEPTOR_BINDING)) {
702708
ClassInfo bindingClass = binding.target().asClass();
703709
if (isExcluded(bindingClass)) {
704710
continue;
@@ -709,7 +715,6 @@ private Map<DotName, ClassInfo> findInterceptorBindings(IndexView index) {
709715
}
710716

711717
private static Map<DotName, Set<AnnotationInstance>> findTransitiveInterceptorBindings(Collection<DotName> initialBindings,
712-
IndexView index,
713718
Map<DotName, Set<AnnotationInstance>> result, Map<DotName, ClassInfo> interceptorBindings,
714719
AnnotationStore annotationStore) {
715720
// for all known interceptor bindings
@@ -748,20 +753,20 @@ private static Set<AnnotationInstance> recursiveBuild(DotName name,
748753
return result;
749754
}
750755

751-
private Map<DotName, StereotypeInfo> findStereotypes(IndexView index, Map<DotName, ClassInfo> interceptorBindings,
756+
private Map<DotName, StereotypeInfo> findStereotypes(Map<DotName, ClassInfo> interceptorBindings,
752757
Map<ScopeInfo, Function<MethodCreator, ResultHandle>> customContexts,
753758
Set<DotName> additionalStereotypes, AnnotationStore annotationStore) {
754759

755760
Map<DotName, StereotypeInfo> stereotypes = new HashMap<>();
756761

757762
Set<DotName> stereotypeNames = new HashSet<>();
758-
for (AnnotationInstance annotation : index.getAnnotations(DotNames.STEREOTYPE)) {
763+
for (AnnotationInstance annotation : beanArchiveImmutableIndex.getAnnotations(DotNames.STEREOTYPE)) {
759764
stereotypeNames.add(annotation.target().asClass().name());
760765
}
761766
stereotypeNames.addAll(additionalStereotypes);
762767

763768
for (DotName stereotypeName : stereotypeNames) {
764-
ClassInfo stereotypeClass = getClassByName(index, stereotypeName);
769+
ClassInfo stereotypeClass = getClassByName(getBeanArchiveIndex(), stereotypeName);
765770
if (stereotypeClass != null && !isExcluded(stereotypeClass)) {
766771

767772
boolean isAlternative = false;
@@ -852,7 +857,8 @@ private List<BeanInfo> findBeans(Collection<DotName> beanDefiningAnnotations, Li
852857
.map(StereotypeInfo::getName)
853858
.collect(Collectors.toSet());
854859

855-
for (ClassInfo beanClass : beanArchiveIndex.getKnownClasses()) {
860+
// If needed use the specialized immutable index to discover beans
861+
for (ClassInfo beanClass : beanArchiveImmutableIndex.getKnownClasses()) {
856862

857863
if (Modifier.isInterface(beanClass.flags()) || Modifier.isAbstract(beanClass.flags())
858864
|| beanClass.isAnnotation() || beanClass.isEnum()) {
@@ -987,7 +993,7 @@ private List<BeanInfo> findBeans(Collection<DotName> beanDefiningAnnotations, Li
987993
}
988994
DotName superType = aClass.superName();
989995
aClass = superType != null && !superType.equals(DotNames.OBJECT)
990-
? getClassByName(beanArchiveIndex, superType)
996+
? getClassByName(getBeanArchiveIndex(), superType)
991997
: null;
992998
}
993999
for (FieldInfo field : beanClass.fields()) {
@@ -1233,7 +1239,7 @@ static void processErrors(List<Throwable> errors) {
12331239

12341240
private List<InterceptorInfo> findInterceptors(List<InjectionPointInfo> injectionPoints) {
12351241
Map<DotName, ClassInfo> interceptorClasses = new HashMap<>();
1236-
for (AnnotationInstance annotation : beanArchiveIndex.getAnnotations(DotNames.INTERCEPTOR)) {
1242+
for (AnnotationInstance annotation : beanArchiveImmutableIndex.getAnnotations(DotNames.INTERCEPTOR)) {
12371243
if (Kind.CLASS.equals(annotation.target().kind())) {
12381244
interceptorClasses.put(annotation.target().asClass().name(), annotation.target().asClass());
12391245
}
@@ -1260,7 +1266,7 @@ private List<InterceptorInfo> findInterceptors(List<InjectionPointInfo> injectio
12601266

12611267
private List<DecoratorInfo> findDecorators(List<InjectionPointInfo> injectionPoints) {
12621268
Map<DotName, ClassInfo> decoratorClasses = new HashMap<>();
1263-
for (AnnotationInstance annotation : beanArchiveIndex.getAnnotations(DotNames.DECORATOR)) {
1269+
for (AnnotationInstance annotation : beanArchiveImmutableIndex.getAnnotations(DotNames.DECORATOR)) {
12641270
if (Kind.CLASS.equals(annotation.target().kind())) {
12651271
decoratorClasses.put(annotation.target().asClass().name(), annotation.target().asClass());
12661272
}

0 commit comments

Comments
 (0)