Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1134f5a
Migrate from Maven Archiver to standard `jar` tool by using the stand…
desruisseaux Oct 12, 2025
4127022
Skip jar --validate on JDK 17/18 (JDK-8282446)
ascheman Aug 12, 2026
768b9a5
Fix base-release dir for modular multi-release JARs
ascheman Aug 12, 2026
ede2c9d
Fix order-dependent main class in modular JARs
ascheman Aug 12, 2026
5bb8540
Make deterministic which file is first after the -C option
ascheman Aug 13, 2026
a59d9fe
Fix empty jar file argument for version releases
ascheman Aug 11, 2026
4617a49
Reset base release after skipping a version dir
ascheman Aug 13, 2026
00b5e53
Record all jar entries relative to -C directory
desruisseaux Aug 15, 2026
27199e6
Sort the JAR entries in platform-independent order when reproducible …
desruisseaux Aug 15, 2026
16ff48a
Document the fact that the `--date` option requires JDK 19 or later.
desruisseaux Aug 16, 2026
d928d41
Automatically create the `target` directory if it does not exist.
desruisseaux Aug 17, 2026
27191ba
Change strategy in the way to exclude files.
desruisseaux Aug 23, 2026
2dc7d98
Add integration tests for ensuring that directory entries are present.
ascheman Aug 23, 2026
5564269
Add IT for filtered multi-release modular JAR
ascheman Aug 24, 2026
109d93f
Rename two integration tests with no change in the actual test.
desruisseaux Aug 24, 2026
3e0852e
Write a JDK-independent "Created-By" when strictly reproducible build…
ascheman Aug 24, 2026
21da295
Decouple the `isReproducible` flag from whether the `--date` option i…
desruisseaux Aug 24, 2026
aeb815c
Address issues raised by AI agent on the pull request.
desruisseaux Aug 24, 2026
1f68f5b
If a path to exclude is a directory, move to a path created by
desruisseaux Aug 25, 2026
245dcb2
Execute `jar --validate` only if requested.
desruisseaux Aug 27, 2026
9c90049
Upgrade Maven Compiler Plugin from beta-3 to beta-5 in integration te…
desruisseaux Aug 31, 2026
13769e8
Apply English corrections suggested in comments to the pull request.
desruisseaux Aug 31, 2026
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
28 changes: 24 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@
<name>Apache Maven JAR Plugin</name>
<description>Builds a Java Archive (JAR) file from the compiled project classes and resources.</description>

<developers>
<developer>
<id>evenisse</id>
<name>Emmanuel Venisse</name>
<email>evenisse@apache.org</email>
<roles>
<role>Java Developer</role>
</roles>
</developer>
<developer>
<id>desruisseaux</id>
<name>Martin Desruisseaux</name>
<email>desruisseaux@apache.org</email>
<organization>Geomatys</organization>
<roles>
<role>Java Developer</role>
</roles>
<timezone>+1</timezone>
</developer>
</developers>
<contributors>
<contributor>
<name>Jerome Lacoste</name>
Expand Down Expand Up @@ -133,9 +153,9 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>file-management</artifactId>
<version>${mavenFileManagementVersion}</version>
<groupId>org.apache.maven</groupId>
<artifactId>maven-support</artifactId>
<version>${mavenVersion}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
Expand Down Expand Up @@ -205,7 +225,7 @@
<!--
! The manifest specification does not describe any method for writing comments into the manifest.
-->
<exclude>src/it/mjar-71-01/src/main/resources/META-INF/MANIFEST.MF</exclude>
<exclude>src/it/mjar-71-01/src/main/my-custom-dir/some-manifest.mf</exclude>
<exclude>src/it/mjar-71-02/src/main/resources/META-INF/MANIFEST.MF</exclude>
</excludes>
</configuration>
Expand Down
3 changes: 1 addition & 2 deletions src/it/MJAR-260-invalid-automatic-module-name/verify.bsh
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ try
String[] snippets = new String[] {
"[INFO] BUILD FAILURE",
"[ERROR] Failed to execute goal org.apache.maven.plugins:maven-jar-plugin",
"Caused by: org.apache.maven.api.plugin.MojoException: Error assembling JAR",
"Caused by: org.codehaus.plexus.archiver.jar.ManifestException: Invalid automatic module name: 'in-valid.name.with.new.keyword'"
"Caused by: org.apache.maven.api.plugin.MojoException: Invalid automatic module name: \"in-valid.name.with.new.keyword\"."
};

System.out.println("\nVerifying log snippets...");
Expand Down
10 changes: 4 additions & 6 deletions src/it/MJAR-275-reproducible-module-info/invoker.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@
# to you 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
#
#
# http://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.

# NOTE: Requires Java 10+ to compile the module declaration for Java 9+,
# this is due that compiling the module declaration generates a
# module descriptor with the JDK version on it, making it unreproducible.
invoker.java.version = 10+
# The --date option needed for reproducible build is available only since Java 19.
invoker.java.version = 19+
4 changes: 2 additions & 2 deletions src/it/MJAR-292-detect-mjar/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
</manifest>
<manifestEntries>
<!--
We override this config since we are detecting the versioned area,
The output JAR should contain `Multi-Release: true`
For verifying that this entry will be overridden.
If users really want to disable multi-release, they should set <detectMultiReleaseJar> to false.
-->
<Multi-Release>false</Multi-Release>
</manifestEntries>
Expand Down
1 change: 1 addition & 0 deletions src/it/MJAR-292-disable-detect-mjar/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<mainClass>myproject.HelloWorld</mainClass>
</manifest>
</archive>
<detectMultiReleaseJar>false</detectMultiReleaseJar>
</configuration>
</plugin>
</plugins>
Expand Down
2 changes: 1 addition & 1 deletion src/it/MJAR-30-include/verify.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ try
{
String artifactName = artifactNames[i];
if ( !contents.contains( artifactName ) )
{
{
System.err.println( "Artifact[" + artifactName + "] not found in jar archive" );
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/it/MJAR-70-recreation/verify.bsh
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ if ( buildLog.exists() ) {
int jarPluginExecutions = 0;
String[] lines = buildLogContent.split( "\n" );
for ( String line : lines ) {
if ( line.contains( "Building jar:" ) && line.contains( "MJAR-70-recreation-1.0-SNAPSHOT.jar" ) ) {
if ( line.contains( "Building JAR:" ) && line.contains( "MJAR-70-recreation-1.0-SNAPSHOT.jar" ) ) {
jarPluginExecutions++;
System.out.println( "Found JAR creation: " + line );
}
Expand Down
69 changes: 69 additions & 0 deletions src/it/directory-entries-mr/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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

http://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.
-->
<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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>directory-entries-mr</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>directory-entries-mr-it</name>
<description>Verifies that a non-modular multi-release JAR preserves the intermediate directory
entries (com/, com/acme/, com/acme/sub/) in the base area and in the versioned area
(META-INF/versions/17/, .../com/, .../com/acme/). Consumers relying on JAR directory
traversal (e.g. Spring @ComponentScan) depend on those entries being present.

This is the same test as `directory-entries` but with multi-release.</description>

<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<release>11</release>
</configuration>
<executions>
<execution>
<id>java17</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>17</release>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/main/java17</compileSourceRoot>
</compileSourceRoots>
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>@project.version@</version>
</plugin>
</plugins>
</build>
</project>
25 changes: 25 additions & 0 deletions src/it/directory-entries-mr/src/main/java/com/acme/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 com.acme;

public class App {
public String greet() {
return "Hello (base) from " + new com.acme.sub.Helper().name();
}
}
25 changes: 25 additions & 0 deletions src/it/directory-entries-mr/src/main/java/com/acme/sub/Helper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 com.acme.sub;

public class Helper {
public String name() {
return "helper";
}
}
29 changes: 29 additions & 0 deletions src/it/directory-entries-mr/src/main/java17/com/acme/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 com.acme;

/**
* JDK-17 specific override of {@link App}. Placed under {@code src/main/java17} and compiled with
* {@code multiReleaseOutput=true}, so it lands in {@code META-INF/versions/17/com/acme/App.class}.
*/
public class App {
public String greet() {
return "Hello (java17) from " + new com.acme.sub.Helper().name();
}
}
68 changes: 68 additions & 0 deletions src/it/directory-entries-mr/verify.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.
*/

import java.util.jar.Attributes
import java.util.jar.JarFile

File artifact = new File(basedir, "target/directory-entries-mr-1.0-SNAPSHOT.jar")
assert artifact.isFile() : "JAR artifact is missing: " + artifact

JarFile jar = new JarFile(artifact)
try {
// Sanity: this must really be a multi-release JAR.
assert jar.manifest.mainAttributes.getValue(Attributes.Name.MULTI_RELEASE) == "true" :
"Expected Multi-Release: true in the manifest"

// Regression guard for maven-jar-plugin #508, extended to non-modular multi-release JARs.
// if the JAR is built by enumerating individual files, the intermediate directory entries
// can not be specified (if they were, they would be traversed), which breaks consumers
// relying on JAR directory traversal (e.g. Spring Boot @ComponentScan). Assert that the
// directory entries are present in both the base area and the "META-INF/versions/17" area.
def requiredDirectoryEntries = [
// base area
"com/",
"com/acme/",
"com/acme/sub/",
// versioned area
"META-INF/versions/17/",
"META-INF/versions/17/com/",
"META-INF/versions/17/com/acme/"
]
for (String name : requiredDirectoryEntries) {
def entry = jar.getEntry(name)
assert entry != null : "Missing directory entry: " + name
assert entry.isDirectory() : "Entry is not a directory: " + name
}

// The class files must of course still be present.
def requiredFileEntries = [
"com/acme/App.class",
"com/acme/sub/Helper.class",
"META-INF/versions/17/com/acme/App.class"
]
for (String name : requiredFileEntries) {
def entry = jar.getEntry(name)
assert entry != null : "Missing class entry: " + name
assert !entry.isDirectory() : "Class entry unexpectedly a directory: " + name
}
} finally {
jar.close()
}

return true
18 changes: 18 additions & 0 deletions src/it/directory-entries/invoker.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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
#
# http://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.

invoker.goals = clean package
Loading
Loading