Skip to content

Commit 66d97c5

Browse files
committed
initialize non-imported JavaClass with empty dependencies
So far, if a user would call `JavaClass.getDirectDependency{From/To}Self()` on a class that was not directly imported (e.g. a class that was not present in the original import, but accessed by a class from that import) it would cause a NPE. While we do want to cut the class graph at that point (i.e. not further track dependencies for classes that are not part of the import), we do not want this exceptional behavior. This change fixes the behavior and sets empty dependencies for all non-directly imported classes, be it classes that have been resolved from the classpath later on, or stub classes, because further resolution has been turned off. Resolves: #397 Signed-off-by: Manfred Hanke <[email protected]>
1 parent 44698c9 commit 66d97c5

File tree

2 files changed

+46
-2
lines changed

2 files changed

+46
-2
lines changed

archunit/src/main/java/com/tngtech/archunit/core/domain/JavaClass.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ public Set<JavaMember> get() {
145145
.build();
146146
}
147147
});
148-
private JavaClassDependencies javaClassDependencies;
149-
private ReverseDependencies reverseDependencies;
148+
private JavaClassDependencies javaClassDependencies = new JavaClassDependencies(this); // just for stubs; will be overwritten for imported classes
149+
private ReverseDependencies reverseDependencies = ReverseDependencies.EMPTY; // just for stubs; will be overwritten for imported classes
150150

151151
JavaClass(JavaClassBuilder builder) {
152152
source = checkNotNull(builder.getSource());

archunit/src/test/java/com/tngtech/archunit/core/importer/ClassFileImporterTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@
205205
import static com.tngtech.archunit.testutil.ReflectionTestUtils.field;
206206
import static com.tngtech.archunit.testutil.ReflectionTestUtils.method;
207207
import static com.tngtech.archunit.testutil.TestUtils.namesOf;
208+
import static com.tngtech.java.junit.dataprovider.DataProviders.$;
209+
import static com.tngtech.java.junit.dataprovider.DataProviders.$$;
208210
import static com.tngtech.java.junit.dataprovider.DataProviders.testForEach;
209211
import static java.nio.charset.StandardCharsets.UTF_8;
210212
import static org.junit.Assume.assumeTrue;
@@ -1711,6 +1713,48 @@ public void resolve_missing_dependencies_from_classpath_can_be_toogled() throws
17111713
assertThat(clazz.getSuperClass().get().getMethods()).isEmpty();
17121714
}
17131715

1716+
@DataProvider
1717+
public static Object[][] classes_not_directly_imported() {
1718+
class Element {
1719+
}
1720+
@SuppressWarnings("unused")
1721+
class DependsOnArray {
1722+
Element[] array;
1723+
}
1724+
ArchConfiguration.get().setResolveMissingDependenciesFromClassPath(true);
1725+
JavaClass resolvedFromClasspath = new ClassFileImporter().importClasses(DependsOnArray.class)
1726+
.get(DependsOnArray.class).getField("array").getRawType().getComponentType();
1727+
1728+
ArchConfiguration.get().setResolveMissingDependenciesFromClassPath(false);
1729+
JavaClass stub = new ClassFileImporter().importClasses(DependsOnArray.class)
1730+
.get(DependsOnArray.class).getField("array").getRawType().getComponentType();
1731+
1732+
return $$(
1733+
$("Resolved from classpath", resolvedFromClasspath),
1734+
$("Stub class", stub)
1735+
);
1736+
}
1737+
1738+
@Test
1739+
@UseDataProvider("classes_not_directly_imported")
1740+
public void classes_not_directly_imported_have_empty_dependencies(@SuppressWarnings("unused") String description, JavaClass notDirectlyImported) {
1741+
assertThat(notDirectlyImported.getDirectDependenciesFromSelf()).isEmpty();
1742+
assertThat(notDirectlyImported.getDirectDependenciesToSelf()).isEmpty();
1743+
assertThat(notDirectlyImported.getFieldAccessesToSelf()).isEmpty();
1744+
assertThat(notDirectlyImported.getMethodCallsToSelf()).isEmpty();
1745+
assertThat(notDirectlyImported.getConstructorCallsToSelf()).isEmpty();
1746+
assertThat(notDirectlyImported.getAccessesToSelf()).isEmpty();
1747+
assertThat(notDirectlyImported.getFieldsWithTypeOfSelf()).isEmpty();
1748+
assertThat(notDirectlyImported.getMethodsWithParameterTypeOfSelf()).isEmpty();
1749+
assertThat(notDirectlyImported.getMethodsWithReturnTypeOfSelf()).isEmpty();
1750+
assertThat(notDirectlyImported.getMethodThrowsDeclarationsWithTypeOfSelf()).isEmpty();
1751+
assertThat(notDirectlyImported.getConstructorsWithParameterTypeOfSelf()).isEmpty();
1752+
assertThat(notDirectlyImported.getConstructorsWithThrowsDeclarationTypeOfSelf()).isEmpty();
1753+
assertThat(notDirectlyImported.getAnnotationsWithTypeOfSelf()).isEmpty();
1754+
assertThat(notDirectlyImported.getAnnotationsWithParameterTypeOfSelf()).isEmpty();
1755+
assertThat(notDirectlyImported.getInstanceofChecksWithTypeOfSelf()).isEmpty();
1756+
}
1757+
17141758
@Test
17151759
public void import_is_resilient_against_broken_class_files() throws Exception {
17161760
Class<?> expectedClass = getClass();

0 commit comments

Comments
 (0)