Skip to content

Commit 80b5500

Browse files
authored
Update Gradle Wrapper from 8.14.3 to 9.5.0 & also run tests with JDK 25 (#1550)
* Update Gradle Wrapper from 8.14.3 to 9.5.0 Release notes: * https://docs.gradle.org/9.0.0/release-notes.html * https://docs.gradle.org/9.1.0/release-notes.html (which supports Java 25) * https://docs.gradle.org/9.2.0/release-notes.html * https://docs.gradle.org/9.3.0/release-notes.html * https://docs.gradle.org/9.4.0/release-notes.html (which supports Java 26) * https://docs.gradle.org/9.5.0/release-notes.html * Also run tests with JDK 25 Release notes: * https://openjdk.org/projects/jdk/25/
2 parents 5ba35ec + 783cd23 commit 80b5500

16 files changed

Lines changed: 73 additions & 60 deletions

.github/workflows/build.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
pull_request:
99

1010
env:
11-
build_java_version: 21
11+
build_java_version: 25
1212

1313
jobs:
1414
build:
@@ -48,6 +48,7 @@ jobs:
4848
- 11
4949
- 17
5050
- 21
51+
- 25
5152
runs-on: ${{ matrix.os }}
5253
steps:
5354
- name: Checkout
@@ -97,6 +98,7 @@ jobs:
9798
- 11
9899
- 17
99100
- 21
101+
- 25
100102
runs-on: ${{ matrix.os }}
101103
steps:
102104
- name: Checkout

.github/workflows/update-gradle-wrapper.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
uses: actions/setup-java@v5.2.0
1616
with:
1717
distribution: 'zulu'
18-
java-version: 17
18+
java-version: 25
1919

2020
- name: Update Gradle Wrapper
2121
uses: gradle-update/update-gradle-wrapper-action@v2.1.0

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ Contributions are very welcome. The following will provide some helpful guidelin
44

55
## How to build the project
66

7-
ArchUnit requires at least JDK 15 to build.
7+
ArchUnit requires at least JDK 25 to build.
88
The following is just an example input/output from a Unix command line.
99
Windows users should use `gradlew.bat` instead.
1010

1111
```
1212
$ cd /path/to/git/clone/of/ArchUnit
1313
$ ./gradlew showJdkVersion
14-
Configured JDK: 15
14+
Configured JDK: 25
1515
$ ./gradlew build
1616
```
1717

archunit/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ compileJdk9mainJava {
9292
dependsOn(compileJava)
9393
ext.minimumJavaVersion = JavaVersion.VERSION_1_9
9494

95-
destinationDir = compileJava.destinationDir
95+
destinationDirectory.set(compileJava.destinationDirectory.get())
9696
}
9797
javadoc.dependsOn(compileJdk9mainJava)
9898
spotbugsMain.dependsOn(compileJdk9mainJava)

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

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
import static com.tngtech.archunit.core.domain.TestUtils.targetFrom;
105105
import static com.tngtech.archunit.core.importer.ClassFileImporterTestUtils.findAnyByName;
106106
import static com.tngtech.archunit.core.importer.ClassFileImporterTestUtils.getByName;
107+
import static com.tngtech.archunit.core.importer.ClassFileImporterTestUtils.getMethodCallsFromClassWithoutAutomaticNullCheck;
107108
import static com.tngtech.archunit.core.importer.DomainBuilders.newMethodCallTargetBuilder;
108109
import static com.tngtech.archunit.testutil.Assertions.assertThat;
109110
import static com.tngtech.archunit.testutil.Assertions.assertThatAccess;
@@ -457,9 +458,10 @@ String covariantlyOverriddenCausingBridgeMethod() {
457458
}
458459

459460
JavaMethodCall callFromBridgeMethodToOverriddenOne = getOnlyElement(
460-
new ClassFileImporter().importClasses(Parent.class, Child.class)
461-
.get(Child.class)
462-
.getMethodCallsFromSelf());
461+
getMethodCallsFromClassWithoutAutomaticNullCheck(
462+
new ClassFileImporter().importClasses(Parent.class, Child.class)
463+
.get(Child.class)
464+
));
463465
JavaCodeUnit bridgeMethod = callFromBridgeMethodToOverriddenOne.getOrigin();
464466

465467
assertThat(bridgeMethod.getName()).isEqualTo("covariantlyOverriddenCausingBridgeMethod");
@@ -1146,10 +1148,11 @@ void call(Target target) {
11461148
}
11471149
}
11481150

1149-
JavaMethodCall call = getOnlyElement(new ClassFileImporter()
1150-
.importClasses(Origin.class, Target.class)
1151-
.get(Origin.class)
1152-
.getMethodCallsFromSelf());
1151+
JavaMethodCall call = getOnlyElement(
1152+
getMethodCallsFromClassWithoutAutomaticNullCheck(
1153+
new ClassFileImporter().importClasses(Origin.class, Target.class)
1154+
.get(Origin.class)
1155+
));
11531156

11541157
assertThat(call.getTarget().getParameterTypes())
11551158
.isEqualTo(call.getTarget().getRawParameterTypes());
@@ -1193,10 +1196,11 @@ void call(Target target) {
11931196
}
11941197
}
11951198

1196-
JavaClass origin = new ClassFileImporter().importClasses(Origin.class, Target.class).get(Origin.class);
1197-
1198-
assertThat(origin.getMethodCallsFromSelf()).hasSize(2);
1199-
for (JavaMethodCall call : origin.getMethodCallsFromSelf()) {
1199+
JavaClass origin = new ClassFileImporter().importClasses(Origin.class, Target.class)
1200+
.get(Origin.class);
1201+
Set<JavaMethodCall> methodCallsFromSelf = getMethodCallsFromClassWithoutAutomaticNullCheck(origin);
1202+
assertThat(methodCallsFromSelf).hasSize(2);
1203+
for (JavaMethodCall call : methodCallsFromSelf) {
12001204
assertThatCall(call).isTo("callMe");
12011205
}
12021206
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.junit.runner.RunWith;
5252

5353
import static com.google.common.collect.Iterables.getOnlyElement;
54+
import static com.tngtech.archunit.core.importer.ClassFileImporterTestUtils.getMethodCallsFromClassWithoutAutomaticNullCheck;
5455
import static com.tngtech.archunit.core.importer.DependencyResolutionProcess.MAX_ITERATIONS_FOR_ACCESSES_TO_TYPES_PROPERTY_NAME;
5556
import static com.tngtech.archunit.core.importer.DependencyResolutionProcess.MAX_ITERATIONS_FOR_ANNOTATION_TYPES_PROPERTY_NAME;
5657
import static com.tngtech.archunit.core.importer.DependencyResolutionProcess.MAX_ITERATIONS_FOR_ENCLOSING_TYPES_DEFAULT_VALUE;
@@ -351,7 +352,7 @@ void resolvesMethodCallTargetOwner() {
351352

352353
JavaClass javaClass = ImporterWithAdjustedResolutionRuns.disableAllIterationsExcept(MAX_ITERATIONS_FOR_ACCESSES_TO_TYPES_PROPERTY_NAME)
353354
.importClass(Origin.class);
354-
JavaMethodCall call = getOnlyElement(javaClass.getMethodCallsFromSelf());
355+
JavaMethodCall call = getOnlyElement(getMethodCallsFromClassWithoutAutomaticNullCheck(javaClass));
355356

356357
assertThat(call.getTargetOwner()).isFullyImported(true);
357358
}

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import static com.tngtech.archunit.core.domain.Formatters.formatNamesOf;
3535
import static com.tngtech.archunit.core.domain.JavaConstructor.CONSTRUCTOR_NAME;
3636
import static com.tngtech.archunit.core.domain.properties.HasName.Utils.namesOf;
37+
import static com.tngtech.archunit.core.importer.ClassFileImporterTestUtils.getMethodCallsFromClassWithoutAutomaticNullCheck;
3738
import static com.tngtech.archunit.core.importer.JavaClassDescriptorImporterTestUtils.isLambdaMethodName;
3839
import static com.tngtech.archunit.testutil.Assertions.assertThat;
3940
import static com.tngtech.archunit.testutil.Assertions.assertThatAccess;
@@ -68,7 +69,7 @@ Runnable call() {
6869
}
6970

7071
JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller.class);
71-
JavaMethodCall call = getOnlyElement(classes.get(Caller.class).getMethodCallsFromSelf());
72+
JavaMethodCall call = getOnlyElement(getMethodCallsFromClassWithoutAutomaticNullCheck(classes.get(Caller.class)));
7273

7374
assertThatCall(call).isFrom("call").isTo(Target.class, "target");
7475
}
@@ -172,7 +173,7 @@ Consumer<String> call() {
172173
}
173174

174175
JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller.class);
175-
JavaMethodCall call = getOnlyElement(classes.get(Caller.class).getMethodCallsFromSelf());
176+
JavaMethodCall call = getOnlyElement(getMethodCallsFromClassWithoutAutomaticNullCheck(classes.get(Caller.class)));
176177

177178
assertThatCall(call).isFrom("call").isTo(Target.class, "target", String.class);
178179
}
@@ -196,7 +197,7 @@ Supplier<String> call() {
196197
}
197198

198199
JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller.class);
199-
JavaMethodCall call = getOnlyElement(classes.get(Caller.class).getMethodCallsFromSelf());
200+
JavaMethodCall call = getOnlyElement(getMethodCallsFromClassWithoutAutomaticNullCheck(classes.get(Caller.class)));
200201

201202
assertThatCall(call).isFrom("call").isTo(Target.class, "target");
202203
}
@@ -252,7 +253,7 @@ Runnable call() {
252253
}
253254

254255
JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller.class);
255-
Set<JavaMethodCall> calls = classes.get(Caller.class).getMethodCallsFromSelf();
256+
Set<JavaMethodCall> calls = getMethodCallsFromClassWithoutAutomaticNullCheck(classes.get(Caller.class));
256257

257258
assertThat(calls).hasSize(2);
258259
calls.forEach(call -> assertThatCall(call).isFrom("call").isTo(Target.class, "target"));
@@ -285,7 +286,7 @@ Function<String, Target> call2() {
285286
}
286287

287288
JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller.class);
288-
Set<JavaMethodCall> calls = classes.get(Caller.class).getMethodCallsFromSelf();
289+
Set<JavaMethodCall> calls = getMethodCallsFromClassWithoutAutomaticNullCheck(classes.get(Caller.class));
289290
assertThat(calls).hasSize(5);
290291

291292
assertThat(filterOriginByName(calls, "call1"))
@@ -361,10 +362,10 @@ Supplier<String> call() {
361362

362363
JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller1.class, Caller2.class);
363364

364-
JavaMethodCall call1 = getOnlyElement(classes.get(Caller1.class).getMethodCallsFromSelf());
365+
JavaMethodCall call1 = getOnlyElement(getMethodCallsFromClassWithoutAutomaticNullCheck(classes.get(Caller1.class)));
365366
assertThatCall(call1).isFrom("call").isTo(Target.class, "target");
366367

367-
JavaMethodCall call2 = getOnlyElement(classes.get(Caller2.class).getMethodCallsFromSelf());
368+
JavaMethodCall call2 = getOnlyElement(getMethodCallsFromClassWithoutAutomaticNullCheck(classes.get(Caller2.class)));
368369
assertThatCall(call2).isFrom("call").isTo(Target.class, "target");
369370
}
370371

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@
44
import java.net.JarURLConnection;
55
import java.net.URLConnection;
66
import java.util.HashSet;
7+
import java.util.Objects;
78
import java.util.Set;
89
import java.util.jar.JarFile;
910

1011
import com.tngtech.archunit.core.domain.JavaClass;
1112
import com.tngtech.archunit.core.domain.JavaCodeUnit;
1213
import com.tngtech.archunit.core.domain.JavaField;
1314
import com.tngtech.archunit.core.domain.JavaMethod;
15+
import com.tngtech.archunit.core.domain.JavaMethodCall;
1416
import com.tngtech.archunit.core.domain.properties.HasName;
1517

1618
import static com.google.common.base.Preconditions.checkArgument;
1719
import static com.google.common.base.Preconditions.checkNotNull;
1820
import static com.google.common.collect.Iterables.getFirst;
1921
import static com.tngtech.archunit.testutil.TestUtils.urlOf;
22+
import static java.util.stream.Collectors.toSet;
2023

2124
class ClassFileImporterTestUtils {
2225

@@ -64,4 +67,19 @@ static JarFile jarFileOf(Class<?> clazzInJar) throws IOException {
6467
checkArgument(connection instanceof JarURLConnection, "Class %s is not contained in a JAR", clazzInJar.getName());
6568
return ((JarURLConnection) connection).getJarFile();
6669
}
70+
71+
/**
72+
* @return {@link JavaClass#getMethodCallsFromSelf()} excluding {@link Objects#requireNonNull(Object)} calls
73+
* from the constructor, which the JDK 25+ compiler automatically emits in inner classes,
74+
* to normalize test results over multiple JDKs
75+
* @see <a href="https://inside.java/2025/04/04/quality-heads-up/">New Null Checks in Inner Class Constructors</a>
76+
*/
77+
static Set<JavaMethodCall> getMethodCallsFromClassWithoutAutomaticNullCheck(JavaClass javaClass) {
78+
return javaClass.getMethodCallsFromSelf().stream()
79+
.filter(call -> {
80+
return !(call.getOrigin().isConstructor() && call.getOriginOwner().isInnerClass() &&
81+
call.getTargetOwner().isEquivalentTo(Objects.class) && call.getTarget().getName().equals("requireNonNull"));
82+
})
83+
.collect(toSet());
84+
}
6785
}

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ ext {
4646
]
4747

4848
minSupportedJavaVersion = JavaVersion.VERSION_1_8
49-
maxSupportedJavaVersion = JavaVersion.VERSION_21
49+
maxSupportedJavaVersion = JavaVersion.VERSION_25
5050
isTestBuild = project.hasProperty('testJavaVersion')
5151
configuredTestJavaVersion = project.findProperty('testJavaVersion')?.toString()?.with { JavaVersion.toVersion(it) }
5252
assert configuredTestJavaVersion <= maxSupportedJavaVersion:

buildSrc/src/main/groovy/archunit.java-release-publishing-conventions.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ tasks.withType(AbstractPublishToMaven) {
2828
publishing {
2929
publications {
3030
mavenJava(MavenPublication) {
31-
artifactId = project.archivesBaseName
31+
artifactId = project.name
3232
from components.java
3333
pom {
3434
name = app.name

0 commit comments

Comments
 (0)