Skip to content

Commit 81cfe2d

Browse files
committed
Allow package info to be resolved as a dependency
fix for #1564 exclude package-info classes from package metrics calculations Signed-off-by: John Burns <wakingrufus@gmail.com>
1 parent 01a643c commit 81cfe2d

File tree

10 files changed

+107
-3
lines changed

10 files changed

+107
-3
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ public static void completeClassHierarchy(JavaClass javaClass, ImportContext imp
7676
javaClass.completeClassHierarchyFrom(importContext);
7777
}
7878

79+
public static void completePackage(JavaClass javaClass, ImportContext importContext) {
80+
javaClass.completePackageInfoFrom(importContext);
81+
}
82+
7983
public static void completeEnclosingDeclaration(JavaClass javaClass, ImportContext importContext) {
8084
javaClass.completeEnclosingDeclarationFrom(importContext);
8185
}

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package com.tngtech.archunit.core.domain;
1717

1818
import java.lang.annotation.Annotation;
19+
import java.util.Arrays;
1920
import java.util.Collections;
2021
import java.util.HashSet;
2122
import java.util.List;
@@ -1429,6 +1430,13 @@ void completeClassHierarchyFrom(ImportContext context) {
14291430
completionProcess.markClassHierarchyComplete();
14301431
}
14311432

1433+
void completePackageInfoFrom(ImportContext context) {
1434+
this.javaPackage = JavaPackage.from(Arrays.asList(
1435+
this,
1436+
context.resolveClass(this.getPackageName() + ".package-info")));
1437+
completionProcess.markPackageComplete();
1438+
}
1439+
14321440
private void completeSuperclassFrom(ImportContext context) {
14331441
Optional<JavaClass> rawSuperclass = context.createSuperclass(this);
14341442
if (rawSuperclass.isPresent()) {
@@ -1663,6 +1671,10 @@ public void markAnnotationsComplete() {
16631671
@Override
16641672
public void markDependenciesComplete() {
16651673
}
1674+
1675+
@Override
1676+
public void markPackageComplete() {
1677+
}
16661678
};
16671679

16681680
abstract boolean hasFinished();
@@ -1683,6 +1695,8 @@ public void markDependenciesComplete() {
16831695

16841696
public abstract void markDependenciesComplete();
16851697

1698+
public abstract void markPackageComplete();
1699+
16861700
static CompletionProcess start() {
16871701
return new FullCompletionProcess();
16881702
}
@@ -1701,6 +1715,7 @@ private static class FullCompletionProcess extends CompletionProcess {
17011715
private boolean membersComplete = false;
17021716
private boolean annotationsComplete = false;
17031717
private boolean dependenciesComplete = false;
1718+
private boolean packageComplete = false;
17041719

17051720
@Override
17061721
boolean hasFinished() {
@@ -1711,7 +1726,8 @@ boolean hasFinished() {
17111726
&& genericInterfacesComplete
17121727
&& membersComplete
17131728
&& annotationsComplete
1714-
&& dependenciesComplete;
1729+
&& dependenciesComplete
1730+
&& packageComplete;
17151731
}
17161732

17171733
@Override
@@ -1753,6 +1769,11 @@ public void markAnnotationsComplete() {
17531769
public void markDependenciesComplete() {
17541770
this.dependenciesComplete = true;
17551771
}
1772+
1773+
@Override
1774+
public void markPackageComplete() {
1775+
this.packageComplete = true;
1776+
}
17561777
}
17571778

17581779
/**

archunit/src/main/java/com/tngtech/archunit/core/importer/ClassFileProcessor.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ public void onNewClass(String className, Optional<String> superclassName, List<S
9999
}
100100
importRecord.addInterfaces(ownerName, interfaceNames);
101101
dependencyResolutionProcess.registerSupertypes(interfaceNames);
102-
}
102+
if(!className.endsWith(".package-info")) {
103+
String packageName = className.substring(0, className.lastIndexOf("."));
104+
dependencyResolutionProcess.registerPackageInfo(packageName + ".package-info");
105+
}
106+
}
103107

104108
@Override
105109
public void onDeclaredTypeParameters(JavaClassTypeParametersBuilder typeParametersBuilder) {

archunit/src/main/java/com/tngtech/archunit/core/importer/ClassGraphCreator.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.completeGenericInterfaces;
7474
import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.completeGenericSuperclass;
7575
import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.completeMembers;
76+
import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.completePackage;
7677
import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.completeTypeParameters;
7778
import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.createInstanceofCheck;
7879
import static com.tngtech.archunit.core.domain.DomainObjectCreationContext.createJavaClasses;
@@ -119,6 +120,7 @@ private void completeClasses() {
119120
completeGenericInterfaces(javaClass, this);
120121
completeMembers(javaClass, this);
121122
completeAnnotations(javaClass, this);
123+
completePackage(javaClass, this);
122124
}
123125
}
124126

archunit/src/main/java/com/tngtech/archunit/core/importer/DependencyResolutionProcess.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ class DependencyResolutionProcess {
6464
private final int maxRunsForGenericSignatureTypes = getConfiguredIterations(
6565
MAX_ITERATIONS_FOR_GENERIC_SIGNATURE_TYPES_PROPERTY_NAME, MAX_ITERATIONS_FOR_GENERIC_SIGNATURE_TYPES_DEFAULT_VALUE);
6666

67+
static final String MAX_ITERATIONS_FOR_PACKAGE_INFO_PROPERTY_NAME = "maxIterationsForPackageInfo";
68+
static final int MAX_ITERATIONS_FOR_PACKAGE_INFO_DEFAULT_VALUE = -1;
69+
private final int maxRunsForPackageInfo = getConfiguredIterations(
70+
MAX_ITERATIONS_FOR_PACKAGE_INFO_PROPERTY_NAME, MAX_ITERATIONS_FOR_PACKAGE_INFO_DEFAULT_VALUE);
71+
6772
private Set<String> currentTypeNames = new HashSet<>();
6873
private int runNumber = 1;
6974
private boolean shouldContinue;
@@ -116,6 +121,12 @@ void registerGenericSignatureType(String typeName) {
116121
}
117122
}
118123

124+
void registerPackageInfo(String typeName) {
125+
if (runNumberHasNotExceeded(maxRunsForPackageInfo)) {
126+
currentTypeNames.add(typeName);
127+
}
128+
}
129+
119130
void resolve(ImportedClasses classes) {
120131
logConfiguration();
121132
do {

archunit/src/main/java/com/tngtech/archunit/library/metrics/MetricsComponents.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Map;
2020
import java.util.Optional;
2121
import java.util.function.Function;
22+
import java.util.stream.Collectors;
2223

2324
import com.google.common.collect.HashMultimap;
2425
import com.google.common.collect.ImmutableSet;
@@ -121,7 +122,12 @@ public static <T> MetricsComponents<T> from(Collection<T> elements, Function<? s
121122
public static MetricsComponents<JavaClass> fromPackages(Collection<JavaPackage> packages) {
122123
ImmutableSet.Builder<MetricsComponent<JavaClass>> components = ImmutableSet.builder();
123124
for (JavaPackage javaPackage : packages) {
124-
components.add(MetricsComponent.of(javaPackage.getName(), javaPackage.getClassesInPackageTree()));
125+
components.add(MetricsComponent.of(
126+
javaPackage.getName(),
127+
javaPackage.getClassesInPackageTree().stream()
128+
.filter(jc -> !jc.getSimpleName().equals("package-info"))
129+
.collect(Collectors.toList())
130+
));
125131
}
126132
return MetricsComponents.of(components.build());
127133
}

archunit/src/test/java/com/tngtech/archunit/core/domain/JavaClassTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import com.tngtech.archunit.base.ArchUnitException.InvalidSyntaxUsageException;
2626
import com.tngtech.archunit.base.DescribedPredicate;
2727
import com.tngtech.archunit.base.HasDescription;
28+
import com.tngtech.archunit.core.domain.packageexamples.annotated.PackageLevelAnnotation;
29+
import com.tngtech.archunit.core.domain.packageexamples.annotated.WithinAnnotatedPackage;
2830
import com.tngtech.archunit.core.domain.testobjects.AAccessingB;
2931
import com.tngtech.archunit.core.domain.testobjects.AExtendingSuperAImplementingInterfaceForA;
3032
import com.tngtech.archunit.core.domain.testobjects.AReferencingB;
@@ -1595,6 +1597,15 @@ public void function_getPackage() {
15951597
.isEqualTo(javaClass.getPackageName());
15961598
}
15971599

1600+
@Test
1601+
public void function_getPackageInfo() {
1602+
JavaClass javaClass = importClassWithContext(WithinAnnotatedPackage.class);
1603+
1604+
assertThat(javaClass.getPackage().isAnnotatedWith(PackageLevelAnnotation.class))
1605+
.as("package info is available")
1606+
.isTrue();
1607+
}
1608+
15981609
@Test
15991610
public void functions_get_members() {
16001611
JavaClass javaClass = importClassWithContext(ClassWithSeveralConstructorsFieldsAndMethods.class);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.tngtech.archunit.core.domain.packageexamples.annotated;
2+
3+
public class WithinAnnotatedPackage {
4+
}

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.ArrayList;
1010
import java.util.HashMap;
1111
import java.util.List;
12+
import java.util.Optional;
1213
import java.util.Map;
1314
import java.util.function.Supplier;
1415

@@ -22,17 +23,20 @@
2223
import com.tngtech.archunit.core.domain.JavaConstructorCall;
2324
import com.tngtech.archunit.core.domain.JavaConstructorReference;
2425
import com.tngtech.archunit.core.domain.JavaEnumConstant;
26+
import com.tngtech.archunit.core.domain.JavaField;
2527
import com.tngtech.archunit.core.domain.JavaFieldAccess;
2628
import com.tngtech.archunit.core.domain.JavaMethod;
2729
import com.tngtech.archunit.core.domain.JavaMethodCall;
2830
import com.tngtech.archunit.core.domain.JavaMethodReference;
31+
import com.tngtech.archunit.core.domain.JavaPackage;
2932
import com.tngtech.archunit.core.domain.JavaParameterizedType;
3033
import com.tngtech.archunit.core.domain.JavaType;
3134
import com.tngtech.archunit.core.domain.JavaWildcardType;
3235
import com.tngtech.archunit.core.domain.ReferencedClassObject;
3336
import com.tngtech.archunit.core.domain.ThrowsDeclaration;
3437
import com.tngtech.archunit.core.domain.properties.HasAnnotations;
3538
import com.tngtech.archunit.core.importer.DependencyResolutionProcessTestUtils.ImporterWithAdjustedResolutionRuns;
39+
import com.tngtech.archunit.core.importer.testexamples.OtherClass;
3640
import com.tngtech.archunit.core.importer.testexamples.SomeAnnotation;
3741
import com.tngtech.archunit.core.importer.testexamples.annotatedclassimport.ClassWithUnimportedAnnotation;
3842
import com.tngtech.archunit.core.importer.testexamples.annotatedparameters.ClassWithMethodWithAnnotatedParameters;
@@ -44,9 +48,11 @@
4448
import com.tngtech.archunit.core.importer.testexamples.annotationresolution.SomeAnnotationWithAnnotationParameter;
4549
import com.tngtech.archunit.core.importer.testexamples.annotationresolution.SomeAnnotationWithClassParameter;
4650
import com.tngtech.archunit.core.importer.testexamples.classhierarchyresolution.Child;
51+
import com.tngtech.archunit.core.importer.testexamples.packageinforesolution.ClassThatReferencesOtherClass;
4752
import com.tngtech.java.junit.dataprovider.DataProvider;
4853
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
4954
import com.tngtech.java.junit.dataprovider.UseDataProvider;
55+
import org.assertj.core.api.Assertions;
5056
import org.junit.Test;
5157
import org.junit.runner.RunWith;
5258

@@ -59,6 +65,7 @@
5965
import static com.tngtech.archunit.core.importer.DependencyResolutionProcess.MAX_ITERATIONS_FOR_GENERIC_SIGNATURE_TYPES_PROPERTY_NAME;
6066
import static com.tngtech.archunit.core.importer.DependencyResolutionProcess.MAX_ITERATIONS_FOR_MEMBER_TYPES_PROPERTY_NAME;
6167
import static com.tngtech.archunit.core.importer.DependencyResolutionProcess.MAX_ITERATIONS_FOR_SUPERTYPES_PROPERTY_NAME;
68+
import static com.tngtech.archunit.core.importer.DependencyResolutionProcess.MAX_ITERATIONS_FOR_PACKAGE_INFO_PROPERTY_NAME;
6269
import static com.tngtech.archunit.core.importer.testexamples.SomeEnum.OTHER_VALUE;
6370
import static com.tngtech.archunit.core.importer.testexamples.SomeEnum.SOME_VALUE;
6471
import static com.tngtech.archunit.core.importer.testexamples.annotatedparameters.ClassWithMethodWithAnnotatedParameters.methodWithOneAnnotatedParameterWithTwoAnnotations;
@@ -620,6 +627,33 @@ class Innermost {
620627
assertThatType(outermost).matches(Outermost.class);
621628
}
622629

630+
@Test
631+
public void automatically_resolves_packages() {
632+
JavaClass otherClass = new ClassFileImporter()
633+
.importClass(OtherClass.class);
634+
635+
JavaPackage checkedClassPackageInfo = otherClass.getPackage();
636+
assertThat(checkedClassPackageInfo.getAnnotations()).hasSize(1);
637+
assertThat(checkedClassPackageInfo.isAnnotatedWith(SomeAnnotation.class)).isTrue();
638+
}
639+
640+
@Test
641+
public void automatically_resolves_dependency_packages() {
642+
JavaClass checkedClass = ImporterWithAdjustedResolutionRuns
643+
.disableAllIterationsExcept(MAX_ITERATIONS_FOR_PACKAGE_INFO_PROPERTY_NAME, MAX_ITERATIONS_FOR_MEMBER_TYPES_PROPERTY_NAME)
644+
.importClass(ClassThatReferencesOtherClass.class);
645+
646+
Optional<JavaField> firstField = checkedClass.getAllFields().stream().findFirst();
647+
assertThat(firstField).isPresent();
648+
JavaClass otherClass = firstField.get().getRawType();
649+
assertThat(otherClass).isFullyImported(true);
650+
651+
JavaPackage otherClassPackageInfo = otherClass.getPackage();
652+
653+
Assertions.assertThat(otherClassPackageInfo.getAnnotations()).hasSize(1);
654+
Assertions.assertThat(otherClassPackageInfo.isAnnotatedWith(SomeAnnotation.class)).isTrue();
655+
}
656+
623657
@DataProvider
624658
public static Object[][] data_automatically_resolves_generic_type_parameter_bounds() {
625659
@SuppressWarnings("unused")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.tngtech.archunit.core.importer.testexamples.packageinforesolution;
2+
3+
import com.tngtech.archunit.core.importer.testexamples.OtherClass;
4+
5+
public class ClassThatReferencesOtherClass {
6+
OtherClass otherClass;
7+
}

0 commit comments

Comments
 (0)