From 9037afcccaef2adaaf008cf8de7824a59e152ea8 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 12 Nov 2019 17:21:03 +0200 Subject: [PATCH] Ensure that the manifest of the generated jar can be read using JarInputStream Fixes: #5399 --- .../pkg/steps/JarResultBuildStep.java | 18 +++++--- .../java/io/quarkus/maven/it/PackageIT.java | 43 ++++++++++++++----- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java index f6022ef75c202..15613a5e89fc3 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java @@ -182,6 +182,11 @@ private JarBuildItem buildUberJar(CurateOutcomeBuildItem curateOutcomeBuildItem, final List appDeps = curateOutcomeBuildItem.getEffectiveModel().getUserDependencies(); + AppArtifact appArtifact = curateOutcomeBuildItem.getEffectiveModel().getAppArtifact(); + // the manifest needs to be the first entry in the jar, otherwise JarInputStream does not work properly + // see https://bugs.openjdk.java.net/browse/JDK-8031748 + generateManifest(runnerZipFs, classPath.toString(), packageConfig, appArtifact, applicationInfo); + for (AppDependency appDep : appDeps) { final AppArtifact depArtifact = appDep.getArtifact(); final Path resolvedDep = depResolver.resolve(depArtifact); @@ -261,12 +266,8 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) } } } - copyCommonContent(runnerZipFs, services, applicationArchivesBuildItem, transformedClasses, generatedClasses, generatedResources, seen); - AppArtifact appArtifact = curateOutcomeBuildItem.getEffectiveModel().getAppArtifact(); - generateManifest(runnerZipFs, classPath.toString(), packageConfig, appArtifact, applicationInfo); - } runnerJar.toFile().setReadable(true, false); @@ -375,10 +376,13 @@ private void doThinJarGeneration(CurateOutcomeBuildItem curateOutcomeBuildItem, final List appDeps = curateOutcomeBuildItem.getEffectiveModel().getUserDependencies(); copyLibraryJars(transformedClasses, libDir, depResolver, classPath, appDeps); - copyCommonContent(runnerZipFs, services, applicationArchivesBuildItem, transformedClasses, allClasses, - generatedResources, seen); + AppArtifact appArtifact = curateOutcomeBuildItem.getEffectiveModel().getAppArtifact(); + // the manifest needs to be the first entry in the jar, otherwise JarInputStream does not work properly + // see https://bugs.openjdk.java.net/browse/JDK-8031748 generateManifest(runnerZipFs, classPath.toString(), packageConfig, appArtifact, applicationInfo); + copyCommonContent(runnerZipFs, services, applicationArchivesBuildItem, transformedClasses, allClasses, + generatedResources, seen); } private void copyLibraryJars(TransformedClassesBuildItem transformedClasses, Path libDir, AppModelResolver depResolver, @@ -528,6 +532,8 @@ private void generateManifest(FileSystem runnerZipFs, final String classPath, Pa manifest.read(is); } Files.delete(manifestPath); + } else { + Files.createDirectories(runnerZipFs.getPath("META-INF")); } Attributes attributes = manifest.getMainAttributes(); attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0"); diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/PackageIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/PackageIT.java index 2491ae0264962..c542cbb179cc4 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/PackageIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/PackageIT.java @@ -4,19 +4,24 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Properties; import java.util.Set; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.maven.shared.invoker.MavenInvocationException; -import org.assertj.core.util.Arrays; import org.junit.Assert; import org.junit.jupiter.api.Test; @@ -30,7 +35,7 @@ public class PackageIT extends MojoTestBase { @Test public void testPackageWorksWhenUberjarIsFalse() - throws MavenInvocationException, FileNotFoundException, InterruptedException { + throws MavenInvocationException, IOException, InterruptedException { testDir = initProject("projects/uberjar-check", "projects/project-uberjar-false"); running = new RunningInvoker(testDir, false); @@ -40,12 +45,23 @@ public void testPackageWorksWhenUberjarIsFalse() assertThat(result.getProcess().waitFor()).isEqualTo(0); final File targetDir = getTargetDir(); - assertThat(getNumberOfFilesEndingWith(targetDir, ".jar")).isEqualTo(2); + List jars = getFilesEndingWith(targetDir, ".jar"); + assertThat(jars).hasSize(2); + + // make sure the jar can be read by JarInputStream + ensureManifestOfJarIsReadableByJarInputStream( + jars.stream().filter(f -> f.getName().contains("-runner")).findFirst().get()); + } + + private void ensureManifestOfJarIsReadableByJarInputStream(File jar) throws IOException { + InputStream fileInputStream = new FileInputStream(jar); + Manifest manifest = new JarInputStream(fileInputStream).getManifest(); + assertThat(manifest).isNotNull(); } @Test public void testPackageWorksWhenUberjarIsTrue() - throws MavenInvocationException, FileNotFoundException, InterruptedException { + throws MavenInvocationException, IOException, InterruptedException { testDir = initProject("projects/uberjar-check", "projects/project-uberjar-true"); createAndVerifyUberJar(); @@ -53,7 +69,7 @@ public void testPackageWorksWhenUberjarIsTrue() createAndVerifyUberJar(); } - private void createAndVerifyUberJar() throws FileNotFoundException, MavenInvocationException, InterruptedException { + private void createAndVerifyUberJar() throws IOException, MavenInvocationException, InterruptedException { Properties p = new Properties(); p.setProperty("quarkus.package.uber-jar", "true"); @@ -63,8 +79,11 @@ private void createAndVerifyUberJar() throws FileNotFoundException, MavenInvocat assertThat(result.getProcess().waitFor()).isEqualTo(0); final File targetDir = getTargetDir(); - assertThat(getNumberOfFilesEndingWith(targetDir, ".jar")).isEqualTo(1); + List jars = getFilesEndingWith(targetDir, ".jar"); + assertThat(jars).hasSize(1); assertThat(getNumberOfFilesEndingWith(targetDir, ".original")).isEqualTo(1); + + ensureManifestOfJarIsReadableByJarInputStream(jars.get(0)); } @Test @@ -105,7 +124,7 @@ public void testCustomPackaging() */ @Test public void testRunnerUberJarHasValidCRC() throws Exception { - testDir = initProject("projects/uberjar-check", "projects/project-uberjar-true"); + testDir = initProject("projects/uberjar-check", "projects/project-uberjar-true2"); running = new RunningInvoker(testDir, false); @@ -134,7 +153,7 @@ public void testRunnerUberJarHasValidCRC() throws Exception { */ @Test public void testRunnerJarHasValidCRC() throws Exception { - testDir = initProject("projects/uberjar-check", "projects/project-uberjar-false"); + testDir = initProject("projects/uberjar-check", "projects/project-uberjar-false2"); running = new RunningInvoker(testDir, false); final MavenProcessInvocationResult result = running.execute(Collections.singletonList("package"), @@ -150,9 +169,13 @@ public void testRunnerJarHasValidCRC() throws Exception { assertZipEntriesCanBeOpenedAndClosed(runnerJar); } - private int getNumberOfFilesEndingWith(File dir, String suffix) { + private List getFilesEndingWith(File dir, String suffix) { final File[] files = dir.listFiles((d, name) -> name.endsWith(suffix)); - return files != null ? files.length : 0; + return files != null ? Arrays.asList(files) : Collections.emptyList(); + } + + private int getNumberOfFilesEndingWith(File dir, String suffix) { + return getFilesEndingWith(dir, suffix).size(); } private File getTargetDir() {