You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by rf...@apache.org on 2018/07/07 18:51:57 UTC
[maven-compiler-plugin] 02/03: [MCOMPILER-323] Support
multi-release jars
This is an automated email from the ASF dual-hosted git repository.
rfscholte pushed a commit to branch MCOMPILER-323
in repository https://gitbox.apache.org/repos/asf/maven-compiler-plugin.git
commit 8eeb8766875079c6b53a2fcb1097ad8331e26cf7
Author: rfscholte <rf...@apache.org>
AuthorDate: Sat Jul 7 20:50:56 2018 +0200
[MCOMPILER-323] Support multi-release jars
---
pom.xml | 1 +
.../multimodule/invoker.properties | 19 ++
.../multimodule/multirelease-base/pom.xml | 47 ++++
.../multirelease-base/src/main/java/base/Base.java | 27 +++
.../multirelease-base/src/main/java/mr/A.java | 34 +++
.../multirelease-base/src/main/java/mr/I.java | 25 +++
.../multirelease-base/src/test/java/mr/ATest.java | 54 +++++
.../multimodule/multirelease-nine/pom.xml | 53 +++++
.../multirelease-nine/src/main/java/mr/A.java | 36 +++
.../multirelease-nine/src/test/java/mr/ATest.java | 54 +++++
.../multimodule/multirelease/pom.xml | 65 ++++++
.../multirelease/src/assembly/mrjar.xml | 56 +++++
src/it/multirelease-patterns/multimodule/pom.xml | 55 +++++
.../multimodule/verify.groovy | 70 ++++++
.../multiproject/invoker.properties | 29 +++
.../multiproject/multirelease-base/pom.xml | 131 +++++++++++
.../multirelease-base/src/main/java/base/Base.java | 27 +++
.../multirelease-base/src/main/java/mr/A.java | 34 +++
.../multirelease-base/src/main/java/mr/I.java | 25 +++
.../multirelease-base/src/test/java/mr/ATest.java | 54 +++++
.../multiproject/multirelease-nine/pom.xml | 58 +++++
.../multirelease-nine/src/main/java/mr/A.java | 36 +++
.../multirelease-nine/src/test/java/mr/ATest.java | 54 +++++
src/it/multirelease-patterns/multiproject/pom.xml | 42 ++++
.../multiproject/verify.groovy | 70 ++++++
.../packaging-plugin/invoker.properties | 19 ++
.../multirelease-patterns/packaging-plugin/pom.xml | 86 ++++++++
.../src/main/java-mr/9/module-info.java | 23 ++
.../packaging-plugin/src/main/java-mr/9/mr/A.java | 36 +++
.../packaging-plugin/src/main/java/base/Base.java | 27 +++
.../packaging-plugin/src/main/java/mr/A.java | 34 +++
.../packaging-plugin/src/main/java/mr/I.java | 25 +++
.../packaging-plugin/src/test/java/mr/ATest.java | 52 +++++
.../packaging-plugin/verify.groovy | 73 +++++++
.../singleproject-runtime/invoker.properties | 18 ++
.../singleproject-runtime/pom.xml | 137 ++++++++++++
.../src/main/java/base/Base.java | 27 +++
.../singleproject-runtime/src/main/java/mr/A.java | 34 +++
.../singleproject-runtime/src/main/java/mr/I.java | 25 +++
.../src/main/java9/module-info.java | 23 ++
.../singleproject-runtime/src/main/java9/mr/A.java | 36 +++
.../src/test/java/mr/ATest.java | 52 +++++
.../singleproject-runtime/verify.groovy | 73 +++++++
.../singleproject-toolchains/invoker.properties | 18 ++
.../singleproject-toolchains/pom.xml | 243 +++++++++++++++++++++
.../src/main/java/base/Base.java | 27 +++
.../src/main/java/mr/A.java | 34 +++
.../src/main/java/mr/I.java | 25 +++
.../src/main/java9/module-info.java | 23 ++
.../src/main/java9/mr/A.java | 36 +++
.../src/test/java/mr/ATest.java | 52 +++++
.../singleproject-toolchains/verify.groovy | 73 +++++++
.../plugin/compiler/AbstractCompilerMojo.java | 24 +-
.../apache/maven/plugin/compiler/CompilerMojo.java | 39 +++-
src/site/apt/multirelease.apt | 65 +++---
src/site/site.xml | 1 +
56 files changed, 2580 insertions(+), 36 deletions(-)
diff --git a/pom.xml b/pom.xml
index 6a9925f..54c4b6f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -281,6 +281,7 @@ under the License.
<pomIncludes>
<pomInclude>*/pom.xml</pomInclude>
<pomInclude>extras/*/pom.xml</pomInclude>
+ <pomInclude>multirelease-patterns/*/pom.xml</pomInclude>
</pomIncludes>
<!--
! Unfortunately we can't define an execution order.
diff --git a/src/it/multirelease-patterns/multimodule/invoker.properties b/src/it/multirelease-patterns/multimodule/invoker.properties
new file mode 100644
index 0000000..152d680
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/invoker.properties
@@ -0,0 +1,19 @@
+# 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.java.version = 9+
+invoker.goals = verify
diff --git a/src/it/multirelease-patterns/multimodule/multirelease-base/pom.xml b/src/it/multirelease-patterns/multimodule/multirelease-base/pom.xml
new file mode 100644
index 0000000..ad270bd
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/multirelease-base/pom.xml
@@ -0,0 +1,47 @@
+<?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>
+ <parent>
+ <groupId>multirelease</groupId>
+ <artifactId>multirelease-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>multirelease-base</artifactId>
+
+ <name>Base</name>
+
+ <properties>
+ <maven.install.skip>true</maven.install.skip>
+ <maven.compiler.release>8</maven.compiler.release>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/src/it/multirelease-patterns/multimodule/multirelease-base/src/main/java/base/Base.java b/src/it/multirelease-patterns/multimodule/multirelease-base/src/main/java/base/Base.java
new file mode 100644
index 0000000..513f909
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/multirelease-base/src/main/java/base/Base.java
@@ -0,0 +1,27 @@
+package base;
+
+/*
+ * 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.
+ */
+
+public class Base {
+
+ public static String get() {
+ return "BASE";
+ }
+}
diff --git a/src/it/multirelease-patterns/multimodule/multirelease-base/src/main/java/mr/A.java b/src/it/multirelease-patterns/multimodule/multirelease-base/src/main/java/mr/A.java
new file mode 100644
index 0000000..6c2eb86
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/multirelease-base/src/main/java/mr/A.java
@@ -0,0 +1,34 @@
+package mr;
+
+/*
+ * 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 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/multimodule/multirelease-base/src/main/java/mr/I.java b/src/it/multirelease-patterns/multimodule/multirelease-base/src/main/java/mr/I.java
new file mode 100644
index 0000000..f9858cf
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/multirelease-base/src/main/java/mr/I.java
@@ -0,0 +1,25 @@
+package mr;
+
+/*
+ * 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.
+ */
+
+public interface I
+{
+ Class<?> introducedClass();
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/multimodule/multirelease-base/src/test/java/mr/ATest.java b/src/it/multirelease-patterns/multimodule/multirelease-base/src/test/java/mr/ATest.java
new file mode 100644
index 0000000..cca7113
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/multirelease-base/src/test/java/mr/ATest.java
@@ -0,0 +1,54 @@
+package mr;
+
+/*
+ * 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 static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.hamcrest.CoreMatchers.is;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+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
+ @Ignore( "Maven module only creates Java 8 classes" )
+ public void testGet9() throws Exception
+ {
+ assumeThat( javaVersion, is( "9" ) );
+
+ assertThat( A.getString(), is( "BASE -> 9" ) );
+
+ assertThat( new A().introducedClass().getName(), is( "java.lang.Module" ) );
+ }
+
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/multimodule/multirelease-nine/pom.xml b/src/it/multirelease-patterns/multimodule/multirelease-nine/pom.xml
new file mode 100644
index 0000000..3204177
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/multirelease-nine/pom.xml
@@ -0,0 +1,53 @@
+<?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>
+ <parent>
+ <groupId>multirelease</groupId>
+ <artifactId>multirelease-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>multirelease-nine</artifactId>
+
+ <name>Version 9</name>
+
+ <properties>
+ <maven.compiler.release>9</maven.compiler.release>
+ <maven.install.skip>true</maven.install.skip>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>multirelease</groupId>
+ <artifactId>multirelease-base</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/src/it/multirelease-patterns/multimodule/multirelease-nine/src/main/java/mr/A.java b/src/it/multirelease-patterns/multimodule/multirelease-nine/src/main/java/mr/A.java
new file mode 100644
index 0000000..e2b9598
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/multirelease-nine/src/main/java/mr/A.java
@@ -0,0 +1,36 @@
+package mr;
+
+/*
+ * 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 base.Base;
+
+import java.util.Optional;
+
+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/multimodule/multirelease-nine/src/test/java/mr/ATest.java b/src/it/multirelease-patterns/multimodule/multirelease-nine/src/test/java/mr/ATest.java
new file mode 100644
index 0000000..ef26fe6
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/multirelease-nine/src/test/java/mr/ATest.java
@@ -0,0 +1,54 @@
+package mr;
+
+/*
+ * 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 static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.hamcrest.CoreMatchers.is;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class ATest {
+
+ private static final String javaVersion = System.getProperty( "java.version" );
+
+ @Test
+ @Ignore( "Maven module only creates Java 9 classes" )
+ 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 -> 9" ) );
+
+ assertThat( new A().introducedClass().getName(), is( "java.lang.Module" ) );
+ }
+
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/multimodule/multirelease/pom.xml b/src/it/multirelease-patterns/multimodule/multirelease/pom.xml
new file mode 100644
index 0000000..220864c
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/multirelease/pom.xml
@@ -0,0 +1,65 @@
+<?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>
+ <parent>
+ <groupId>multirelease</groupId>
+ <artifactId>multirelease-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>multirelease</artifactId>
+
+ <name>Distribution multirelease jar</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>3.1.0</version>
+ <configuration>
+ <appendAssemblyId>false</appendAssemblyId>
+ <descriptors>
+ <descriptor>src/assembly/mrjar.xml</descriptor>
+ </descriptors>
+ <archive>
+ <manifestEntries>
+ <Multi-Release>true</Multi-Release>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies><!-- add multirelease-base dependencies if any -->
+ </dependencies>
+</project>
diff --git a/src/it/multirelease-patterns/multimodule/multirelease/src/assembly/mrjar.xml b/src/it/multirelease-patterns/multimodule/multirelease/src/assembly/mrjar.xml
new file mode 100644
index 0000000..32298e2
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/multirelease/src/assembly/mrjar.xml
@@ -0,0 +1,56 @@
+<?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.
+ -->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+ <id>mvjar</id>
+ <formats>
+ <format>jar</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <moduleSets>
+ <moduleSet>
+ <useAllReactorProjects>true</useAllReactorProjects>
+ <includes>
+ <include>multirelease:multirelease-base</include>
+ </includes>
+ <binaries>
+ <unpack>true</unpack>
+ <includeDependencies>false</includeDependencies>
+ </binaries>
+ </moduleSet>
+ <moduleSet>
+ <useAllReactorProjects>true</useAllReactorProjects>
+ <includes>
+ <include>multirelease:multirelease-nine</include>
+ </includes>
+ <binaries>
+ <outputDirectory>META-INF/versions/9</outputDirectory>
+ <unpack>true</unpack>
+ <includeDependencies>false</includeDependencies>
+ <unpackOptions>
+ <excludes>
+ <exclude>/META-INF/**</exclude>
+ </excludes>
+ </unpackOptions>
+ </binaries>
+ </moduleSet>
+ </moduleSets>
+</assembly>
diff --git a/src/it/multirelease-patterns/multimodule/pom.xml b/src/it/multirelease-patterns/multimodule/pom.xml
new file mode 100644
index 0000000..bf411e6
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/pom.xml
@@ -0,0 +1,55 @@
+<?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-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <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-surefire-plugin</artifactId>
+ <version>2.21.0</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+
+ <modules>
+ <module>multirelease-base</module>
+ <module>multirelease-nine</module>
+ <module>multirelease</module>
+ </modules>
+
+</project>
diff --git a/src/it/multirelease-patterns/multimodule/verify.groovy b/src/it/multirelease-patterns/multimodule/verify.groovy
new file mode 100644
index 0000000..d1d094d
--- /dev/null
+++ b/src/it/multirelease-patterns/multimodule/verify.groovy
@@ -0,0 +1,70 @@
+/*
+ * 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 mrjar = new JarFile(new File(basedir,'multirelease/target/multirelease-1.0.0-SNAPSHOT.jar'))
+
+assert mrjar.manifest.mainAttributes.getValue('Multi-Release') == 'true'
+
+assert (je = mrjar.getEntry('base/Base.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/A.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/I.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+
+assert (je = mrjar.getEntry('META-INF/versions/9/mr/A.class')) != null
+assert 53 == getMajor(mrjar.getInputStream(je))
+
+/*
+ base
+ base/Base.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/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() == 16
+
+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/multiproject/invoker.properties b/src/it/multirelease-patterns/multiproject/invoker.properties
new file mode 100644
index 0000000..6e9d2b5
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/invoker.properties
@@ -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.
+
+#invoker.java.version = 9+
+invoker.goals=install -N
+
+invoker.goals.2=install
+invoker.project.2=multirelease-base
+invoker.profiles.2=!nine
+
+invoker.goals.3=install
+invoker.project.3=multirelease-nine
+
+invoker.goals.4=verify
+invoker.project.4=multirelease-base
diff --git a/src/it/multirelease-patterns/multiproject/multirelease-base/pom.xml b/src/it/multirelease-patterns/multiproject/multirelease-base/pom.xml
new file mode 100644
index 0000000..a730aef
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/multirelease-base/pom.xml
@@ -0,0 +1,131 @@
+<?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>
+
+ <parent>
+ <groupId>multirelease</groupId>
+ <artifactId>multirelease-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>multirelease</artifactId>
+
+ <name>Base</name>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ <resource>
+ <directory>target/generated-resources</directory>
+ <filtering>false</filtering>
+ </resource>
+ </resources>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>nine</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestEntries>
+ <Multi-Release>true</Multi-Release>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>3.1.0</version>
+ <executions>
+ <execution>
+ <id>add-java9-supplement</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <includeGroupIds>multirelease</includeGroupIds>
+ <includeArtifactIds>multirelease-nine</includeArtifactIds>
+ <excludeTransitive>true</excludeTransitive>
+ <includes>**/*.class</includes>
+ <outputDirectory>${project.build.directory}/generated-resources/META-INF/versions/9</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>multirelease</groupId>
+ <artifactId>multirelease-nine</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
+</project>
diff --git a/src/it/multirelease-patterns/multiproject/multirelease-base/src/main/java/base/Base.java b/src/it/multirelease-patterns/multiproject/multirelease-base/src/main/java/base/Base.java
new file mode 100644
index 0000000..513f909
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/multirelease-base/src/main/java/base/Base.java
@@ -0,0 +1,27 @@
+package base;
+
+/*
+ * 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.
+ */
+
+public class Base {
+
+ public static String get() {
+ return "BASE";
+ }
+}
diff --git a/src/it/multirelease-patterns/multiproject/multirelease-base/src/main/java/mr/A.java b/src/it/multirelease-patterns/multiproject/multirelease-base/src/main/java/mr/A.java
new file mode 100644
index 0000000..6c2eb86
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/multirelease-base/src/main/java/mr/A.java
@@ -0,0 +1,34 @@
+package mr;
+
+/*
+ * 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 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/multiproject/multirelease-base/src/main/java/mr/I.java b/src/it/multirelease-patterns/multiproject/multirelease-base/src/main/java/mr/I.java
new file mode 100644
index 0000000..f9858cf
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/multirelease-base/src/main/java/mr/I.java
@@ -0,0 +1,25 @@
+package mr;
+
+/*
+ * 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.
+ */
+
+public interface I
+{
+ Class<?> introducedClass();
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/multiproject/multirelease-base/src/test/java/mr/ATest.java b/src/it/multirelease-patterns/multiproject/multirelease-base/src/test/java/mr/ATest.java
new file mode 100644
index 0000000..cca7113
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/multirelease-base/src/test/java/mr/ATest.java
@@ -0,0 +1,54 @@
+package mr;
+
+/*
+ * 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 static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.hamcrest.CoreMatchers.is;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+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
+ @Ignore( "Maven module only creates Java 8 classes" )
+ public void testGet9() throws Exception
+ {
+ assumeThat( javaVersion, is( "9" ) );
+
+ assertThat( A.getString(), is( "BASE -> 9" ) );
+
+ assertThat( new A().introducedClass().getName(), is( "java.lang.Module" ) );
+ }
+
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/multiproject/multirelease-nine/pom.xml b/src/it/multirelease-patterns/multiproject/multirelease-nine/pom.xml
new file mode 100644
index 0000000..a4f5965
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/multirelease-nine/pom.xml
@@ -0,0 +1,58 @@
+<?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>
+ <parent>
+ <groupId>multirelease</groupId>
+ <artifactId>multirelease-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>multirelease-nine</artifactId>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <release>9</release>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>multirelease</groupId>
+ <artifactId>multirelease</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/src/it/multirelease-patterns/multiproject/multirelease-nine/src/main/java/mr/A.java b/src/it/multirelease-patterns/multiproject/multirelease-nine/src/main/java/mr/A.java
new file mode 100644
index 0000000..e2b9598
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/multirelease-nine/src/main/java/mr/A.java
@@ -0,0 +1,36 @@
+package mr;
+
+/*
+ * 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 base.Base;
+
+import java.util.Optional;
+
+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/multiproject/multirelease-nine/src/test/java/mr/ATest.java b/src/it/multirelease-patterns/multiproject/multirelease-nine/src/test/java/mr/ATest.java
new file mode 100644
index 0000000..ef26fe6
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/multirelease-nine/src/test/java/mr/ATest.java
@@ -0,0 +1,54 @@
+package mr;
+
+/*
+ * 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 static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.hamcrest.CoreMatchers.is;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class ATest {
+
+ private static final String javaVersion = System.getProperty( "java.version" );
+
+ @Test
+ @Ignore( "Maven module only creates Java 9 classes" )
+ 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 -> 9" ) );
+
+ assertThat( new A().introducedClass().getName(), is( "java.lang.Module" ) );
+ }
+
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/multiproject/pom.xml b/src/it/multirelease-patterns/multiproject/pom.xml
new file mode 100644
index 0000000..f79f7af
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/pom.xml
@@ -0,0 +1,42 @@
+<?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-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>@project.version@</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+</project>
diff --git a/src/it/multirelease-patterns/multiproject/verify.groovy b/src/it/multirelease-patterns/multiproject/verify.groovy
new file mode 100644
index 0000000..de18c4e
--- /dev/null
+++ b/src/it/multirelease-patterns/multiproject/verify.groovy
@@ -0,0 +1,70 @@
+/*
+ * 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 mrjar = new JarFile(new File(basedir,'multirelease-base/target/multirelease-1.0.0-SNAPSHOT.jar'))
+
+assert mrjar.manifest.mainAttributes.getValue('Multi-Release') == 'true'
+
+assert (je = mrjar.getEntry('base/Base.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/A.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/I.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+
+assert (je = mrjar.getEntry('META-INF/versions/9/mr/A.class')) != null
+assert 53 == getMajor(mrjar.getInputStream(je))
+
+/*
+ base
+ base/Base.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/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() == 16
+
+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/packaging-plugin/invoker.properties b/src/it/multirelease-patterns/packaging-plugin/invoker.properties
new file mode 100644
index 0000000..5185222
--- /dev/null
+++ b/src/it/multirelease-patterns/packaging-plugin/invoker.properties
@@ -0,0 +1,19 @@
+# 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.java.version = 9+
+invoker.goals = verify
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/packaging-plugin/pom.xml b/src/it/multirelease-patterns/packaging-plugin/pom.xml
new file mode 100644
index 0000000..4173513
--- /dev/null
+++ b/src/it/multirelease-patterns/packaging-plugin/pom.xml
@@ -0,0 +1,86 @@
+<?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>
+ <packaging>multi-release-jar</packaging>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.21.0</version>
+ <configuration>
+ <!-- this shows that the Java 9 code isn't tested -->
+ <testFailureIgnore>true</testFailureIgnore>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>pw.krejci</groupId>
+ <artifactId>multi-release-jar-maven-plugin</artifactId>
+ <version>0.1.5</version>
+ <extensions>true</extensions>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </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>
+ <version>2.21.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <name>Packaging Plugin</name>
+</project>
diff --git a/src/it/multirelease-patterns/packaging-plugin/src/main/java-mr/9/module-info.java b/src/it/multirelease-patterns/packaging-plugin/src/main/java-mr/9/module-info.java
new file mode 100644
index 0000000..2407e6b
--- /dev/null
+++ b/src/it/multirelease-patterns/packaging-plugin/src/main/java-mr/9/module-info.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.
+ */
+module example.mrjar
+{
+ exports base;
+ exports mr;
+}
diff --git a/src/it/multirelease-patterns/packaging-plugin/src/main/java-mr/9/mr/A.java b/src/it/multirelease-patterns/packaging-plugin/src/main/java-mr/9/mr/A.java
new file mode 100644
index 0000000..e2b9598
--- /dev/null
+++ b/src/it/multirelease-patterns/packaging-plugin/src/main/java-mr/9/mr/A.java
@@ -0,0 +1,36 @@
+package mr;
+
+/*
+ * 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 base.Base;
+
+import java.util.Optional;
+
+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/packaging-plugin/src/main/java/base/Base.java b/src/it/multirelease-patterns/packaging-plugin/src/main/java/base/Base.java
new file mode 100644
index 0000000..513f909
--- /dev/null
+++ b/src/it/multirelease-patterns/packaging-plugin/src/main/java/base/Base.java
@@ -0,0 +1,27 @@
+package base;
+
+/*
+ * 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.
+ */
+
+public class Base {
+
+ public static String get() {
+ return "BASE";
+ }
+}
diff --git a/src/it/multirelease-patterns/packaging-plugin/src/main/java/mr/A.java b/src/it/multirelease-patterns/packaging-plugin/src/main/java/mr/A.java
new file mode 100644
index 0000000..6c2eb86
--- /dev/null
+++ b/src/it/multirelease-patterns/packaging-plugin/src/main/java/mr/A.java
@@ -0,0 +1,34 @@
+package mr;
+
+/*
+ * 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 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/packaging-plugin/src/main/java/mr/I.java b/src/it/multirelease-patterns/packaging-plugin/src/main/java/mr/I.java
new file mode 100644
index 0000000..f9858cf
--- /dev/null
+++ b/src/it/multirelease-patterns/packaging-plugin/src/main/java/mr/I.java
@@ -0,0 +1,25 @@
+package mr;
+
+/*
+ * 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.
+ */
+
+public interface I
+{
+ Class<?> introducedClass();
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/packaging-plugin/src/test/java/mr/ATest.java b/src/it/multirelease-patterns/packaging-plugin/src/test/java/mr/ATest.java
new file mode 100644
index 0000000..07a207c
--- /dev/null
+++ b/src/it/multirelease-patterns/packaging-plugin/src/test/java/mr/ATest.java
@@ -0,0 +1,52 @@
+package mr;
+
+/*
+ * 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 static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.hamcrest.CoreMatchers.is;
+
+import org.junit.Test;
+
+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 -> 9" ) );
+
+ assertThat( new A().introducedClass().getName(), is( "java.lang.Module" ) );
+ }
+
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/packaging-plugin/verify.groovy b/src/it/multirelease-patterns/packaging-plugin/verify.groovy
new file mode 100644
index 0000000..6e97274
--- /dev/null
+++ b/src/it/multirelease-patterns/packaging-plugin/verify.groovy
@@ -0,0 +1,73 @@
+/*
+ * 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 mrjar = new JarFile(new File(basedir,'target/multirelease-1.0.0-SNAPSHOT.jar'))
+
+assert mrjar.manifest.mainAttributes.getValue('Multi-Release') == 'true'
+
+assert (je = mrjar.getEntry('base/Base.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/A.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/I.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+
+assert (je = mrjar.getEntry('META-INF/versions/9/mr/A.class')) != null
+assert 53 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('META-INF/versions/9/module-info.class')) != null
+assert 53 == getMajor(mrjar.getInputStream(je))
+
+/*
+ base
+ base/Base.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/module-info.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() == 17
+
+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-runtime/invoker.properties b/src/it/multirelease-patterns/singleproject-runtime/invoker.properties
new file mode 100644
index 0000000..595188b
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-runtime/invoker.properties
@@ -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 = verify
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/singleproject-runtime/pom.xml b/src/it/multirelease-patterns/singleproject-runtime/pom.xml
new file mode 100644
index 0000000..c799ff9
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-runtime/pom.xml
@@ -0,0 +1,137 @@
+<?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>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>@project.version@</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.21.0</version>
+ <configuration>
+ <!-- this shows that the Java 9 code isn't tested -->
+ <testFailureIgnore>true</testFailureIgnore>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <!-- 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>
+ <version>2.21.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>jdk9</id>
+ <activation>
+ <jdk>[9,)</jdk>
+ </activation>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>jdk9</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <release>9</release>
+ <compileSourceRoots>
+ <compileSourceRoot>${project.basedir}/src/main/java9</compileSourceRoot>
+ </compileSourceRoots>
+ <outputDirectory>${project.build.outputDirectory}/META-INF/versions/9</outputDirectory>
+ <compilerArgs>
+ <arg>--patch-module</arg><arg>example.mrjar=${project.build.outputDirectory}</arg>
+ </compilerArgs>
+ </configuration>
+ </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>
+ </pluginManagement>
+ </build>
+ </profile>
+ </profiles>
+ <name>Single Project :: Runtime</name>
+</project>
diff --git a/src/it/multirelease-patterns/singleproject-runtime/src/main/java/base/Base.java b/src/it/multirelease-patterns/singleproject-runtime/src/main/java/base/Base.java
new file mode 100644
index 0000000..513f909
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-runtime/src/main/java/base/Base.java
@@ -0,0 +1,27 @@
+package base;
+
+/*
+ * 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.
+ */
+
+public class Base {
+
+ public static String get() {
+ return "BASE";
+ }
+}
diff --git a/src/it/multirelease-patterns/singleproject-runtime/src/main/java/mr/A.java b/src/it/multirelease-patterns/singleproject-runtime/src/main/java/mr/A.java
new file mode 100644
index 0000000..6c2eb86
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-runtime/src/main/java/mr/A.java
@@ -0,0 +1,34 @@
+package mr;
+
+/*
+ * 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 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-runtime/src/main/java/mr/I.java b/src/it/multirelease-patterns/singleproject-runtime/src/main/java/mr/I.java
new file mode 100644
index 0000000..f9858cf
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-runtime/src/main/java/mr/I.java
@@ -0,0 +1,25 @@
+package mr;
+
+/*
+ * 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.
+ */
+
+public interface I
+{
+ Class<?> introducedClass();
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/singleproject-runtime/src/main/java9/module-info.java b/src/it/multirelease-patterns/singleproject-runtime/src/main/java9/module-info.java
new file mode 100644
index 0000000..2407e6b
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-runtime/src/main/java9/module-info.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.
+ */
+module example.mrjar
+{
+ exports base;
+ exports mr;
+}
diff --git a/src/it/multirelease-patterns/singleproject-runtime/src/main/java9/mr/A.java b/src/it/multirelease-patterns/singleproject-runtime/src/main/java9/mr/A.java
new file mode 100644
index 0000000..e2b9598
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-runtime/src/main/java9/mr/A.java
@@ -0,0 +1,36 @@
+package mr;
+
+/*
+ * 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 base.Base;
+
+import java.util.Optional;
+
+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-runtime/src/test/java/mr/ATest.java b/src/it/multirelease-patterns/singleproject-runtime/src/test/java/mr/ATest.java
new file mode 100644
index 0000000..07a207c
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-runtime/src/test/java/mr/ATest.java
@@ -0,0 +1,52 @@
+package mr;
+
+/*
+ * 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 static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.hamcrest.CoreMatchers.is;
+
+import org.junit.Test;
+
+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 -> 9" ) );
+
+ assertThat( new A().introducedClass().getName(), is( "java.lang.Module" ) );
+ }
+
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/singleproject-runtime/verify.groovy b/src/it/multirelease-patterns/singleproject-runtime/verify.groovy
new file mode 100644
index 0000000..6e97274
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-runtime/verify.groovy
@@ -0,0 +1,73 @@
+/*
+ * 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 mrjar = new JarFile(new File(basedir,'target/multirelease-1.0.0-SNAPSHOT.jar'))
+
+assert mrjar.manifest.mainAttributes.getValue('Multi-Release') == 'true'
+
+assert (je = mrjar.getEntry('base/Base.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/A.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/I.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+
+assert (je = mrjar.getEntry('META-INF/versions/9/mr/A.class')) != null
+assert 53 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('META-INF/versions/9/module-info.class')) != null
+assert 53 == getMajor(mrjar.getInputStream(je))
+
+/*
+ base
+ base/Base.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/module-info.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() == 17
+
+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-toolchains/invoker.properties b/src/it/multirelease-patterns/singleproject-toolchains/invoker.properties
new file mode 100644
index 0000000..b87e56b
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-toolchains/invoker.properties
@@ -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.java.version = 9+
+invoker.goals = verify -Pmulti-jar
diff --git a/src/it/multirelease-patterns/singleproject-toolchains/pom.xml b/src/it/multirelease-patterns/singleproject-toolchains/pom.xml
new file mode 100644
index 0000000..4c0face
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-toolchains/pom.xml
@@ -0,0 +1,243 @@
+<?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 :: Toolchains</name>
+
+ <properties>
+ <!-- The oldest Java version supported by this tool. -->
+ <!-- Will control compilation of the main code and the unit tests. -->
+ <base.java.version>1.8</base.java.version>
+
+ <!-- set the property when running from the release plugin -->
+ <arguments>-Dmulti_release=true</arguments>
+ </properties>
+
+ <build>
+ <plugins>
+
+ <!-- Use toolchains to select the compilers -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-toolchains-plugin</artifactId>
+ <version>1.1</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>toolchain</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <toolchains>
+ <jdk>
+ <version>${base.java.version}</version>
+ </jdk>
+ </toolchains>
+ </configuration>
+ </plugin>
+
+ <!-- define the possible compilations -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>@project.version@</version>
+ <configuration>
+ <source>${base.java.version}</source>
+ <target>${base.java.version}</target>
+ </configuration>
+ <executions>
+ <!-- for Java 9 -->
+ <execution>
+ <id>java9</id>
+ <phase />
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <release>9</release>
+ <jdkToolchain>
+ <version>9</version>
+ </jdkToolchain>
+ <compileSourceRoots>
+ <compileSourceRoot>${project.basedir}/src/main/java9</compileSourceRoot>
+ </compileSourceRoots>
+ <multiReleaseOutput>true</multiReleaseOutput>
+ </configuration>
+ </execution>
+ <!-- for Java 10 -->
+ <execution>
+ <id>java10</id>
+ <phase />
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <release>10</release>
+ <jdkToolchain>
+ <version>10</version>
+ </jdkToolchain>
+ <compileSourceRoots>
+ <compileSourceRoot>${project.basedir}/src/main/java10</compileSourceRoot>
+ </compileSourceRoots>
+ <multiReleaseOutput>true</multiReleaseOutput>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+
+ <!-- enable java9 compilation -->
+ <profile>
+ <id>compile-java9</id>
+ <activation>
+ <jdk>[9,)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>java9</id>
+ <phase>compile</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <!-- enable java10 compilation -->
+ <profile>
+ <id>compile-java10</id>
+ <activation>
+ <jdk>[10,)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>java10</id>
+ <phase>compile</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>test-toolchains-bypass</id>
+ <activation>
+ <property>
+ <name>!multi_release</name>
+ </property>
+ </activation>
+
+ <build>
+ <plugins>
+ <!-- Run the unit tests with the JVM used to run maven -->
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.21.0</version>
+ <configuration>
+ <jvm>${env.JAVA_HOME}/bin/java</jvm>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>multi-jar</id>
+ <activation>
+ <property>
+ <name>multi_release</name>
+ </property>
+ </activation>
+
+ <build>
+ <plugins>
+ <!-- enable java9 - java11 compilations -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>java9</id>
+ <phase>compile</phase>
+ </execution>
+ <execution>
+ <id>java10</id>
+ <phase>compile</phase>
+ </execution>
+ <execution>
+ <id>java11</id>
+ <phase>compile</phase>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- add the multi-release:true manifest entry -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <archive>
+ <manifestEntries>
+ <Multi-Release>true</Multi-Release>
+ </manifestEntries>
+ </archive>
+ <excludes>
+ <exclude>**/javac*</exclude>
+ <exclude>**/org.codehaus.plexus.compiler.javac.JavacCompiler*arguments</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/src/it/multirelease-patterns/singleproject-toolchains/src/main/java/base/Base.java b/src/it/multirelease-patterns/singleproject-toolchains/src/main/java/base/Base.java
new file mode 100644
index 0000000..513f909
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-toolchains/src/main/java/base/Base.java
@@ -0,0 +1,27 @@
+package base;
+
+/*
+ * 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.
+ */
+
+public class Base {
+
+ public static String get() {
+ return "BASE";
+ }
+}
diff --git a/src/it/multirelease-patterns/singleproject-toolchains/src/main/java/mr/A.java b/src/it/multirelease-patterns/singleproject-toolchains/src/main/java/mr/A.java
new file mode 100644
index 0000000..6c2eb86
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-toolchains/src/main/java/mr/A.java
@@ -0,0 +1,34 @@
+package mr;
+
+/*
+ * 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 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-toolchains/src/main/java/mr/I.java b/src/it/multirelease-patterns/singleproject-toolchains/src/main/java/mr/I.java
new file mode 100644
index 0000000..f9858cf
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-toolchains/src/main/java/mr/I.java
@@ -0,0 +1,25 @@
+package mr;
+
+/*
+ * 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.
+ */
+
+public interface I
+{
+ Class<?> introducedClass();
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/singleproject-toolchains/src/main/java9/module-info.java b/src/it/multirelease-patterns/singleproject-toolchains/src/main/java9/module-info.java
new file mode 100644
index 0000000..2407e6b
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-toolchains/src/main/java9/module-info.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.
+ */
+module example.mrjar
+{
+ exports base;
+ exports mr;
+}
diff --git a/src/it/multirelease-patterns/singleproject-toolchains/src/main/java9/mr/A.java b/src/it/multirelease-patterns/singleproject-toolchains/src/main/java9/mr/A.java
new file mode 100644
index 0000000..e2b9598
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-toolchains/src/main/java9/mr/A.java
@@ -0,0 +1,36 @@
+package mr;
+
+/*
+ * 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 base.Base;
+
+import java.util.Optional;
+
+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-toolchains/src/test/java/mr/ATest.java b/src/it/multirelease-patterns/singleproject-toolchains/src/test/java/mr/ATest.java
new file mode 100644
index 0000000..07a207c
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-toolchains/src/test/java/mr/ATest.java
@@ -0,0 +1,52 @@
+package mr;
+
+/*
+ * 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 static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.hamcrest.CoreMatchers.is;
+
+import org.junit.Test;
+
+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 -> 9" ) );
+
+ assertThat( new A().introducedClass().getName(), is( "java.lang.Module" ) );
+ }
+
+}
\ No newline at end of file
diff --git a/src/it/multirelease-patterns/singleproject-toolchains/verify.groovy b/src/it/multirelease-patterns/singleproject-toolchains/verify.groovy
new file mode 100644
index 0000000..6e97274
--- /dev/null
+++ b/src/it/multirelease-patterns/singleproject-toolchains/verify.groovy
@@ -0,0 +1,73 @@
+/*
+ * 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 mrjar = new JarFile(new File(basedir,'target/multirelease-1.0.0-SNAPSHOT.jar'))
+
+assert mrjar.manifest.mainAttributes.getValue('Multi-Release') == 'true'
+
+assert (je = mrjar.getEntry('base/Base.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/A.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('mr/I.class')) != null
+assert 52 == getMajor(mrjar.getInputStream(je))
+
+assert (je = mrjar.getEntry('META-INF/versions/9/mr/A.class')) != null
+assert 53 == getMajor(mrjar.getInputStream(je))
+assert (je = mrjar.getEntry('META-INF/versions/9/module-info.class')) != null
+assert 53 == getMajor(mrjar.getInputStream(je))
+
+/*
+ base
+ base/Base.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/module-info.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() == 17
+
+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/main/java/org/apache/maven/plugin/compiler/AbstractCompilerMojo.java b/src/main/java/org/apache/maven/plugin/compiler/AbstractCompilerMojo.java
index b9d98d1..d15599f 100644
--- a/src/main/java/org/apache/maven/plugin/compiler/AbstractCompilerMojo.java
+++ b/src/main/java/org/apache/maven/plugin/compiler/AbstractCompilerMojo.java
@@ -981,8 +981,6 @@ public abstract class AbstractCompilerMojo
}
else if ( "--patch-module".equals( entry.getKey() ) )
{
- jpmsLines.add( "--patch-module" );
-
String value = entry.getValue();
if ( value == null )
{
@@ -1011,6 +1009,11 @@ public abstract class AbstractCompilerMojo
{
patchModules.add( "_" ); // this jar
}
+ else if ( getOutputDirectory().toPath().startsWith( filePath ) )
+ {
+ // multirelease, can be ignored
+ continue;
+ }
else if ( sourceRoots.contains( filePath ) )
{
patchModules.add( "_" ); // this jar
@@ -1039,17 +1042,22 @@ public abstract class AbstractCompilerMojo
StringBuilder sb = new StringBuilder();
- for ( String mod : patchModules )
+ if ( patchModules.size() > 0 )
{
- if ( sb.length() > 0 )
+ for ( String mod : patchModules )
{
- sb.append( ", " );
+ if ( sb.length() > 0 )
+ {
+ sb.append( ", " );
+ }
+ // use 'invalid' separator to ensure values are transformed
+ sb.append( mod );
}
- // use 'invalid' separator to ensure values are transformed
- sb.append( mod );
+
+ jpmsLines.add( "--patch-module" );
+ jpmsLines.add( patchModule + sb.toString() );
}
- jpmsLines.add( patchModule + sb.toString() );
}
}
diff --git a/src/main/java/org/apache/maven/plugin/compiler/CompilerMojo.java b/src/main/java/org/apache/maven/plugin/compiler/CompilerMojo.java
index 1053d7d..04811c5 100644
--- a/src/main/java/org/apache/maven/plugin/compiler/CompilerMojo.java
+++ b/src/main/java/org/apache/maven/plugin/compiler/CompilerMojo.java
@@ -196,7 +196,7 @@ public class CompilerMojo
@Override
protected void preparePaths( Set<File> sourceFiles )
{
- assert compilePath != null;
+ //assert compilePath != null;
File moduleDescriptorPath = null;
@@ -280,6 +280,25 @@ public class CompilerMojo
for ( File file : resolvePathsResult.getClasspathElements() )
{
classpathElements.add( file.getPath() );
+
+ if ( multiReleaseOutput )
+ {
+ if ( compilerArgs == null )
+ {
+ compilerArgs = new ArrayList<String>();
+ }
+
+ if ( getOutputDirectory().toPath().startsWith( file.getPath() ) )
+ {
+ compilerArgs.add( "--patch-module" );
+
+ StringBuilder patchModuleValue = new StringBuilder( moduleDescriptor.name() )
+ .append( '=' )
+ .append( file.getPath() );
+
+ compilerArgs.add( patchModuleValue.toString() );
+ }
+ }
}
for ( File file : resolvePathsResult.getModulepathElements().keySet() )
@@ -301,7 +320,23 @@ public class CompilerMojo
private List<File> getCompileClasspathElements( MavenProject project )
{
- List<File> list = new ArrayList<File>( project.getArtifacts().size() + 1 );
+ // 3 is outputFolder + 2 preserved for multirelease
+ List<File> list = new ArrayList<File>( project.getArtifacts().size() + 3 );
+
+ if ( multiReleaseOutput )
+ {
+ File versionsFolder = new File( project.getBuild().getOutputDirectory(), "META-INF/versions" );
+
+ // in reverse order
+ for ( int version = Integer.parseInt( getRelease() ) - 1; version >= 9 ; version-- )
+ {
+ File versionSubFolder = new File( versionsFolder, String.valueOf( version ) );
+ if ( versionSubFolder.exists() )
+ {
+ list.add( versionSubFolder );
+ }
+ }
+ }
list.add( new File( project.getBuild().getOutputDirectory() ) );
diff --git a/src/site/apt/multirelease.apt b/src/site/apt/multirelease.apt
index 6c10808..b0d4491 100644
--- a/src/site/apt/multirelease.apt
+++ b/src/site/apt/multirelease.apt
@@ -32,7 +32,7 @@ Multi Release
* The "forward compatibility" problem
- The problem is it trying to solve is to make it possible to use new JDK features even though the codebase must stay compatible with earlier versions.
+ The problem this JEP is trying to solve is to make it possible to use new JDK features even though the codebase must stay compatible with earlier versions.
Let's try to make this concrete with a real world example: In Java 7 <<<java.nio>>> was added, which was much better in File handling. In those days Maven still required Java 6 to run, however they wanted to make use of these new features when Maven was running on Java 7 or beyond.
@@ -111,7 +111,14 @@ META-INF/MANIFEST.MF { Multi-Release: true }
[]
- The only solution to cover the first two bullets was by split the code into a Maven multimodule project. Now every Maven module is just a standard Maven project with close to no specific adjustments in the pom.
+ The only solution to cover the first two bullets was by split the code into a Maven multimodule project. Now every Maven module is just a standard Maven project with close to no specific adjustments in the pom.
+ There are several ways you can run this project:
+
+ * Use the highest required version of the JDK to build the project. You can use <<<release>>> to ensure the code only uses matching code and syntax. Since the version-code is isolated you can run surefire with a higher Java runtime.
+
+ * Use toolchains if you really want to compile and test with the matching Java version.
+
+
The downside it that a hierarchical structure is required even though the result is just 1 artifact.
{{{http://word-bits.flurg.com/multrelease-jars/}Multi Project}}
@@ -125,8 +132,9 @@ META-INF/MANIFEST.MF { Multi-Release: true }
[]
The first requirements implies that the project now are separate Maven projects. One Maven project contains the base-code and in the end this will also be the multirelease jar.
- When building such project for the first time, you'll need to call Maven at least 3 times: first the base needs to be compiled, next all version specific projects must be built and finally the main project needs to be built again, now including the version specific classes extracted from their jars.
- This setup is compact, but has cyclic dependencies. This requires some tricks and makes releasing a bit more complicated.
+ When building such project for the first time, you'll need to call Maven at least 3 times: first the base needs to be compiled, next all version specific projects must be built and finally the main project needs to be built again, now including the version specific classes extracted from their jars.
+ This setup is compact, but has cyclic dependencies. This requires some tricks and makes releasing a bit more complicated.
+ Another downside is that you must install SNAPSHOTs to your local repository and when doing a release it requires 2 releases of the base project, one to prepare for the multirelease-nine and one with the released multirelease-nine.
Single project
@@ -162,26 +170,31 @@ Single project
@todo make examples for every setup with for the same sources
-*-------------------------------*-----------------------*-------------------------*-----------------*--------------------------------*
-|| || Maven Multimodule || Multi Project || Single project || Maven extension+plugin ||
-*-------------------------------+-----------------------+-------------------------+-----------------+--------------------------------+
-| # projects | 1 | 1 + #javaVersions | 1 | 1 |
-*-------------------------------+-----------------------+-------------------------+-----------------+--------------------------------+
-| # builds to package | 1 | 2 + #javaVersions | 1 | 1 |
-*-------------------------------+-----------------------+-------------------------+-----------------+--------------------------------+
-| # builds/project to test | 1 | 1 | #javaVersions | #javaVersions (?) |
-*-------------------------------+-----------------------+-------------------------+-----------------+--------------------------------+
-| Simple Maven Project Layout | No | Yes | Yes | Yes |
-*-------------------------------+-----------------------+-------------------------+-----------------+--------------------------------+
-| Additional POM adjustments(a) | 1 (b) | #javaVersions(c) | #javaVersions(d)| #javaVersions(e) |
-*-------------------------------+-----------------------+-------------------------+-----------------+--------------------------------+
-| IDE support (f) | Yes | Yes | No | No |
-*-------------------------------+-----------------------+-------------------------+-----------------+--------------------------------+
-
- (a) Additional POM adjustments: # of executions added to the default lifecycle. This reflects the complexity of the POM.
- (b) Maven multimodule uses maven-assembly-plugin to assemble to multirelease jar
- (c) Multi project uses the maven-dependency-plugin to unpack java specific dependency to its matching outputDirectory
- (d)
- (e) Maven extension+plugin hides the multiple executions in the <<<perReleaseConfiguration>>> configuration
- (f) IDE Support: All classes are recognized and can be tested within the IDE.
+*-------------------------------*-----------------------*-------------------------*---------------------------*------------------------------*--------------------------------*
+|| || Maven Multimodule || Multi Project || Single project (runtime) || Single project (toolchains) || Maven extension+plugin ||
+*-------------------------------+-----------------------+-------------------------+---------------------------+------------------------------*--------------------------------+
+| # projects | 1 | 1 + #javaVersions | 1 | 1 | 1 |
+*-------------------------------+-----------------------+-------------------------+---------------------------+------------------------------*--------------------------------+
+| # builds to package | 1 | 2 + #javaVersions | 1 | 1 | 1 |
+*-------------------------------+-----------------------+-------------------------+---------------------------+------------------------------*--------------------------------+
+| # builds/project to test | 1 | 1 | #javaVersions | 1 | N/A (a) |
+*-------------------------------+-----------------------+-------------------------+---------------------------+------------------------------*--------------------------------+
+| Simple Maven Project Layout | No | Yes | Yes | Yes | Yes |
+*-------------------------------+-----------------------+-------------------------+---------------------------+------------------------------*--------------------------------+
+| Additional POM adjustments(b) | 1 (c) | #javaVersions(d) | #javaVersions(e) | ??(f) | #javaVersions(g) |
+*-------------------------------+-----------------------+-------------------------+---------------------------+------------------------------*--------------------------------+
+| Include module descriptor | No (h) | No (h) | Yes | Yes | Yes |
+*-------------------------------+-----------------------+-------------------------+---------------------------+------------------------------*--------------------------------+
+| IDE support (i) | Yes | Yes | No | No | No |
+*-------------------------------+-----------------------+-------------------------+---------------------------+------------------------------*--------------------------------+
+
+ (a) Project can only be executed with highest required JDK, hence you can't test the code for all JDKs
+ (b) Additional POM adjustments: # of executions added to the default lifecycle. This reflects the complexity of the POM.
+ (c) Maven multimodule uses maven-assembly-plugin to assemble to multirelease jar
+ (d) Multi project uses the maven-dependency-plugin to unpack java specific dependency to its matching outputDirectory
+ (e) There's a profile for every Java version required which contains an extra execution-block for that Java version.
+ (f)
+ (g) Maven extension+plugin hides the multiple executions in the <<<perReleaseConfiguration>>> configuration
+ (h) Requires a --patch-module on a dependency
+ (i) IDE Support: All classes are recognized and can be tested within the IDE.
\ No newline at end of file
diff --git a/src/site/site.xml b/src/site/site.xml
index 67c1514..f38ad60 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -39,6 +39,7 @@ under the License.
<item name="Pass Compiler Arguments" href="examples/pass-compiler-arguments.html"/>
<item name="Non-javac compilerIds" href="non-javac-compilers.html"/>
<item name="Older projects with module-info" href="examples/module-info.html"/>
+ <item name="MultiRelease" href="multirelease.html"/>
</menu>
</body>
</project>