Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
pull_request:

env:
build_java_version: 21
build_java_version: 25

jobs:
build:
Expand Down Expand Up @@ -48,6 +48,7 @@ jobs:
- 11
- 17
- 21
- 25
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
Expand Down Expand Up @@ -97,6 +98,7 @@ jobs:
- 11
- 17
- 21
- 25
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update-gradle-wrapper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
uses: actions/setup-java@v5.2.0
with:
distribution: 'zulu'
java-version: 17
java-version: 25

- name: Update Gradle Wrapper
uses: gradle-update/update-gradle-wrapper-action@v2.1.0
Expand Down
2 changes: 1 addition & 1 deletion archunit/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ compileJdk9mainJava {
dependsOn(compileJava)
ext.minimumJavaVersion = JavaVersion.VERSION_1_9

destinationDir = compileJava.destinationDir
destinationDirectory.set(compileJava.destinationDirectory.get())
}
javadoc.dependsOn(compileJdk9mainJava)
spotbugsMain.dependsOn(compileJdk9mainJava)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,10 @@ String covariantlyOverriddenCausingBridgeMethod() {
JavaMethodCall callFromBridgeMethodToOverriddenOne = getOnlyElement(
new ClassFileImporter().importClasses(Parent.class, Child.class)
.get(Child.class)
.getMethodCallsFromSelf());
.getMethodCallsFromSelf()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took me a really long time reproduce the second method call locally, as the build always falls back to java8 as the minimum supported version.
The easiest was in the end to set testJavaVersion=25 manually in the gradle.properties.
Is it document somewhere how to choose the java version for local execution?

.stream()
.filter(call -> call.getOrigin().isMethod())
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this relies entirely on the fact the the new null check is added in the constructor which doesn't count as method.
I think this would be easier to understand if you write the filter in a way that makes clear that the target Objects.requireNonNull is excluded and adding a small comment that this is added in java 25+
both the bridge method and the new null check added in byte code where new to me.

As a user of ArchUnit I would be very surprised to see the new synthetic method call to Objects.requireNonNull.
Is that an expected migration effort for Java25 or do we need a special handling for this call (e.g. ignoring it)?

.collect(toSet()));
JavaCodeUnit bridgeMethod = callFromBridgeMethodToOverriddenOne.getOrigin();

assertThat(bridgeMethod.getName()).isEqualTo("covariantlyOverriddenCausingBridgeMethod");
Expand Down Expand Up @@ -1146,10 +1149,11 @@ void call(Target target) {
}
}

JavaMethodCall call = getOnlyElement(new ClassFileImporter()
.importClasses(Origin.class, Target.class)
.get(Origin.class)
.getMethodCallsFromSelf());
JavaMethodCall call = getOnlyElement(
new ClassFileImporter().importClasses(Origin.class, Target.class)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: keep line breaks as before
same for other tests

.get(Origin.class)
.getMethod("call", Target.class)
.getMethodCallsFromSelf());

assertThat(call.getTarget().getParameterTypes())
.isEqualTo(call.getTarget().getRawParameterTypes());
Expand Down Expand Up @@ -1193,10 +1197,13 @@ void call(Target target) {
}
}

JavaClass origin = new ClassFileImporter().importClasses(Origin.class, Target.class).get(Origin.class);

assertThat(origin.getMethodCallsFromSelf()).hasSize(2);
for (JavaMethodCall call : origin.getMethodCallsFromSelf()) {
Set<JavaMethodCall> methodCallsFromSelf =
new ClassFileImporter().importClasses(Origin.class, Target.class)
.get(Origin.class)
.getMethod("call", Target.class)
.getMethodCallsFromSelf();
assertThat(methodCallsFromSelf).hasSize(2);
for (JavaMethodCall call : methodCallsFromSelf) {
assertThatCall(call).isTo("callMe");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
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.util.stream.Collectors.toSet;

@RunWith(DataProviderRunner.class)
public class ClassFileImporterAutomaticResolutionTest {
Expand Down Expand Up @@ -349,9 +350,13 @@ void resolvesMethodCallTargetOwner() {
}
}

JavaClass javaClass = ImporterWithAdjustedResolutionRuns.disableAllIterationsExcept(MAX_ITERATIONS_FOR_ACCESSES_TO_TYPES_PROPERTY_NAME)
.importClass(Origin.class);
JavaMethodCall call = getOnlyElement(javaClass.getMethodCallsFromSelf());
JavaMethodCall call = getOnlyElement(
ImporterWithAdjustedResolutionRuns.disableAllIterationsExcept(MAX_ITERATIONS_FOR_ACCESSES_TO_TYPES_PROPERTY_NAME)
.importClass(Origin.class)
.getMethodCallsFromSelf()
.stream()
.filter(c -> c.getOrigin().isMethod())
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you are not extremly aware of the new null check, the logic behind this is quite surprising.
Could we filter for origin Origin.resolvesMethodCallTargetOwner instead? it would at least be clear that exactly that one method call in it is meant

or functionally equivalent: again use .getMethod("resolvesMethodCallTargetOwner").getMethodCallsFromSelf() as in other tests

.collect(toSet()));

assertThat(call.getTargetOwner()).isFullyImported(true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,11 @@ Runnable call() {
}
}

JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller.class);
JavaMethodCall call = getOnlyElement(classes.get(Caller.class).getMethodCallsFromSelf());
JavaMethodCall call = getOnlyElement(
new ClassFileImporter().importClasses(Target.class, Caller.class)
.get(Caller.class)
.getMethod("call")
.getMethodCallsFromSelf());

assertThatCall(call).isFrom("call").isTo(Target.class, "target");
}
Expand Down Expand Up @@ -171,8 +174,11 @@ Consumer<String> call() {
}
}

JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller.class);
JavaMethodCall call = getOnlyElement(classes.get(Caller.class).getMethodCallsFromSelf());
JavaMethodCall call = getOnlyElement(
new ClassFileImporter().importClasses(Target.class, Caller.class)
.get(Caller.class)
.getMethod("call")
.getMethodCallsFromSelf());

assertThatCall(call).isFrom("call").isTo(Target.class, "target", String.class);
}
Expand All @@ -195,8 +201,11 @@ Supplier<String> call() {
}
}

JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller.class);
JavaMethodCall call = getOnlyElement(classes.get(Caller.class).getMethodCallsFromSelf());
JavaMethodCall call = getOnlyElement(
new ClassFileImporter().importClasses(Target.class, Caller.class)
.get(Caller.class)
.getMethod("call")
.getMethodCallsFromSelf());

assertThatCall(call).isFrom("call").isTo(Target.class, "target");
}
Expand Down Expand Up @@ -251,8 +260,10 @@ Runnable call() {
}
}

JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller.class);
Set<JavaMethodCall> calls = classes.get(Caller.class).getMethodCallsFromSelf();
Set<JavaMethodCall> calls = new ClassFileImporter().importClasses(Target.class, Caller.class)
.get(Caller.class)
.getMethod("call")
.getMethodCallsFromSelf();

assertThat(calls).hasSize(2);
calls.forEach(call -> assertThatCall(call).isFrom("call").isTo(Target.class, "target"));
Expand Down Expand Up @@ -284,8 +295,12 @@ Function<String, Target> call2() {
}
}

JavaClasses classes = new ClassFileImporter().importClasses(Target.class, Caller.class);
Set<JavaMethodCall> calls = classes.get(Caller.class).getMethodCallsFromSelf();
Set<JavaMethodCall> calls = new ClassFileImporter().importClasses(Target.class, Caller.class)
.get(Caller.class)
.getMethodCallsFromSelf()
.stream()
.filter(call -> call.getOrigin().isMethod())
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

call.getOrigin().getName().matches("call\\d")?
you filter for the name afterwards anyway and this would free us from isMethod (meant as isNotConstructor) which seems a pretty random check to me, if I wouldn't have read the commit message

.collect(toSet());
assertThat(calls).hasSize(5);

assertThat(filterOriginByName(calls, "call1"))
Expand Down Expand Up @@ -361,10 +376,14 @@ Supplier<String> call() {

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

JavaMethodCall call1 = getOnlyElement(classes.get(Caller1.class).getMethodCallsFromSelf());
JavaMethodCall call1 = getOnlyElement(classes.get(Caller1.class)
.getMethod("call")
.getMethodCallsFromSelf());
assertThatCall(call1).isFrom("call").isTo(Target.class, "target");

JavaMethodCall call2 = getOnlyElement(classes.get(Caller2.class).getMethodCallsFromSelf());
JavaMethodCall call2 = getOnlyElement(classes.get(Caller2.class)
.getMethod("call")
.getMethodCallsFromSelf());
assertThatCall(call2).isFrom("call").isTo(Target.class, "target");
}

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ ext {
]

minSupportedJavaVersion = JavaVersion.VERSION_1_8
maxSupportedJavaVersion = JavaVersion.VERSION_21
maxSupportedJavaVersion = JavaVersion.VERSION_25
isTestBuild = project.hasProperty('testJavaVersion')
configuredTestJavaVersion = project.findProperty('testJavaVersion')?.toString()?.with { JavaVersion.toVersion(it) }
assert configuredTestJavaVersion <= maxSupportedJavaVersion:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ tasks.withType(AbstractPublishToMaven) {
publishing {
publications {
mavenJava(MavenPublication) {
artifactId = project.archivesBaseName
artifactId = project.name
from components.java
pom {
name = app.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ class VersionSpec {
JavaVersion.VERSION_1_8,
JavaVersion.VERSION_11,
JavaVersion.VERSION_17,
JavaVersion.VERSION_21
JavaVersion.VERSION_21,
JavaVersion.VERSION_25,
] as SortedSet

JavaVersion desiredJdkVersion
Expand Down Expand Up @@ -43,11 +44,10 @@ afterEvaluate {
toolchain {
languageVersion = versionSpec.desiredJavaLanguageVersion
}
sourceCompatibility = versionSpec.desiredSourceCompatibility
targetCompatibility = versionSpec.desiredSourceCompatibility
}

sourceCompatibility = versionSpec.desiredSourceCompatibility
targetCompatibility = versionSpec.desiredSourceCompatibility

tasks.withType(JavaCompile) { Task task ->
VersionSpec taskVersionSpec = versionSpec.withLowerLtsVersionBoundCompatibleWith(getMinTaskJavaVersion(task))
println "Task ${task.name} configured: ${taskVersionSpec.describe()}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dependencies {
def parseLicenseInfoFrom = { config ->
def pom = config.resolve().find { it.name.endsWith('.pom') }

def projectNode = new XmlParser().parse(pom)
def projectNode = new groovy.xml.XmlParser().parse(pom)
def licenses = projectNode.licenses.license
assert licenses.size() == 1: 'Can only handle one declared license at the moment'

Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
3 changes: 1 addition & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=bd71102213493060956ec229d946beee57158dbd89d0e62b91bca0fa2c5f3531
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you drop the checksum intentionally?
according to https://gradle.org/release-checksums/ it is now for binary version 9.4.1 2ab2958f2a1e51120c326cad6f385153bb11ee93b3c216c5fccebfdfbb7ec6cb
and for the wrapper 55243ef57851f12b070ad14f7f5bb8302daceeebc5bce5ece5fa6edb23e1145c (I verified that your new wrapper file has the correct checksum)

If we actually check it somewhere in the pipeline, I'd prefer to keep it, otherwise, deletion is fine

distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
7 changes: 2 additions & 5 deletions gradlew

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions gradlew.bat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.