This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-compiler-plugin.git
The following commit(s) were added to refs/heads/master by this push:
new 3bcda08 Two more test cases for multi-release integration tests (#951)
3bcda08 is described below
commit 3bcda086c21118901c08f445371bf29327f4f521
Author: Fridrich Strba <[email protected]>
AuthorDate: Wed Jul 16 17:40:25 2025 +0200
Two more test cases for multi-release integration tests (#951)
* Test case with multirelease and module-info.java in root directory
* Test case with multi-release jar where module-info is in root and built
in a separate execution
Moreover the version 9 multirelease directory contains a class that is not
in the base
directory and that should be still accessible to the version 17
multirelease classes
---
.../singleproject-root/invoker.properties | 17 +++
.../singleproject-root/pom.xml | 141 ++++++++++++++++++
.../src/main/java/base/Base.java | 26 ++++
.../src/main/java/module-info.java | 22 +++
.../singleproject-root/src/main/java/mr/A.java | 32 ++++
.../singleproject-root/src/main/java/mr/I.java | 23 +++
.../singleproject-root/src/main/java11/mr/A.java | 34 +++++
.../singleproject-root/src/main/java17/mr/A.java | 34 +++++
.../singleproject-root/src/test/java/mr/ATest.java | 48 ++++++
.../singleproject-root/verify.groovy | 82 ++++++++++
.../invoker.properties | 17 +++
.../singleproject-separate-moduleinfo/pom.xml | 165 +++++++++++++++++++++
.../src/main/java/base/Base.java | 26 ++++
.../src/main/java/module-info.java | 22 +++
.../src/main/java/mr/A.java | 32 ++++
.../src/main/java/mr/I.java | 23 +++
.../src/main/java17/mr/A.java | 34 +++++
.../src/main/java9/mr/A.java | 34 +++++
.../src/main/java9/mr/B.java | 25 ++++
.../src/test/java/mr/ATest.java | 48 ++++++
.../verify.groovy | 86 +++++++++++
21 files changed, 971 insertions(+)
diff --git a/src/it/multirelease-patterns/singleproject-root/invoker.properties
b/src/it/multirelease-patterns/singleproject-root/invoker.properties
new file mode 100644
index 0000000..8e4e5be
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-root/invoker.properties
@@ -0,0 +1,17 @@
+# 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 = verify
diff --git a/src/it/multirelease-patterns/singleproject-root/pom.xml
b/src/it/multirelease-patterns/singleproject-root/pom.xml
new file mode 100644
index 0000000..09e9a01
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-root/pom.xml
@@ -0,0 +1,141 @@
+<?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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>multirelease</groupId>
+
+ <artifactId>multirelease</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name>Single Project :: Root</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.13.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>@project.version@</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>@version.maven-jar-plugin@</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>@version.maven-surefire@</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>@version.maven-surefire@</version>
+ <configuration>
+ <!-- this shows that the Java 9 code isn't tested -->
+ <testFailureIgnore>true</testFailureIgnore>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <!-- TODO: remove source and target after we identified where Maven
inherits those values. -->
+ <source />
+ <target />
+ <release>9</release>
+ </configuration>
+ <executions>
+ <execution>
+ <id>multi-release-11</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <release>11</release>
+ <compileSourceRoots>
+
<compileSourceRoot>${project.basedir}/src/main/java11</compileSourceRoot>
+ </compileSourceRoots>
+ <multiReleaseOutput>true</multiReleaseOutput>
+ </configuration>
+ </execution>
+ <execution>
+ <id>multi-release-17</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>
+ <!-- Rerun unittests with the multirelease jar, cannot be done with
exploded directory of classes -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-jar</id>
+ <configuration>
+ <archive>
+ <manifestEntries>
+ <Multi-Release>true</Multi-Release>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git
a/src/it/multirelease-patterns/singleproject-root/src/main/java/base/Base.java
b/src/it/multirelease-patterns/singleproject-root/src/main/java/base/Base.java
new file mode 100644
index 0000000..19ec7d8
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-root/src/main/java/base/Base.java
@@ -0,0 +1,26 @@
+/*
+ * 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 base;
+
+public class Base {
+
+ public static String get() {
+ return "BASE";
+ }
+}
diff --git
a/src/it/multirelease-patterns/singleproject-root/src/main/java/module-info.java
b/src/it/multirelease-patterns/singleproject-root/src/main/java/module-info.java
new file mode 100644
index 0000000..36f00e0
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-root/src/main/java/module-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+module example.mrjar {
+ exports base;
+ exports mr;
+}
diff --git
a/src/it/multirelease-patterns/singleproject-root/src/main/java/mr/A.java
b/src/it/multirelease-patterns/singleproject-root/src/main/java/mr/A.java
new file mode 100644
index 0000000..663a2ba
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-root/src/main/java/mr/A.java
@@ -0,0 +1,32 @@
+/*
+ * 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 mr;
+
+import base.Base;
+
+public class A implements I {
+ public static String getString() {
+ return Base.get() + " -> 9";
+ }
+
+ @Override
+ public Class<?> introducedClass() {
+ return java.time.LocalDateTime.class;
+ }
+}
diff --git
a/src/it/multirelease-patterns/singleproject-root/src/main/java/mr/I.java
b/src/it/multirelease-patterns/singleproject-root/src/main/java/mr/I.java
new file mode 100644
index 0000000..a052326
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-root/src/main/java/mr/I.java
@@ -0,0 +1,23 @@
+/*
+ * 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 mr;
+
+public interface I {
+ Class<?> introducedClass();
+}
diff --git
a/src/it/multirelease-patterns/singleproject-root/src/main/java11/mr/A.java
b/src/it/multirelease-patterns/singleproject-root/src/main/java11/mr/A.java
new file mode 100644
index 0000000..aa4e197
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-root/src/main/java11/mr/A.java
@@ -0,0 +1,34 @@
+/*
+ * 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 mr;
+
+import java.util.Optional;
+
+import base.Base;
+
+public class A implements I {
+ public static String getString() {
+ return Base.get() + " -> " + Optional.of("11").get();
+ }
+
+ @Override
+ public Class<?> introducedClass() {
+ return Module.class;
+ }
+}
diff --git
a/src/it/multirelease-patterns/singleproject-root/src/main/java17/mr/A.java
b/src/it/multirelease-patterns/singleproject-root/src/main/java17/mr/A.java
new file mode 100644
index 0000000..c1dc066
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-root/src/main/java17/mr/A.java
@@ -0,0 +1,34 @@
+/*
+ * 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 mr;
+
+import java.util.Optional;
+
+import base.Base;
+
+public class A implements I {
+ public static String getString() {
+ return Base.get() + " -> " + Optional.of("17").get();
+ }
+
+ @Override
+ public Class<?> introducedClass() {
+ return Module.class;
+ }
+}
diff --git
a/src/it/multirelease-patterns/singleproject-root/src/test/java/mr/ATest.java
b/src/it/multirelease-patterns/singleproject-root/src/test/java/mr/ATest.java
new file mode 100644
index 0000000..ab08e67
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-root/src/test/java/mr/ATest.java
@@ -0,0 +1,48 @@
+/*
+ * 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 mr;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+
+public class ATest {
+
+ private static final String javaVersion =
System.getProperty("java.version");
+
+ @Test
+ public void testGet9() throws Exception {
+ assumeThat(javaVersion, is("9"));
+
+ assertThat(A.getString(), is("BASE -> 9"));
+
+ assertThat(new A().introducedClass().getName(),
is("java.time.LocalDateTime"));
+ }
+
+ @Test
+ public void testGet11() throws Exception {
+ assumeThat(javaVersion, is("11"));
+
+ assertThat(A.getString(), is("BASE -> 11"));
+
+ assertThat(new A().introducedClass().getName(),
is("java.lang.Module"));
+ }
+}
diff --git a/src/it/multirelease-patterns/singleproject-root/verify.groovy
b/src/it/multirelease-patterns/singleproject-root/verify.groovy
new file mode 100644
index 0000000..e321af1
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-root/verify.groovy
@@ -0,0 +1,82 @@
+/*
+ * 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.JarFile
+
+def baseVersion = 53 // Java 9
+def mr1Version = 55; // Java 11
+def mr2Version = 61; // Java 17
+
+def mrjar = new JarFile(new
File(basedir,'target/multirelease-1.0.0-SNAPSHOT.jar'))
+
+assert (je = mrjar.getEntry('base/Base.class')) != null
+assert baseVersion == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/A.class')) != null
+assert baseVersion == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/I.class')) != null
+assert baseVersion == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('module-info.class')) != null
+assert baseVersion == getMajor(mrjar.getInputStream(je))
+
+assert mrjar.manifest.mainAttributes.getValue('Multi-Release') == 'true'
+
+assert (je = mrjar.getEntry('META-INF/versions/11/mr/A.class')) != null
+assert mr1Version == getMajor(mrjar.getInputStream(je))
+
+assert (je = mrjar.getEntry('META-INF/versions/17/mr/A.class')) != null
+assert mr2Version == getMajor(mrjar.getInputStream(je))
+
+/*
+ base
+ base/Base.class
+ module-info.class
+ mr
+ mr/A.class
+ mr/I.class
+ META-INF
+ META-INF/MANFEST.MF
+ META-INF/versions
+ META-INF/versions/11
+ META-INF/versions/11/mr
+ META-INF/versions/11/mr/A.class
+ META-INF/versions/17
+ META-INF/versions/17/mr
+ META-INF/versions/17/mr/A.class
+ META-INF/maven
+ META-INF/maven/multirelease
+ META-INF/maven/multirelease/multirelease
+ META-INF/maven/multirelease/multirelease/pom.xml
+ META-INF/maven/multirelease/multirelease/pom.properties
+*/
+assert mrjar.entries().size() == 20
+
+int getMajor(InputStream is)
+{
+ def dis = new DataInputStream(is)
+ final String firstFourBytes = Integer.toHexString(dis.readUnsignedShort()) +
Integer.toHexString(dis.readUnsignedShort())
+ if (!firstFourBytes.equalsIgnoreCase("cafebabe"))
+ {
+ throw new IllegalArgumentException(dataSourceName + " is NOT a Java .class
file.")
+ }
+ final int minorVersion = dis.readUnsignedShort()
+ final int majorVersion = dis.readUnsignedShort()
+
+ is.close();
+ return majorVersion;
+}
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/invoker.properties
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/invoker.properties
new file mode 100644
index 0000000..8e4e5be
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/invoker.properties
@@ -0,0 +1,17 @@
+# 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 = verify
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/pom.xml
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/pom.xml
new file mode 100644
index 0000000..091874c
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/pom.xml
@@ -0,0 +1,165 @@
+<?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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>multirelease</groupId>
+
+ <artifactId>multirelease</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name>Single Project :: Separate Module Info</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.13.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>@project.version@</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>@version.maven-jar-plugin@</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>@version.maven-surefire@</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>@version.maven-surefire@</version>
+ <configuration>
+ <!-- this shows that the Java 9 code isn't tested -->
+ <testFailureIgnore>true</testFailureIgnore>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <!-- TODO: remove source and target after we identified where Maven
inherits those values. -->
+ <source />
+ <target />
+ </configuration>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <release>8</release>
+ <excludes>
+ <exclude>module-info.java</exclude>
+ </excludes>
+ </configuration>
+ </execution>
+ <execution>
+ <id>module-info</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <release>9</release>
+ <includes>
+ <include>module-info.java</include>
+ </includes>
+ </configuration>
+ </execution>
+ <execution>
+ <id>multi-release-9</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <release>9</release>
+ <compileSourceRoots>
+
<compileSourceRoot>${project.basedir}/src/main/java9</compileSourceRoot>
+ </compileSourceRoots>
+ <multiReleaseOutput>true</multiReleaseOutput>
+ </configuration>
+ </execution>
+ <execution>
+ <id>multi-release-17</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>
+ <!-- Rerun unittests with the multirelease jar, cannot be done with
exploded directory of classes -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-jar</id>
+ <configuration>
+ <archive>
+ <manifestEntries>
+ <Multi-Release>true</Multi-Release>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/base/Base.java
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/base/Base.java
new file mode 100644
index 0000000..19ec7d8
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/base/Base.java
@@ -0,0 +1,26 @@
+/*
+ * 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 base;
+
+public class Base {
+
+ public static String get() {
+ return "BASE";
+ }
+}
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/module-info.java
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/module-info.java
new file mode 100644
index 0000000..36f00e0
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/module-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+module example.mrjar {
+ exports base;
+ exports mr;
+}
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/mr/A.java
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/mr/A.java
new file mode 100644
index 0000000..0e48eee
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/mr/A.java
@@ -0,0 +1,32 @@
+/*
+ * 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 mr;
+
+import base.Base;
+
+public class A implements I {
+ public static String getString() {
+ return Base.get() + " -> 8";
+ }
+
+ @Override
+ public Class<?> introducedClass() {
+ return java.time.LocalDateTime.class;
+ }
+}
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/mr/I.java
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/mr/I.java
new file mode 100644
index 0000000..a052326
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java/mr/I.java
@@ -0,0 +1,23 @@
+/*
+ * 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 mr;
+
+public interface I {
+ Class<?> introducedClass();
+}
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java17/mr/A.java
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java17/mr/A.java
new file mode 100644
index 0000000..f66f780
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java17/mr/A.java
@@ -0,0 +1,34 @@
+/*
+ * 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 mr;
+
+import java.util.Optional;
+
+import base.Base;
+
+public class A implements I {
+ public static String getString() {
+ return Base.get() + " -> " + Optional.of("17").get() + B.getString();
+ }
+
+ @Override
+ public Class<?> introducedClass() {
+ return Module.class;
+ }
+}
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java9/mr/A.java
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java9/mr/A.java
new file mode 100644
index 0000000..5083e1c
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java9/mr/A.java
@@ -0,0 +1,34 @@
+/*
+ * 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 mr;
+
+import java.util.Optional;
+
+import base.Base;
+
+public class A implements I {
+ public static String getString() {
+ return Base.get() + " -> " + Optional.of("9").get();
+ }
+
+ @Override
+ public Class<?> introducedClass() {
+ return Module.class;
+ }
+}
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java9/mr/B.java
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java9/mr/B.java
new file mode 100644
index 0000000..9032e4c
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/main/java9/mr/B.java
@@ -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 mr;
+
+public class B {
+ public static String getString() {
+ return "B";
+ }
+}
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/test/java/mr/ATest.java
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/test/java/mr/ATest.java
new file mode 100644
index 0000000..8c7f76b
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/src/test/java/mr/ATest.java
@@ -0,0 +1,48 @@
+/*
+ * 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 mr;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+
+public class ATest {
+
+ private static final String javaVersion =
System.getProperty("java.version");
+
+ @Test
+ public void testGet8() throws Exception {
+ assumeThat(javaVersion, is("8"));
+
+ assertThat(A.getString(), is("BASE -> 8"));
+
+ assertThat(new A().introducedClass().getName(),
is("java.time.LocalDateTime"));
+ }
+
+ @Test
+ public void testGet9() throws Exception {
+ assumeThat(javaVersion, is("9"));
+
+ assertThat(A.getString(), is("BASE -> 9B"));
+
+ assertThat(new A().introducedClass().getName(),
is("java.lang.Module"));
+ }
+}
diff --git
a/src/it/multirelease-patterns/singleproject-separate-moduleinfo/verify.groovy
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/verify.groovy
new file mode 100644
index 0000000..30c0a55
--- /dev/null
+++
b/src/it/multirelease-patterns/singleproject-separate-moduleinfo/verify.groovy
@@ -0,0 +1,86 @@
+/*
+ * 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.JarFile
+
+def baseVersion = 52 // Java 8
+def mr1Version = 53; // Java 9
+def mr2Version = 61; // Java 17
+
+def mrjar = new JarFile(new
File(basedir,'target/multirelease-1.0.0-SNAPSHOT.jar'))
+
+assert (je = mrjar.getEntry('base/Base.class')) != null
+assert baseVersion == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/A.class')) != null
+assert baseVersion == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/I.class')) != null
+assert baseVersion == getMajor(mrjar.getInputStream(je))
+
+assert (je = mrjar.getEntry('module-info.class')) != null
+assert mr1Version == getMajor(mrjar.getInputStream(je))
+
+assert mrjar.manifest.mainAttributes.getValue('Multi-Release') == 'true'
+
+assert (je = mrjar.getEntry('META-INF/versions/9/mr/A.class')) != null
+assert mr1Version == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('META-INF/versions/9/mr/B.class')) != null
+assert mr1Version == getMajor(mrjar.getInputStream(je))
+
+assert (je = mrjar.getEntry('META-INF/versions/17/mr/A.class')) != null
+assert mr2Version == getMajor(mrjar.getInputStream(je))
+
+/*
+ base
+ base/Base.class
+ module-info.class
+ mr
+ mr/A.class
+ mr/I.class
+ META-INF
+ META-INF/MANFEST.MF
+ META-INF/versions
+ META-INF/versions/9
+ META-INF/versions/9/mr
+ META-INF/versions/9/mr/A.class
+ META-INF/versions/9/mr/B.class
+ META-INF/versions/17
+ META-INF/versions/17/mr
+ META-INF/versions/17/mr/A.class
+ META-INF/maven
+ META-INF/maven/multirelease
+ META-INF/maven/multirelease/multirelease
+ META-INF/maven/multirelease/multirelease/pom.xml
+ META-INF/maven/multirelease/multirelease/pom.properties
+*/
+assert mrjar.entries().size() == 21
+
+int getMajor(InputStream is)
+{
+ def dis = new DataInputStream(is)
+ final String firstFourBytes = Integer.toHexString(dis.readUnsignedShort()) +
Integer.toHexString(dis.readUnsignedShort())
+ if (!firstFourBytes.equalsIgnoreCase("cafebabe"))
+ {
+ throw new IllegalArgumentException(dataSourceName + " is NOT a Java .class
file.")
+ }
+ final int minorVersion = dis.readUnsignedShort()
+ final int majorVersion = dis.readUnsignedShort()
+
+ is.close();
+ return majorVersion;
+}