Skip to content

Commit

Permalink
Merge pull request quarkusio#9868 from mkouba/issue-9545
Browse files Browse the repository at this point in the history
ArC - make it possible to exclude types and dependencies
  • Loading branch information
mkouba authored Jun 9, 2020
2 parents 4618401 + d55f738 commit 4dc464a
Show file tree
Hide file tree
Showing 26 changed files with 589 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import org.jboss.jandex.IndexView;

import io.quarkus.bootstrap.model.AppArtifactKey;
import io.quarkus.bootstrap.model.PathsCollection;

/**
Expand Down Expand Up @@ -63,10 +64,17 @@ public interface ApplicationArchive {
PathsCollection getRootDirs();

/**
* Returns paths representing the application root paths.
*
* @return The paths representing the application root paths.
*/
PathsCollection getPaths();

/**
*
* @return the artifact key or null if not available
*/
AppArtifactKey getArtifactKey();

/**
* Convenience method, returns the child path if it exists, otherwise null.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import org.jboss.jandex.IndexView;

import io.quarkus.bootstrap.model.AppArtifactKey;
import io.quarkus.bootstrap.model.PathsCollection;
import io.quarkus.builder.item.MultiBuildItem;

Expand All @@ -14,20 +15,25 @@ public final class ApplicationArchiveImpl extends MultiBuildItem implements Appl
private final PathsCollection rootDirs;
private final boolean jar;
private final PathsCollection paths;
private final AppArtifactKey artifactKey;

public ApplicationArchiveImpl(IndexView indexView, Path archiveRoot, Closeable closeable, boolean jar,
Path archiveLocation) {
this.indexView = indexView;
this.rootDirs = PathsCollection.of(archiveRoot);
this.jar = jar;
this.paths = PathsCollection.of(archiveLocation);
Path archiveLocation, AppArtifactKey artifactKey) {
this(indexView, PathsCollection.of(archiveRoot), PathsCollection.of(archiveLocation), artifactKey);
}

public ApplicationArchiveImpl(IndexView indexView, PathsCollection rootDirs, PathsCollection paths) {
public ApplicationArchiveImpl(IndexView indexView, PathsCollection rootDirs, PathsCollection paths,
AppArtifactKey artifactKey) {
this(indexView, rootDirs, paths, false, artifactKey);
}

private ApplicationArchiveImpl(IndexView indexView, PathsCollection rootDirs, PathsCollection paths, boolean jar,
AppArtifactKey artifactKey) {
this.indexView = indexView;
this.rootDirs = rootDirs;
this.paths = paths;
jar = false;
this.jar = jar;
this.artifactKey = artifactKey;
}

@Override
Expand Down Expand Up @@ -62,4 +68,10 @@ public PathsCollection getRootDirs() {
public PathsCollection getPaths() {
return paths;
}

@Override
public AppArtifactKey getArtifactKey() {
return artifactKey;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ ApplicationArchivesBuildItem build(
markerFiles, root, additionalApplicationArchiveBuildItem, indexDependencyBuildItems, indexCache,
curateOutcomeBuildItem);
return new ApplicationArchivesBuildItem(
new ApplicationArchiveImpl(appindex.getIndex(), root.getRootDirs(), root.getPaths()),
new ApplicationArchiveImpl(appindex.getIndex(), root.getRootDirs(), root.getPaths(), null),
applicationArchives);
}

Expand All @@ -131,7 +131,7 @@ private List<ApplicationArchive> scanForOtherIndexes(QuarkusBuildCloseablesBuild
for (AdditionalApplicationArchiveBuildItem i : additionalApplicationArchives) {
for (Path apPath : i.getPaths()) {
if (!root.getPaths().contains(apPath) && indexedPaths.add(apPath)) {
appArchives.add(createApplicationArchive(buildCloseables, classLoader, indexCache, apPath));
appArchives.add(createApplicationArchive(buildCloseables, classLoader, indexCache, apPath, null));
}
}
}
Expand Down Expand Up @@ -164,7 +164,7 @@ public void addIndexDependencyPaths(List<IndexDependencyBuildItem> indexDependen
}
for (Path path : artifact.getPaths()) {
if (!root.isExcludedFromIndexing(path) && !root.getPaths().contains(path) && indexedDeps.add(path)) {
appArchives.add(createApplicationArchive(buildCloseables, classLoader, indexCache, path));
appArchives.add(createApplicationArchive(buildCloseables, classLoader, indexCache, path, key));
}
}
}
Expand All @@ -175,10 +175,10 @@ public void addIndexDependencyPaths(List<IndexDependencyBuildItem> indexDependen

private static ApplicationArchive createApplicationArchive(QuarkusBuildCloseablesBuildItem buildCloseables,
ClassLoader classLoader,
IndexCache indexCache, Path dep) throws IOException {
IndexCache indexCache, Path dep, AppArtifactKey artifactKey) throws IOException {
final FileSystem fs = Files.isDirectory(dep) ? null : buildCloseables.add(FileSystems.newFileSystem(dep, classLoader));
return new ApplicationArchiveImpl(indexPath(indexCache, dep),
fs == null ? dep : fs.getRootDirectories().iterator().next(), fs, fs != null, dep);
fs == null ? dep : fs.getRootDirectories().iterator().next(), fs, fs != null, dep, artifactKey);
}

private static IndexView indexPath(IndexCache indexCache, Path dep) throws IOException {
Expand Down Expand Up @@ -232,7 +232,7 @@ private static void addMarkerFilePaths(Set<String> applicationArchiveFiles,
}
appArchives
.add(new ApplicationArchiveImpl(indexes.size() == 1 ? indexes.get(0) : CompositeIndex.create(indexes),
rootDirs.build(), artifactPaths));
rootDirs.build(), artifactPaths, dep.getArtifact().getKey()));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ public class IndexDependencyConfig {
* The maven groupId of the artifact to index
*/
@ConfigItem
String groupId;
public String groupId;

/**
* The maven artifactId of the artifact to index
*/
@ConfigItem
String artifactId;
public String artifactId;

/**
* The maven classifier of the artifact to index
*/
@ConfigItem
Optional<String> classifier;
public Optional<String> classifier;

}
33 changes: 31 additions & 2 deletions docs/src/main/asciidoc/cdi-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,39 @@ quarkus.index-dependency.<name>.classifier=(this one is optional)

For example, the following entries ensure that the `org.acme:acme-api` dependency is indexed:

=== How To Exclude Types and Dependencies from Discovery

It may happen that some beans from third-party libraries do not work correctly in Quarkus.
A typical example is a bean injecting a portable extension.
In such case, it's possible to exclude types and dependencies from the bean discovery.
The `quarkus.arc.exclude-types` property accepts a list of string values that are used to match classes that should be excluded.

.Value Examples
|===
|Value|Description
|`org.acme.Foo`| Match the fully qualified name of the class
|`org.acme.*`| Match classes with package `org.acme`
|`org.acme.**`| Match classes where the package starts with `org.acme`
|`Bar`| Match the simple name of the class
|===

.Example application.properties
[source,properties]
----
quarkus.arc.exclude-types=org.acme.Foo,org.acme.*,Bar <1><2><3>
----
<1> Exclude the type `org.acme.Foo`.
<2> Exclude all types from the `org.acme` package.
<3> Exclude all types whose simple name is `Bar`

It is also possible to exclude a dependency artifact that would be otherwise scanned for beans.
For example, because it contains a `beans.xml` descriptor.

.Example application.properties
[source,properties]
----
quarkus.index-dependency.acme.group-id=org.acme <1>
quarkus.index-dependency.acme.artifact-id=acme-api <2>
quarkus.arc.exclude-dependency.acme.group-id=org.acme <1>
quarkus.arc.exclude-dependency.acme.artifact-id=acme-services <2>
----
<1> Value is a group id for a dependency identified by name `acme`.
<2> Value is an artifact id for a dependency identified by name `acme`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import io.quarkus.arc.config.ConfigProperties;
import io.quarkus.deployment.index.IndexDependencyConfig;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigRoot;

Expand Down Expand Up @@ -94,6 +96,29 @@ public class ArcConfig {
@ConfigItem(defaultValue = "true")
public boolean autoProducerMethods;

/**
* The list of types that should be excluded from discovery.
* <p>
* An element value can be:
* <ul>
* <li>a fully qualified class name, i.e. {@code org.acme.Foo}</li>
* <li>a simple class name as defined by {@link Class#getSimpleName()}, i.e. {@code Foo}</li>
* <li>a package name with suffix {@code .*}, i.e. {@code org.acme.*}, matches a package</li>
* <li>a package name with suffix {@code .**}, i.e. {@code org.acme.**}, matches a package that starts with the value</li>
* </ul>
* If any element value matches a discovered type then the type is excluded from discovery, i.e. no beans and observer
* methods are created from this type.
*/
@ConfigItem
public Optional<List<String>> excludeTypes;

/**
* The artifacts that should be excluded from discovery. These artifacts would be otherwise scanned for beans, i.e. they
* contain a Jandex index or a beans.xml descriptor.
*/
@ConfigItem
Map<String, IndexDependencyConfig> excludeDependency;

public final boolean isRemoveUnusedBeansFieldValid() {
return ALLOWED_REMOVE_UNUSED_BEANS_VALUES.contains(removeUnusedBeans.toLowerCase());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ public boolean test(BeanInfo bean) {
builder.setAllowMocking(launchModeBuildItem.getLaunchMode() == LaunchMode.TEST);

if (arcConfig.selectedAlternatives.isPresent()) {
final List<Predicate<ClassInfo>> selectedAlternatives = initAlternativePredicates(
final List<Predicate<ClassInfo>> selectedAlternatives = initClassPredicates(
arcConfig.selectedAlternatives.get());
builder.setAlternativePriorities(new AlternativePriorities() {

Expand Down Expand Up @@ -304,6 +304,13 @@ public Integer compute(AnnotationTarget target, Collection<StereotypeInfo> stere
});
}

if (arcConfig.excludeTypes.isPresent()) {
for (Predicate<ClassInfo> predicate : initClassPredicates(
arcConfig.excludeTypes.get())) {
builder.addExcludeType(predicate);
}
}

BeanProcessor beanProcessor = builder.build();
ContextRegistrar.RegistrationContext context = beanProcessor.registerCustomContexts();
return new ContextRegistrationPhaseBuildItem(context, beanProcessor);
Expand Down Expand Up @@ -467,7 +474,7 @@ CustomScopeAnnotationsBuildItem exposeCustomScopeNames(List<ContextRegistrarBuil
return new CustomScopeAnnotationsBuildItem(names);
}

private List<Predicate<ClassInfo>> initAlternativePredicates(List<String> selectedAlternatives) {
private List<Predicate<ClassInfo>> initClassPredicates(List<String> selectedAlternatives) {
final String packMatch = ".*";
final String packStarts = ".**";
List<Predicate<ClassInfo>> predicates = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,21 @@
import org.jboss.jandex.IndexView;
import org.jboss.jandex.Indexer;

import com.google.common.base.Objects;

import io.quarkus.arc.processor.BeanArchives;
import io.quarkus.arc.processor.BeanDefiningAnnotation;
import io.quarkus.arc.processor.BeanDeployment;
import io.quarkus.arc.processor.DotNames;
import io.quarkus.arc.runtime.LifecycleEventRunner;
import io.quarkus.bootstrap.model.AppArtifactKey;
import io.quarkus.deployment.ApplicationArchive;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.ApplicationArchivesBuildItem;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
import io.quarkus.deployment.builditem.LiveReloadBuildItem;
import io.quarkus.deployment.index.IndexDependencyConfig;
import io.quarkus.deployment.index.IndexingUtil;

public class BeanArchiveProcessor {
Expand All @@ -46,6 +50,8 @@ public class BeanArchiveProcessor {
@Inject
BuildProducer<GeneratedClassBuildItem> generatedClass;

ArcConfig config;

@BuildStep
public BeanArchiveIndexBuildItem build(LiveReloadBuildItem liveReloadBuildItem) throws Exception {

Expand Down Expand Up @@ -116,6 +122,9 @@ private IndexView buildApplicationIndex() {
List<IndexView> indexes = new ArrayList<>();

for (ApplicationArchive archive : applicationArchivesBuildItem.getApplicationArchives()) {
if (isApplicationArchiveExcluded(archive)) {
continue;
}
IndexView index = archive.getIndex();
// NOTE: Implicit bean archive without beans.xml contains one or more bean classes with a bean defining annotation and no extension
if (archive.getChildPath("META-INF/beans.xml") != null || archive.getChildPath("WEB-INF/beans.xml") != null
Expand All @@ -128,6 +137,20 @@ && containsBeanDefiningAnnotation(index, beanDefiningAnnotations))) {
return CompositeIndex.create(indexes);
}

private boolean isApplicationArchiveExcluded(ApplicationArchive archive) {
if (archive.getArtifactKey() != null) {
AppArtifactKey key = archive.getArtifactKey();
for (IndexDependencyConfig excludeDependency : config.excludeDependency.values()) {
if (Objects.equal(key.getArtifactId(), excludeDependency.artifactId)
&& Objects.equal(key.getGroupId(), excludeDependency.groupId)
&& Objects.equal(key.getClassifier(), excludeDependency.classifier)) {
return true;
}
}
}
return false;
}

boolean containsBeanDefiningAnnotation(IndexView index, Collection<DotName> beanDefiningAnnotations) {
for (DotName beanDefiningAnnotation : beanDefiningAnnotations) {
if (!index.getAnnotations(beanDefiningAnnotation).isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.quarkus.arc.test.exclude;

import javax.enterprise.context.ApplicationScoped;

import io.quarkus.arc.test.exclude.ExcludeTypesTest.Pong;

@ApplicationScoped
class Bravo implements Pong {

public String ping() {
return "bravo";
}

}
Loading

0 comments on commit 4dc464a

Please sign in to comment.