GH-613 - Add SPI to support external ApplicationModuleSource contributions.
We now expose ApplicationModuleSourceFactory as Spring Factories-based SPI interface to further contribute ApplicationModuleSource instances either from a provided root package subject for module detection through a (potentially customized) ApplicationModuleDetectionStrategy or by explicitly listing particular module base packages.
This commit is contained in:
@@ -102,7 +102,7 @@ public class ApplicationModule implements Comparable<ApplicationModule> {
|
||||
Assert.notNull(source, "Base package must not be null!");
|
||||
Assert.notNull(exclusions, "Exclusions must not be null!");
|
||||
|
||||
JavaPackage basePackage = source.moduleBasePackage();
|
||||
JavaPackage basePackage = source.getModuleBasePackage();
|
||||
|
||||
this.source = source;
|
||||
this.basePackage = basePackage;
|
||||
@@ -144,7 +144,7 @@ public class ApplicationModule implements Comparable<ApplicationModule> {
|
||||
* @return will never be {@literal null} or empty.
|
||||
*/
|
||||
public String getName() {
|
||||
return source.moduleName();
|
||||
return source.getModuleName();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.modulith.core;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
@@ -29,9 +30,25 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Drotbohm
|
||||
* @since 1.3
|
||||
*/
|
||||
record ApplicationModuleSource(
|
||||
JavaPackage moduleBasePackage,
|
||||
String moduleName) {
|
||||
public class ApplicationModuleSource {
|
||||
|
||||
private final JavaPackage moduleBasePackage;
|
||||
private final String moduleName;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ApplicationModuleSource} for the given module base package and module name.
|
||||
*
|
||||
* @param moduleBasePackage must not be {@literal null}.
|
||||
* @param moduleName must not be {@literal null} or empty.
|
||||
*/
|
||||
private ApplicationModuleSource(JavaPackage moduleBasePackage, String moduleName) {
|
||||
|
||||
Assert.notNull(moduleBasePackage, "JavaPackage must not be null!");
|
||||
Assert.hasText(moduleName, "Module name must not be null or empty!");
|
||||
|
||||
this.moduleBasePackage = moduleBasePackage;
|
||||
this.moduleName = moduleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Stream} of {@link ApplicationModuleSource}s by applying the given
|
||||
@@ -66,4 +83,46 @@ record ApplicationModuleSource(
|
||||
|
||||
return new ApplicationModuleSource(pkg, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public JavaPackage getModuleBasePackage() {
|
||||
return moduleBasePackage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return will never be {@literal null} or empty.
|
||||
*/
|
||||
public String getModuleName() {
|
||||
return moduleName;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof ApplicationModuleSource that)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Objects.equals(this.moduleName, that.moduleName)
|
||||
&& Objects.equals(this.moduleBasePackage, that.moduleBasePackage);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(moduleName, moduleBasePackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.modulith.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
import com.tngtech.archunit.core.domain.JavaClasses;
|
||||
|
||||
/**
|
||||
* Lookup of external {@link ApplicationModuleSource} contributions via {@link ApplicationModuleSourceFactory}
|
||||
* implementations.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
* @since 1.3
|
||||
*/
|
||||
class ApplicationModuleSourceContributions {
|
||||
|
||||
static String LOCATION = SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION;
|
||||
|
||||
private final List<String> rootPackages;
|
||||
private final List<ApplicationModuleSource> sources;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ApplicationModuleSourceContributions} for the given importer function, default
|
||||
* {@link ApplicationModuleDetectionStrategy} and whether to use fully-qualified module names.
|
||||
*
|
||||
* @param importer must not be {@literal null}.
|
||||
* @param defaultStrategy must not be {@literal null}.
|
||||
* @param useFullyQualifiedModuleNames whether to use fully-qualified module names.
|
||||
*/
|
||||
public static ApplicationModuleSourceContributions of(Function<Collection<String>, JavaClasses> importer,
|
||||
ApplicationModuleDetectionStrategy defaultStrategy, boolean useFullyQualifiedModuleNames) {
|
||||
|
||||
var loader = SpringFactoriesLoader.forResourceLocation(LOCATION, ApplicationModules.class.getClassLoader());
|
||||
|
||||
return new ApplicationModuleSourceContributions(loader.load(ApplicationModuleSourceFactory.class), importer,
|
||||
defaultStrategy, useFullyQualifiedModuleNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ApplicationModuleSourceContributions} for the given {@link ApplicationModuleSourceFactory}s,
|
||||
* importer function, default {@link ApplicationModuleDetectionStrategy} and whether to use fully-qualified module
|
||||
* names.
|
||||
*
|
||||
* @param factories must not be {@literal null}.
|
||||
* @param importer must not be {@literal null}.
|
||||
* @param defaultStrategy must not be {@literal null}.
|
||||
* @param useFullyQualifiedModuleNames whether to use fully-qualified module names.
|
||||
*/
|
||||
ApplicationModuleSourceContributions(List<? extends ApplicationModuleSourceFactory> factories,
|
||||
Function<Collection<String>, JavaClasses> importer,
|
||||
ApplicationModuleDetectionStrategy defaultStrategy, boolean useFullyQualifiedModuleNames) {
|
||||
|
||||
this.rootPackages = new ArrayList<>();
|
||||
this.sources = new ArrayList<>();
|
||||
|
||||
factories.forEach(factory -> {
|
||||
|
||||
var contributedPackages = factory.getRootPackages();
|
||||
var factoryStrategy = factory.getApplicationModuleDetectionStrategy();
|
||||
var classes = importer.apply(contributedPackages);
|
||||
var strategy = factoryStrategy == null ? defaultStrategy : factoryStrategy;
|
||||
|
||||
// Add discovered ApplicationModuleSources
|
||||
|
||||
rootPackages.addAll(contributedPackages);
|
||||
|
||||
contributedPackages.stream()
|
||||
.map(it -> JavaPackage.of(Classes.of(classes), it))
|
||||
.flatMap(it -> factory.getApplicationModuleSources(it, strategy, useFullyQualifiedModuleNames))
|
||||
.forEach(this.sources::add);
|
||||
|
||||
// Add enumerated ApplicationModuleSources
|
||||
|
||||
Function<String, JavaPackage> packageRegistrar = it -> {
|
||||
return JavaPackage.of(Classes.of(importer.apply(List.of(it))), it);
|
||||
};
|
||||
|
||||
factory.getApplicationModuleSources(packageRegistrar, useFullyQualifiedModuleNames).forEach(this.sources::add);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public Stream<String> getRootPackages() {
|
||||
return rootPackages.stream();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
public Stream<ApplicationModuleSource> getSources() {
|
||||
return sources.stream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.modulith.core;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* SPI to allow build units contribute additional {@link ApplicationModuleSource}s in the form of either declaring them
|
||||
* directly via {@link #getModuleBasePackages()} and {@link #getApplicationModuleSources(Function, boolean)} or via
|
||||
* provided {@link #getRootPackages()} and subsequent resolution via
|
||||
* {@link #getApplicationModuleSources(JavaPackage, ApplicationModuleDetectionStrategy, boolean)} for each of the
|
||||
* packages provided. <br>
|
||||
* The following snippet would register {@link ApplicationModuleSource}s for {@code com.acme.foo} and
|
||||
* {@code com.acme.bar} directly:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* class MyCustomFactory implements ApplicationModuleSourceFactory {
|
||||
*
|
||||
* @Override
|
||||
* public List<String> getModuleBasePackages() {
|
||||
* return List.of("com.acme.foo", "com.acme.bar");
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* The following snippet would register all modules located underneath {@code com.acme} found via the
|
||||
* {@link ApplicationModuleDetectionStrategy#explicitlyAnnotated()} strategy:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* class MyCustomFactory implements ApplicationModuleSourceFactory {
|
||||
*
|
||||
* @Override
|
||||
* public List<String> getRootPackages() {
|
||||
* return List.of("com.acme");
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* ApplicationModuleDetectionStrategy getApplicationModuleDetectionStrategy() {
|
||||
* return ApplicationModuleDetectionStrategy.explicitlyAnnotated();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
* @since 1.3
|
||||
*/
|
||||
public interface ApplicationModuleSourceFactory {
|
||||
|
||||
/**
|
||||
* Returns the additional root packages to be considered. The ones returned from this method will be scanned for
|
||||
* {@link ApplicationModuleSource}s via
|
||||
* {@link #getApplicationModuleSources(JavaPackage, ApplicationModuleDetectionStrategy, boolean)} using the
|
||||
* {@link ApplicationModuleDetectionStrategy} returned from {@link #getApplicationModuleDetectionStrategy()}. If the
|
||||
* latter is {@literal null}, the default {@link ApplicationModuleDetectionStrategy} is used.
|
||||
*
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
default List<String> getRootPackages() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns additional module base packages to create {@link ApplicationModuleSource}s from. Subsequently handled by
|
||||
* {@link #getApplicationModuleSources(Function, boolean)}.
|
||||
*
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
default List<String> getModuleBasePackages() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ApplicationModuleDetectionStrategy} to be used to detect {@link ApplicationModuleSource}s from
|
||||
* the packages returned by {@link #getRootPackages()}. If {@literal null} is returned, the default
|
||||
* {@link ApplicationModuleDetectionStrategy} will be used.
|
||||
*
|
||||
* @return can be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
default ApplicationModuleDetectionStrategy getApplicationModuleDetectionStrategy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates all {@link ApplicationModuleSource}s using the given base package and
|
||||
* {@link ApplicationModuleDetectionStrategy}.
|
||||
*
|
||||
* @param rootPackage will never be {@literal null}.
|
||||
* @param strategy will never be {@literal null}.
|
||||
* @param useFullyQualifiedModuleNames whether to use fully-qualified names for application modules.
|
||||
* @return must not be {@literal null}.
|
||||
* @see ApplicationModuleSource#from(JavaPackage, ApplicationModuleDetectionStrategy, boolean)
|
||||
*/
|
||||
default Stream<ApplicationModuleSource> getApplicationModuleSources(JavaPackage rootPackage,
|
||||
ApplicationModuleDetectionStrategy strategy, boolean useFullyQualifiedModuleNames) {
|
||||
|
||||
return ApplicationModuleSource.from(rootPackage, strategy, useFullyQualifiedModuleNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link ApplicationModuleSource} for individually, manually described application modules.
|
||||
*
|
||||
* @param packages will never be {@literal null}.
|
||||
* @param useFullyQualifiedModuleNames whether to use fully-qualified names for application modules.
|
||||
* @return must not be {@literal null}.
|
||||
* @see ApplicationModuleSource#from(JavaPackage, String)
|
||||
*/
|
||||
default Stream<ApplicationModuleSource> getApplicationModuleSources(Function<String, JavaPackage> packages,
|
||||
boolean useFullyQualifiedModuleNames) {
|
||||
|
||||
return getModuleBasePackages().stream()
|
||||
.map(packages)
|
||||
.map(it -> ApplicationModuleSource.from(it, useFullyQualifiedModuleNames ? it.getName() : it.getLocalName()));
|
||||
}
|
||||
}
|
||||
@@ -96,12 +96,11 @@ public class ApplicationModules implements Iterable<ApplicationModule> {
|
||||
*
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @param ignored must not be {@literal null}.
|
||||
* @param useFullyQualifiedModuleNames can be {@literal null}.
|
||||
* @param option must not be {@literal null}.
|
||||
*/
|
||||
protected ApplicationModules(ModulithMetadata metadata,
|
||||
DescribedPredicate<? super JavaClass> ignored, boolean useFullyQualifiedModuleNames, ImportOption option) {
|
||||
this(metadata, metadata.getBasePackages(), ignored, useFullyQualifiedModuleNames, option);
|
||||
DescribedPredicate<? super JavaClass> ignored, ImportOption option) {
|
||||
this(metadata, metadata.getBasePackages(), ignored, metadata.useFullyQualifiedModuleNames(), option);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,8 +112,7 @@ public class ApplicationModules implements Iterable<ApplicationModule> {
|
||||
* @param useFullyQualifiedModuleNames can be {@literal null}.
|
||||
* @param option must not be {@literal null}.
|
||||
* @deprecated since 1.2, for removal in 1.3. Use {@link ApplicationModules(ModulithMetadata, DescribedPredicate,
|
||||
* boolean, ImportOption)} instead and set up {@link ModulithMetadata} to contain the packages you want to
|
||||
* use.
|
||||
* ImportOption)} instead and set up {@link ModulithMetadata} to contain the packages you want to use.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
protected ApplicationModules(ModulithMetadata metadata, Collection<String> packages,
|
||||
@@ -128,8 +126,9 @@ public class ApplicationModules implements Iterable<ApplicationModule> {
|
||||
DescribedPredicate<? super JavaClass> excluded = DescribedPredicate.or(ignored, IS_AOT_TYPE, IS_SPRING_CGLIB_PROXY);
|
||||
|
||||
this.metadata = metadata;
|
||||
this.allClasses = new ClassFileImporter() //
|
||||
.withImportOption(option) //
|
||||
var importer = new ClassFileImporter() //
|
||||
.withImportOption(option);
|
||||
this.allClasses = importer //
|
||||
.importPackages(packages) //
|
||||
.that(not(excluded));
|
||||
|
||||
@@ -138,9 +137,14 @@ public class ApplicationModules implements Iterable<ApplicationModule> {
|
||||
Classes classes = Classes.of(allClasses);
|
||||
var strategy = ApplicationModuleDetectionStrategyLookup.getStrategy();
|
||||
|
||||
var sources = packages.stream() //
|
||||
var contributions = ApplicationModuleSourceContributions.of(
|
||||
pkgs -> importer.importPackages(pkgs).that(not(excluded)), strategy, useFullyQualifiedModuleNames);
|
||||
|
||||
var directSources = packages.stream() //
|
||||
.map(it -> JavaPackage.of(classes, it))
|
||||
.flatMap(it -> ApplicationModuleSource.from(it, strategy, useFullyQualifiedModuleNames))
|
||||
.flatMap(it -> ApplicationModuleSource.from(it, strategy, useFullyQualifiedModuleNames));
|
||||
|
||||
var sources = Stream.concat(directSources, contributions.getSources())
|
||||
.distinct()
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
@@ -148,12 +152,12 @@ public class ApplicationModules implements Iterable<ApplicationModule> {
|
||||
.map(it -> {
|
||||
|
||||
return new ApplicationModule(it,
|
||||
JavaPackages.onlySubPackagesOf(it.moduleBasePackage(),
|
||||
sources.stream().map(ApplicationModuleSource::moduleBasePackage).toList())); //
|
||||
JavaPackages.onlySubPackagesOf(it.getModuleBasePackage(),
|
||||
sources.stream().map(ApplicationModuleSource::getModuleBasePackage).toList())); //
|
||||
})
|
||||
.collect(toMap(ApplicationModule::getName, Function.identity()));
|
||||
|
||||
this.rootPackages = packages.stream() //
|
||||
this.rootPackages = Stream.concat(packages.stream(), contributions.getRootPackages()) //
|
||||
.map(it -> JavaPackage.of(classes, it).toSingle()) //
|
||||
.toList();
|
||||
|
||||
@@ -643,8 +647,7 @@ public class ApplicationModules implements Iterable<ApplicationModule> {
|
||||
return CACHE.computeIfAbsent(cacheKey, key -> {
|
||||
|
||||
var metadata = key.getMetadata();
|
||||
var modules = new ApplicationModules(metadata, key.getIgnored(),
|
||||
metadata.useFullyQualifiedModuleNames(), key.getOptions());
|
||||
var modules = new ApplicationModules(metadata, key.getIgnored(), key.getOptions());
|
||||
|
||||
var sharedModules = metadata.getSharedModuleNames() //
|
||||
.map(modules::getRequiredModule) //
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package contributed;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.modulith.core.ApplicationModuleDetectionStrategy;
|
||||
import org.springframework.modulith.core.ApplicationModuleSourceFactory;
|
||||
|
||||
/**
|
||||
* Example {@link ApplicationModuleSourceFactory}.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
public class ApplicationModuleSourceContribution implements ApplicationModuleSourceFactory {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.modulith.core.ApplicationModuleSourceFactory#getRootPackages()
|
||||
*/
|
||||
@Override
|
||||
public List<String> getRootPackages() {
|
||||
return List.of("contributed");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.modulith.core.ApplicationModuleSourceFactory#getApplicationModuleDetectionStrategy()
|
||||
*/
|
||||
@Override
|
||||
public ApplicationModuleDetectionStrategy getApplicationModuleDetectionStrategy() {
|
||||
return ApplicationModuleDetectionStrategy.explicitlyAnnotated();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.modulith.core.ApplicationModuleSourceFactory#getModuleBasePackages()
|
||||
*/
|
||||
@Override
|
||||
public List<String> getModuleBasePackages() {
|
||||
return List.of("contributed.enumerated");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
@org.springframework.modulith.ApplicationModule
|
||||
package contributed.detected;
|
||||
@@ -0,0 +1 @@
|
||||
package contributed.enumerated;
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.modulith.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import contributed.ApplicationModuleSourceContribution;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.tngtech.archunit.core.importer.ClassFileImporter;
|
||||
import com.tngtech.archunit.core.importer.ImportOption;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ApplicationModuleSourceContributions}.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
* @since 1.3
|
||||
*/
|
||||
class ApplicationModuleSourceContributionsUnitTests {
|
||||
|
||||
@Test // GH-613
|
||||
void detectsContributions() {
|
||||
|
||||
var factories = List.of(new ApplicationModuleSourceContribution());
|
||||
var importer = new ClassFileImporter().withImportOption(new ImportOption.OnlyIncludeTests());
|
||||
var strategy = ApplicationModuleDetectionStrategy.directSubPackage();
|
||||
|
||||
var contributions = new ApplicationModuleSourceContributions(factories, importer::importPackages, strategy, false);
|
||||
|
||||
assertThat(contributions.getRootPackages()).contains("contributed");
|
||||
assertThat(contributions.getSources())
|
||||
.extracting(ApplicationModuleSource::getModuleBasePackage)
|
||||
.extracting(JavaPackage::getName)
|
||||
.containsExactlyInAnyOrder("contributed.detected", "contributed.enumerated");
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,6 @@ public class TestUtils {
|
||||
}
|
||||
|
||||
private static ApplicationModules of(ModulithMetadata metadata, DescribedPredicate<JavaClass> ignores) {
|
||||
return new ApplicationModules(metadata, ignores, false, new ImportOption.OnlyIncludeTests()) {};
|
||||
return new ApplicationModules(metadata, ignores, new ImportOption.OnlyIncludeTests()) {};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user