Filter additional configuration metadata from archives

Signed-off-by: Wan bin yu <3431359639@qq.com>

See gh-51386
This commit is contained in:
Wan bin yu
2026-09-09 08:30:08 +01:00
committed by Andy Wilkinson
parent 3a869d0645
commit 0d223cbc77
5 changed files with 82 additions and 4 deletions
@@ -46,6 +46,7 @@ import org.jspecify.annotations.Nullable;
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
* @author Wan bin yu
* @see BootJar
* @see BootWar
*/
@@ -81,6 +82,7 @@ class BootArchiveSupport {
this.librarySpec = librarySpec;
this.compressionResolver = compressionResolver;
this.requiresUnpack.include(Specs.satisfyNone());
this.exclusions.exclude("**/META-INF/additional-spring-configuration-metadata.json");
}
void configureManifest(Manifest manifest, String mainClass, String classes, String lib,
@@ -247,6 +247,25 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
}
}
@Test
void additionalConfigurationMetadataIsExcluded() throws IOException {
this.task.getMainClass().set("com.example.Main");
File classpathDirectory = new File(this.temp, "classes");
File additionalMetadata = new File(classpathDirectory,
"META-INF/additional-spring-configuration-metadata.json");
additionalMetadata.getParentFile().mkdirs();
additionalMetadata.createNewFile();
File metadata = new File(classpathDirectory, "META-INF/spring-configuration-metadata.json");
metadata.createNewFile();
this.task.classpath(classpathDirectory);
executeTask();
try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {
assertThat(getEntryNames(jarFile))
.noneMatch((name) -> name.endsWith("META-INF/additional-spring-configuration-metadata.json"))
.anyMatch((name) -> name.endsWith("META-INF/spring-configuration-metadata.json"));
}
}
@Test
void loaderIsWrittenToTheRootOfTheJarAfterManifest() throws IOException {
this.task.getMainClass().set("com.example.Main");
@@ -192,3 +192,28 @@ The items contained in the "`ignored.properties`" section are removed from the "
The additional properties file is optional.
If you do not have any additional properties, do not add the file.
The Spring Boot Maven and Gradle plugins exclude `additional-spring-configuration-metadata.json` from the packaged artifact.
If you do not use either plugin to build your library, you should configure your build to exclude the file.
With Maven, you can configure the `maven-jar-plugin` as follows:
[source,xml]
----
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<excludes>
<exclude>META-INF/additional-spring-configuration-metadata.json</exclude>
</excludes>
</configuration>
</plugin>
----
With Gradle, you can configure the `jar` task as follows:
[source,gradle]
----
tasks.named('jar') {
exclude('META-INF/additional-spring-configuration-metadata.json')
}
----
@@ -55,10 +55,13 @@ import org.springframework.util.StringUtils;
* @author Stephane Nicoll
* @author Madhura Bhave
* @author Scott Frederick
* @author Wan bin yu
* @since 2.3.0
*/
public abstract class Packager {
private static final String ADDITIONAL_CONFIGURATION_METADATA_PATH = "META-INF/additional-spring-configuration-metadata.json";
private static final String MAIN_CLASS_ATTRIBUTE = "Main-Class";
private static final String START_CLASS_ATTRIBUTE = "Start-Class";
@@ -205,7 +208,7 @@ public abstract class Packager {
}
writer.writeManifest(buildManifest(sourceJar));
writeLoaderClasses(writer);
writer.writeEntries(sourceJar, getEntityTransformer(), libraries.getUnpackHandler(),
writer.writeEntries(sourceJar, getEntryTransformer(), libraries.getUnpackHandler(),
libraries.getLibraryLookup());
Map<String, Library> writtenLibraries = libraries.write(writer);
writeNativeImageArgFile(writer, sourceJar, writtenLibraries);
@@ -272,11 +275,14 @@ public abstract class Packager {
throws IOException {
}
private EntryTransformer getEntityTransformer() {
private EntryTransformer getEntryTransformer() {
EntryTransformer transformer = EntryTransformer.NONE;
if (getLayout() instanceof RepackagingLayout repackagingLayout) {
return new RepackagingEntryTransformer(repackagingLayout);
transformer = new RepackagingEntryTransformer(repackagingLayout);
}
return EntryTransformer.NONE;
EntryTransformer delegate = transformer;
String additionalMetadataLocation = getLayout().getClassesLocation() + ADDITIONAL_CONFIGURATION_METADATA_PATH;
return (entry) -> (entry.getName().equals(additionalMetadataLocation)) ? null : delegate.transform(entry);
}
private boolean isZip(InputStreamSupplier supplier) {
@@ -486,6 +486,32 @@ abstract class AbstractPackagerTests<P extends Packager> {
assertThat(getPackagedEntry("META-INF/INDEX.LIST")).isNull();
}
@Test
void additionalConfigurationMetadataIsRemovedFromRepackagedJar() throws Exception {
this.testJarFile.addClass("A.class", ClassWithMainMethod.class);
this.testJarFile.addFile("META-INF/additional-spring-configuration-metadata.json",
new ByteArrayInputStream(new byte[0]));
this.testJarFile.addFile("META-INF/spring-configuration-metadata.json", new ByteArrayInputStream(new byte[0]));
P packager = createPackager();
execute(packager, NO_LIBRARIES);
assertThat(getPackagedEntry("META-INF/additional-spring-configuration-metadata.json")).isNull();
assertThat(getPackagedEntry("META-INF/spring-configuration-metadata.json")).isNotNull();
}
@Test
void additionalConfigurationMetadataIsRemovedFromRepackagedWar() throws Exception {
this.testJarFile.addClass("WEB-INF/classes/com/example/Application.class", ClassWithMainMethod.class);
this.testJarFile.addFile("WEB-INF/classes/META-INF/additional-spring-configuration-metadata.json",
new ByteArrayInputStream(new byte[0]));
this.testJarFile.addFile("WEB-INF/classes/META-INF/spring-configuration-metadata.json",
new ByteArrayInputStream(new byte[0]));
P packager = createPackager(this.testJarFile.getFile("war"));
packager.setLayout(new Layouts.War());
execute(packager, NO_LIBRARIES);
assertThat(getPackagedEntry("WEB-INF/classes/META-INF/additional-spring-configuration-metadata.json")).isNull();
assertThat(getPackagedEntry("WEB-INF/classes/META-INF/spring-configuration-metadata.json")).isNotNull();
}
@Test
void customLayoutFactoryWithoutLayout() throws Exception {
this.testJarFile.addClass("a/b/C.class", ClassWithMainMethod.class);