Skip to content

Commit

Permalink
initialize non-imported JavaClass with empty dependencies
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
hankem committed Dec 16, 2020
1 parent 44698c9 commit 66d97c5
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ public Set<JavaMember> get() {
.build();
}
});
private JavaClassDependencies javaClassDependencies;
private ReverseDependencies reverseDependencies;
private JavaClassDependencies javaClassDependencies = new JavaClassDependencies(this); // just for stubs; will be overwritten for imported classes
private ReverseDependencies reverseDependencies = ReverseDependencies.EMPTY; // just for stubs; will be overwritten for imported classes

JavaClass(JavaClassBuilder builder) {
source = checkNotNull(builder.getSource());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@
import static com.tngtech.archunit.testutil.ReflectionTestUtils.field;
import static com.tngtech.archunit.testutil.ReflectionTestUtils.method;
import static com.tngtech.archunit.testutil.TestUtils.namesOf;
import static com.tngtech.java.junit.dataprovider.DataProviders.$;
import static com.tngtech.java.junit.dataprovider.DataProviders.$$;
import static com.tngtech.java.junit.dataprovider.DataProviders.testForEach;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assume.assumeTrue;
Expand Down Expand Up @@ -1711,6 +1713,48 @@ public void resolve_missing_dependencies_from_classpath_can_be_toogled() throws
assertThat(clazz.getSuperClass().get().getMethods()).isEmpty();
}

@DataProvider
public static Object[][] classes_not_directly_imported() {
class Element {
}
@SuppressWarnings("unused")
class DependsOnArray {
Element[] array;
}
ArchConfiguration.get().setResolveMissingDependenciesFromClassPath(true);
JavaClass resolvedFromClasspath = new ClassFileImporter().importClasses(DependsOnArray.class)
.get(DependsOnArray.class).getField("array").getRawType().getComponentType();

ArchConfiguration.get().setResolveMissingDependenciesFromClassPath(false);
JavaClass stub = new ClassFileImporter().importClasses(DependsOnArray.class)
.get(DependsOnArray.class).getField("array").getRawType().getComponentType();

return $$(
$("Resolved from classpath", resolvedFromClasspath),
$("Stub class", stub)
);
}

@Test
@UseDataProvider("classes_not_directly_imported")
public void classes_not_directly_imported_have_empty_dependencies(@SuppressWarnings("unused") String description, JavaClass notDirectlyImported) {
assertThat(notDirectlyImported.getDirectDependenciesFromSelf()).isEmpty();
assertThat(notDirectlyImported.getDirectDependenciesToSelf()).isEmpty();
assertThat(notDirectlyImported.getFieldAccessesToSelf()).isEmpty();
assertThat(notDirectlyImported.getMethodCallsToSelf()).isEmpty();
assertThat(notDirectlyImported.getConstructorCallsToSelf()).isEmpty();
assertThat(notDirectlyImported.getAccessesToSelf()).isEmpty();
assertThat(notDirectlyImported.getFieldsWithTypeOfSelf()).isEmpty();
assertThat(notDirectlyImported.getMethodsWithParameterTypeOfSelf()).isEmpty();
assertThat(notDirectlyImported.getMethodsWithReturnTypeOfSelf()).isEmpty();
assertThat(notDirectlyImported.getMethodThrowsDeclarationsWithTypeOfSelf()).isEmpty();
assertThat(notDirectlyImported.getConstructorsWithParameterTypeOfSelf()).isEmpty();
assertThat(notDirectlyImported.getConstructorsWithThrowsDeclarationTypeOfSelf()).isEmpty();
assertThat(notDirectlyImported.getAnnotationsWithTypeOfSelf()).isEmpty();
assertThat(notDirectlyImported.getAnnotationsWithParameterTypeOfSelf()).isEmpty();
assertThat(notDirectlyImported.getInstanceofChecksWithTypeOfSelf()).isEmpty();
}

@Test
public void import_is_resilient_against_broken_class_files() throws Exception {
Class<?> expectedClass = getClass();
Expand Down

0 comments on commit 66d97c5

Please sign in to comment.