Tolerate module-info with AOT processing

This commit updates the Maven Plugin to tolerate projects that are using
the module path on the JVM and targeting native images with AOT.

Previously, the plugin compiled AOT sources directly to target/classes
and the presence of a module-info there is enough to trigger a
compilation on the module path.

With this change we now compile in a separate directory that contains
the generated AOT classes (typically CGLIB proxies). These are copied to
target/classes once compilation completes already.

The integration test also uses our parent, rather than relying on what
Maven provides. That's because older Maven versions provide a default
compiler plugin version that did not handle the module path correctly.

Closes gh-33383
This commit is contained in:
Stéphane Nicoll 2024-07-30 10:45:02 +02:00
parent 47465f6ed5
commit 05468def54
6 changed files with 94 additions and 6 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -133,7 +133,7 @@ class AotTests {
}
@TestTemplate
void whenAotRunsSourcesAreCompiled(MavenBuild mavenBuild) {
void whenAotRunsSourcesAreCompiledAndMovedToTargetClasses(MavenBuild mavenBuild) {
mavenBuild.project("aot").goals("package").execute((project) -> {
Path classesDirectory = project.toPath().resolve("target/classes");
assertThat(collectRelativePaths(classesDirectory))
@ -141,6 +141,15 @@ class AotTests {
});
}
@TestTemplate
void whenAotRunsWithModuleInfoSourcesAreCompiledAndMovedToTargetClass(MavenBuild mavenBuild) {
mavenBuild.project("aot-module-info").goals("package").execute((project) -> {
Path classesDirectory = project.toPath().resolve("target/classes");
assertThat(collectRelativePaths(classesDirectory))
.contains(Path.of("org", "test", "SampleApplication__ApplicationContextInitializer.class"));
});
}
@TestTemplate
void whenAotRunsResourcesAreCopiedToTargetClasses(MavenBuild mavenBuild) {
mavenBuild.project("aot-jdk-proxy").goals("package").execute((project) -> {

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent> <!-- required to use a recent compiler plugin with old Maven versions -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>@project.version@</version>
<relativePath/>
</parent>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>aot-module-info</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>@java.version@</maven.compiler.source>
<maven.compiler.target>@java.version@</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<executions>
<execution>
<goals>
<goal>process-aot</goal>
</goals>
</execution>
<execution>
<id>repackage</id>
<configuration>
<skip>true</skip>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,4 @@
module sampleApp {
requires spring.context;
requires spring.boot;
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.test;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class SampleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -96,7 +96,7 @@ public class ProcessAotMojo extends AbstractAotMojo {
: SpringBootApplicationClassFinder.findSingleClass(this.classesDirectory);
URL[] classPath = getClassPath();
generateAotAssets(classPath, AOT_PROCESSOR_CLASS_NAME, getAotArguments(applicationClass));
compileSourceFiles(classPath, this.generatedSources, this.classesDirectory);
compileSourceFiles(classPath, this.generatedSources, this.generatedClasses);
copyAll(this.generatedResources.toPath(), this.classesDirectory.toPath());
copyAll(this.generatedClasses.toPath(), this.classesDirectory.toPath());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -125,7 +125,7 @@ public class ProcessTestAotMojo extends AbstractAotMojo {
return;
}
generateAotAssets(getClassPath(true), AOT_PROCESSOR_CLASS_NAME, getAotArguments());
compileSourceFiles(getClassPath(false), this.generatedSources, this.testClassesDirectory);
compileSourceFiles(getClassPath(false), this.generatedSources, this.generatedTestClasses);
copyAll(this.generatedResources.toPath().resolve("META-INF/native-image"),
this.testClassesDirectory.toPath().resolve("META-INF/native-image"));
copyAll(this.generatedTestClasses.toPath(), this.testClassesDirectory.toPath());