Skip to content

Commit

Permalink
Quarkus ArC integration refactoring
Browse files Browse the repository at this point in the history
- modify SyntheticBeanBuildItem so that it can be used for "regular" synthetic beans, i.e. no recorder proxy is needed
- introduce BeanDiscoveryFinishedBuildItem and SynthesisFinishedBuildItem
- introduce the "CDI Integration Guide" and remove the relevant parts from the reference guide
- deprecate some build items
- code refactoring

Co-authored-by: Chris Laprun <[email protected]>
Co-authored-by: Matej Novotny <[email protected]>
Co-authored-by: Guillaume Smet <[email protected]>
  • Loading branch information
4 people committed Dec 9, 2020
1 parent 337e9fa commit 0cef176
Show file tree
Hide file tree
Showing 38 changed files with 1,351 additions and 854 deletions.
532 changes: 532 additions & 0 deletions docs/src/main/asciidoc/cdi-integration.adoc

Large diffs are not rendered by default.

388 changes: 4 additions & 384 deletions docs/src/main/asciidoc/cdi-reference.adoc

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/src/main/asciidoc/cdi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public class Translator {
<2> This is a field injection point. It tells the container that `Translator` depends on the `Dictionary` bean. If there is no matching bean the build fails.
<3> This is an interceptor binding annotation. In this case, the annotation comes from the MicroProfile Metrics. The relevant interceptor intercepts the invocation and updates the relevant metrics. We will talk about <<interceptors,interceptors>> later.

[[typesafe_resolution]]
== Nice. How does the dependency resolution work? I see no names or identifiers.

That's a good question.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,16 @@
import io.quarkus.arc.processor.BeanConfigurator;
import io.quarkus.arc.processor.BeanDefiningAnnotation;
import io.quarkus.arc.processor.BeanDeployment;
import io.quarkus.arc.processor.BeanDeploymentValidator;
import io.quarkus.arc.processor.BeanInfo;
import io.quarkus.arc.processor.BeanProcessor;
import io.quarkus.arc.processor.BeanRegistrar;
import io.quarkus.arc.processor.BytecodeTransformer;
import io.quarkus.arc.processor.ContextConfigurator;
import io.quarkus.arc.processor.ContextRegistrar;
import io.quarkus.arc.processor.DotNames;
import io.quarkus.arc.processor.ObserverConfigurator;
import io.quarkus.arc.processor.ObserverRegistrar;
import io.quarkus.arc.processor.ReflectionRegistration;
import io.quarkus.arc.processor.ResourceOutput;
import io.quarkus.arc.processor.StereotypeInfo;
Expand Down Expand Up @@ -91,6 +94,7 @@
* <ol>
* <li>{@link ContextRegistrationPhaseBuildItem}</li>
* <li>{@link BeanRegistrationPhaseBuildItem}</li>
* <li>{@link ObserverRegistrationPhaseBuildItem}</li>
* <li>{@link ValidationPhaseBuildItem}</li>
* </ol>
* These build items are especially useful if an extension needs to produce other build items within the given phase.
Expand Down Expand Up @@ -123,7 +127,7 @@ AdditionalBeanBuildItem quarkusApplication(CombinedIndexBuildItem combinedIndexB
.build();
}

// PHASE 1 - build BeanProcessor, register custom contexts
// PHASE 1 - build BeanProcessor
@BuildStep
public ContextRegistrationPhaseBuildItem initialize(
ArcConfig arcConfig,
Expand All @@ -143,10 +147,9 @@ public ContextRegistrationPhaseBuildItem initialize(
List<BeanDeploymentValidatorBuildItem> beanDeploymentValidators,
List<ResourceAnnotationBuildItem> resourceAnnotations,
List<BeanDefiningAnnotationBuildItem> additionalBeanDefiningAnnotations,
List<UnremovableBeanBuildItem> removalExclusions,
Optional<TestClassPredicateBuildItem> testClassPredicate,
Capabilities capabilities,
CustomScopeAnnotationsBuildItem scopes,
CustomScopeAnnotationsBuildItem customScopes,
LaunchModeBuildItem launchModeBuildItem) {

if (!arcConfig.isRemoveUnusedBeansFieldValid()) {
Expand Down Expand Up @@ -196,7 +199,7 @@ public void transform(TransformationContext transformationContext) {
// Not an additional bean type
return;
}
if (scopes.isScopeDeclaredOn(beanClass)) {
if (customScopes.isScopeDeclaredOn(beanClass)) {
// If it declares a scope no action is needed
return;
}
Expand Down Expand Up @@ -278,9 +281,6 @@ protected DotName getDotName(BeanInfo bean) {
builder.addRemovalExclusion(new BeanClassAnnotationExclusion(annotation.getName()));
}
}
for (UnremovableBeanBuildItem exclusion : removalExclusions) {
builder.addRemovalExclusion(exclusion.getPredicate());
}
// unremovable beans specified in application.properties
if (arcConfig.unremovableTypes.isPresent()) {
List<Predicate<ClassInfo>> classPredicates = initClassPredicates(arcConfig.unremovableTypes.get());
Expand Down Expand Up @@ -366,6 +366,7 @@ public Integer compute(AnnotationTarget target, Collection<StereotypeInfo> stere
public BeanRegistrationPhaseBuildItem registerBeans(ContextRegistrationPhaseBuildItem contextRegistrationPhase,
List<ContextConfiguratorBuildItem> contextConfigurators,
BuildProducer<InterceptorResolverBuildItem> interceptorResolver,
BuildProducer<BeanDiscoveryFinishedBuildItem> beanDiscoveryFinished,
BuildProducer<TransformedAnnotationsBuildItem> transformedAnnotations) {

for (ContextConfiguratorBuildItem contextConfigurator : contextConfigurators) {
Expand All @@ -374,13 +375,15 @@ public BeanRegistrationPhaseBuildItem registerBeans(ContextRegistrationPhaseBuil
value.done();
}
}
contextRegistrationPhase.getBeanProcessor().registerScopes();
BeanDeployment beanDeployment = contextRegistrationPhase.getBeanProcessor().getBeanDeployment();
BeanProcessor beanProcessor = contextRegistrationPhase.getBeanProcessor();
beanProcessor.registerScopes();
BeanRegistrar.RegistrationContext registrationContext = beanProcessor.registerBeans();
BeanDeployment beanDeployment = beanProcessor.getBeanDeployment();
interceptorResolver.produce(new InterceptorResolverBuildItem(beanDeployment));
beanDiscoveryFinished.produce(new BeanDiscoveryFinishedBuildItem(beanDeployment));
transformedAnnotations.produce(new TransformedAnnotationsBuildItem(beanDeployment));

return new BeanRegistrationPhaseBuildItem(contextRegistrationPhase.getBeanProcessor().registerBeans(),
contextRegistrationPhase.getBeanProcessor());
return new BeanRegistrationPhaseBuildItem(registrationContext, beanProcessor);
}

// PHASE 3 - register synthetic observers
Expand All @@ -393,25 +396,35 @@ public ObserverRegistrationPhaseBuildItem registerSyntheticObservers(BeanRegistr
configurator.getValues().forEach(BeanConfigurator::done);
}

return new ObserverRegistrationPhaseBuildItem(beanRegistrationPhase.getBeanProcessor().registerSyntheticObservers(),
beanRegistrationPhase.getBeanProcessor());
BeanProcessor beanProcessor = beanRegistrationPhase.getBeanProcessor();
ObserverRegistrar.RegistrationContext registrationContext = beanProcessor.registerSyntheticObservers();

return new ObserverRegistrationPhaseBuildItem(registrationContext, beanProcessor);
}

// PHASE 4 - initialize and validate the bean deployment
@BuildStep
public ValidationPhaseBuildItem validate(ObserverRegistrationPhaseBuildItem observerRegistrationPhase,
List<ObserverConfiguratorBuildItem> observerConfigurators,
BuildProducer<BytecodeTransformerBuildItem> bytecodeTransformer) {
List<UnremovableBeanBuildItem> unremovableBeans,
BuildProducer<BytecodeTransformerBuildItem> bytecodeTransformer,
BuildProducer<SynthesisFinishedBuildItem> synthesisFinished) {

for (ObserverConfiguratorBuildItem configurator : observerConfigurators) {
// Just make sure the configurator is processed
configurator.getValues().forEach(ObserverConfigurator::done);
}

BeanProcessor beanProcessor = observerRegistrationPhase.getBeanProcessor();
synthesisFinished.produce(new SynthesisFinishedBuildItem(beanProcessor.getBeanDeployment()));

Consumer<BytecodeTransformer> bytecodeTransformerConsumer = new BytecodeTransformerConsumer(bytecodeTransformer);
observerRegistrationPhase.getBeanProcessor().initialize(bytecodeTransformerConsumer);
return new ValidationPhaseBuildItem(observerRegistrationPhase.getBeanProcessor().validate(bytecodeTransformerConsumer),
observerRegistrationPhase.getBeanProcessor());

beanProcessor.initialize(bytecodeTransformerConsumer,
unremovableBeans.stream().map(UnremovableBeanBuildItem::getPredicate).collect(Collectors.toList()));
BeanDeploymentValidator.ValidationContext validationContext = beanProcessor.validate(bytecodeTransformerConsumer);

return new ValidationPhaseBuildItem(validationContext, beanProcessor);
}

// PHASE 5 - generate resources and initialize the container
Expand Down Expand Up @@ -490,7 +503,6 @@ public void registerField(FieldInfo fieldInfo) {
.collect(Collectors.toList()));

return new BeanContainerBuildItem(beanContainer);

}

@BuildStep
Expand All @@ -516,11 +528,15 @@ AdditionalBeanBuildItem loggerProducer() {
}

@BuildStep
CustomScopeAnnotationsBuildItem exposeCustomScopeNames(List<ContextRegistrarBuildItem> contextBuildItems) {
CustomScopeAnnotationsBuildItem exposeCustomScopeNames(List<ContextRegistrarBuildItem> contextBuildItems,
List<CustomScopeBuildItem> customScopes) {
Set<DotName> names = new HashSet<>();
for (ContextRegistrarBuildItem item : contextBuildItems) {
names.addAll(item.getAnnotationNames());
}
for (CustomScopeBuildItem customScope : customScopes) {
names.add(customScope.getAnnotationName());
}
return new CustomScopeAnnotationsBuildItem(names);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.quarkus.arc.deployment;

import java.util.List;
import java.util.Set;

import org.jboss.jandex.DotName;
Expand All @@ -25,13 +24,10 @@ public final class BeanArchiveIndexBuildItem extends SimpleBuildItem {

private final IndexView index;
private final Set<DotName> generatedClassNames;
private final List<String> additionalBeans;

public BeanArchiveIndexBuildItem(IndexView index, Set<DotName> generatedClassNames,
List<String> additionalBeans) {
public BeanArchiveIndexBuildItem(IndexView index, Set<DotName> generatedClassNames) {
this.index = index;
this.generatedClassNames = generatedClassNames;
this.additionalBeans = additionalBeans;
}

public IndexView getIndex() {
Expand All @@ -42,15 +38,4 @@ public Set<DotName> getGeneratedClassNames() {
return generatedClassNames;
}

/**
* This method will be removed at some point post Quarkus 1.9.
*
* @return the list of additional beans
* @deprecated Use {@link AdditionalBeanBuildItem} instead
*/
@Deprecated
public List<String> getAdditionalBeans() {
return additionalBeans;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import java.util.Set;
import java.util.stream.Collectors;

import javax.inject.Inject;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget.Kind;
import org.jboss.jandex.CompositeIndex;
Expand Down Expand Up @@ -36,39 +34,30 @@

public class BeanArchiveProcessor {

@Inject
ApplicationArchivesBuildItem applicationArchivesBuildItem;

@Inject
List<BeanDefiningAnnotationBuildItem> additionalBeanDefiningAnnotations;

@Inject
List<AdditionalBeanBuildItem> additionalBeans;

@Inject
List<GeneratedBeanBuildItem> generatedBeans;

ArcConfig config;

@BuildStep
public BeanArchiveIndexBuildItem build(LiveReloadBuildItem liveReloadBuildItem,
BuildProducer<GeneratedClassBuildItem> generatedClass) throws Exception {
public BeanArchiveIndexBuildItem build(ArcConfig config, ApplicationArchivesBuildItem applicationArchivesBuildItem,
List<BeanDefiningAnnotationBuildItem> additionalBeanDefiningAnnotations,
List<AdditionalBeanBuildItem> additionalBeans, List<GeneratedBeanBuildItem> generatedBeans,
LiveReloadBuildItem liveReloadBuildItem, BuildProducer<GeneratedClassBuildItem> generatedClass,
CustomScopeAnnotationsBuildItem customScopes)
throws Exception {

// First build an index from application archives
IndexView applicationIndex = buildApplicationIndex();
IndexView applicationIndex = buildApplicationIndex(config, applicationArchivesBuildItem,
additionalBeanDefiningAnnotations, customScopes);

// Then build additional index for beans added by extensions
Indexer additionalBeanIndexer = new Indexer();
List<String> additionalBeans = new ArrayList<>();
for (AdditionalBeanBuildItem i : this.additionalBeans) {
additionalBeans.addAll(i.getBeanClasses());
List<String> additionalBeanClasses = new ArrayList<>();
for (AdditionalBeanBuildItem i : additionalBeans) {
additionalBeanClasses.addAll(i.getBeanClasses());
}
// NOTE: the types added directly must always declare a scope annotation otherwise they will be ignored during bean discovery
additionalBeans.add(LifecycleEventRunner.class.getName());
additionalBeanClasses.add(LifecycleEventRunner.class.getName());

// Build the index for additional beans and generated bean classes
Set<DotName> additionalIndex = new HashSet<>();
for (String beanClass : additionalBeans) {
for (String beanClass : additionalBeanClasses) {
IndexingUtil.indexClass(beanClass, additionalBeanIndexer, applicationIndex, additionalIndex,
Thread.currentThread().getContextClassLoader());
}
Expand All @@ -93,11 +82,12 @@ public BeanArchiveIndexBuildItem build(LiveReloadBuildItem liveReloadBuildItem,
BeanArchives.buildBeanArchiveIndex(Thread.currentThread().getContextClassLoader(), index.getAdditionalClasses(),
applicationIndex,
additionalBeanIndexer.complete()),
generatedClassNames,
additionalBeans);
generatedClassNames);
}

private IndexView buildApplicationIndex() {
private IndexView buildApplicationIndex(ArcConfig config, ApplicationArchivesBuildItem applicationArchivesBuildItem,
List<BeanDefiningAnnotationBuildItem> additionalBeanDefiningAnnotations,
CustomScopeAnnotationsBuildItem customScopes) {

Set<ApplicationArchive> archives = applicationArchivesBuildItem.getAllApplicationArchives();

Expand All @@ -114,18 +104,21 @@ private IndexView buildApplicationIndex() {
}
}

Collection<DotName> beanDefiningAnnotations = BeanDeployment
Set<DotName> beanDefiningAnnotations = BeanDeployment
.initBeanDefiningAnnotations(additionalBeanDefiningAnnotations.stream()
.map(bda -> new BeanDefiningAnnotation(bda.getName(), bda.getDefaultScope()))
.collect(Collectors.toList()), stereotypes);
for (DotName customScopeAnnotationName : customScopes.getCustomScopeNames()) {
beanDefiningAnnotations.add(customScopeAnnotationName);
}
// Also include archives that are not bean archives but contain qualifiers or interceptor bindings
beanDefiningAnnotations.add(DotNames.QUALIFIER);
beanDefiningAnnotations.add(DotNames.INTERCEPTOR_BINDING);

List<IndexView> indexes = new ArrayList<>();

for (ApplicationArchive archive : applicationArchivesBuildItem.getApplicationArchives()) {
if (isApplicationArchiveExcluded(archive)) {
if (isApplicationArchiveExcluded(config, archive)) {
continue;
}
IndexView index = archive.getIndex();
Expand All @@ -140,7 +133,7 @@ && containsBeanDefiningAnnotation(index, beanDefiningAnnotations))) {
return CompositeIndex.create(indexes);
}

private boolean isApplicationArchiveExcluded(ApplicationArchive archive) {
private boolean isApplicationArchiveExcluded(ArcConfig config, ApplicationArchive archive) {
if (archive.getArtifactKey() != null) {
AppArtifactKey key = archive.getArtifactKey();
for (IndexDependencyConfig excludeDependency : config.excludeDependency.values()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
/**
* Register a custom {@link BeanDeploymentValidator} which can either perform additional validation or enforce
* validation skip for certain components.
*
* @see NoArgsConstructorProcessor#addMissingConstructors()
* @see ObserverValidationProcessor
*
* This build item will be removed at some point post Quarkus 1.11.
*
* @deprecated Use {@link ValidationPhaseBuildItem} instead
*/
@Deprecated
public final class BeanDeploymentValidatorBuildItem extends MultiBuildItem {

private final BeanDeploymentValidator beanDeploymentValidator;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.quarkus.arc.deployment;

import io.quarkus.arc.processor.BeanDeployment;

/**
* Consumers of this build item can easily inspect all class-based beans, observers and injection points registered in the
* application. Synthetic beans and observers are not included. If you need to consider synthetic components as well use
* the {@link SynthesisFinishedBuildItem} instead.
* <p>
* Additionaly, the bean resolver can be used to apply the type-safe resolution rules, e.g. to find out wheter there is a bean
* that would satisfy certain combination of required type and qualifiers.
*
* @see SynthesisFinishedBuildItem
*/
public final class BeanDiscoveryFinishedBuildItem extends RegisteredComponentsBuildItem {

public BeanDiscoveryFinishedBuildItem(BeanDeployment beanDeployment) {
super(beanDeployment);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
* specify a synthetic bean through series of configuration methods (scope, type, qualifiers, ...).
*
* This is a build time alternative to CDI BeanConfigurator API.
*
* This build item will be removed at some point post Quarkus 1.11.
*
* @deprecated Use {@link SyntheticBeanBuildItem} instead
*/
@Deprecated
public final class BeanRegistrarBuildItem extends MultiBuildItem {

private final BeanRegistrar beanRegistrar;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package io.quarkus.arc.deployment;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import io.quarkus.arc.processor.BeanConfigurator;
import io.quarkus.arc.processor.BeanProcessor;
import io.quarkus.arc.processor.BeanRegistrar;
import io.quarkus.arc.processor.BeanRegistrar.RegistrationContext;
import io.quarkus.arc.processor.BuildExtension;
import io.quarkus.arc.processor.InjectionPointInfo;
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.deployment.annotations.BuildProducer;
Expand Down Expand Up @@ -36,6 +39,10 @@ public RegistrationContext getContext() {
return context;
}

public Collection<InjectionPointInfo> getInjectionPoints() {
return getContext().get(BuildExtension.Key.INJECTION_POINTS);
}

public BeanProcessor getBeanProcessor() {
return beanProcessor;
}
Expand Down
Loading

0 comments on commit 0cef176

Please sign in to comment.