diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java index ff263aca56e..09246ec3e6e 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,16 +92,26 @@ public final class DefaultCompressPlugin extends AbstractPlugin implements Resou if (level != null) { switch (level) { case LEVEL_0: + System.err.println(getMessage("compress.warn.argumentdeprecated", LEVEL_0)); ss = null; zip = null; break; case LEVEL_1: + System.err.println(getMessage("compress.warn.argumentdeprecated", LEVEL_1)); ss = new StringSharingPlugin(resFilter); break; case LEVEL_2: + System.err.println(getMessage("compress.warn.argumentdeprecated", LEVEL_2)); zip = new ZipPlugin(resFilter); break; default: + if (level.length() == 5 && level.startsWith("zip-")) { + try { + int zipLevel = Integer.parseInt(level.substring(4)); + zip = new ZipPlugin(resFilter, zipLevel); + break; + } catch (NumberFormatException ignored) {} + } throw new IllegalArgumentException("Invalid compression level " + level); } } else { diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ZipPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ZipPlugin.java index c733392690b..1fb0a935628 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ZipPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ZipPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,9 @@ public final class ZipPlugin extends AbstractPlugin { private Predicate predicate; + private static final int DEFAULT_COMPRESSION = 6; + private final int compressionLevel; + public ZipPlugin() { this((Predicate) null); } @@ -54,8 +57,13 @@ public final class ZipPlugin extends AbstractPlugin { } ZipPlugin(Predicate predicate) { + this(predicate, DEFAULT_COMPRESSION); + } + + ZipPlugin(Predicate predicate, int compressionLevel) { super("zip"); this.predicate = predicate; + this.compressionLevel = compressionLevel; } @Override @@ -73,8 +81,8 @@ public final class ZipPlugin extends AbstractPlugin { predicate = ResourceFilter.includeFilter(config.get(getName())); } - static byte[] compress(byte[] bytesIn) { - Deflater deflater = new Deflater(); + static byte[] compress(byte[] bytesIn, int compressionLevel) { + Deflater deflater = new Deflater(compressionLevel); deflater.setInput(bytesIn); ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length); byte[] buffer = new byte[1024]; @@ -104,7 +112,7 @@ public final class ZipPlugin extends AbstractPlugin { if (resource.type().equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE) && predicate.test(resource.path())) { byte[] compressed; - compressed = compress(resource.contentBytes()); + compressed = compress(resource.contentBytes(), this.compressionLevel); res = ResourcePoolManager.newCompressedResource(resource, ByteBuffer.wrap(compressed), getName(), null, ((ResourcePoolImpl)in).getStringTable(), in.byteOrder()); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index a64db65ce17..6b0303f2b2b 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -59,38 +59,20 @@ Class optimization: convert Class.forName calls to constant loads. class-for-name.usage=\ \ --class-for-name Class optimization: convert Class.forName calls to constant loads. -compress.argument=<0|1|2>[:filter=] +compress.argument=[:filter=] -compress.description=\ -Compress all resources in the output image.\n\ -Level 0: No compression\n\ -Level 1: Constant string sharing\n\ -Level 2: ZIP.\n\ -An optional filter can be specified to list the pattern of\n\ -files to be included. +compress.description= Compression to use in compressing resources. compress.usage=\ -\ --compress <0|1|2>[:filter=]\n\ -\ Compress all resources in the output image.\n\ -\ Level 0: No compression\n\ -\ Level 1: Constant string sharing\n\ -\ Level 2: ZIP.\n\ -\ An optional filter can be\n\ -\ specified to list the pattern of \n\ -\ files to be included. +\ --compress Compression to use in compressing resources:\n\ +\ Accepted values are:\n\ +\ zip-[0-9], where zip-0 provides no compression,\n\ +\ and zip-9 provides the best compression.\n\ +\ Default is zip-6. -compact-cp.argument= +compress.warn.argumentdeprecated=\ +Warning: The {0} argument for --compress is deprecated and may be removed in a future release -compact-cp.description=Constant Pool strings sharing.\n\ -By default, all resources are compressed. You can express the set \n\ -of resources to compress or not compress (use ^ for negation). - -compact-cp.usage=\ -\ --compact-cp \n\ -\ Constant Pool strings sharing.\n\ -\ By default, all resources are compressed.\n\ -\ You can express the set of resources to\n\ -\ compress or not compress (use ^ for negation). dedup-legal-notices.argument=[error-if-not-same-content] @@ -323,10 +305,15 @@ plugin.opt.disable-plugin=\ \ --disable-plugin Disable the plugin mentioned plugin.opt.compress=\ -\ -c, --compress=<0|1|2> Enable compression of resources:\n\ -\ Level 0: No compression\n\ -\ Level 1: Constant string sharing\n\ -\ Level 2: ZIP +\ --compress Compression to use in compressing resources:\n\ +\ Accepted values are:\n\ +\ zip-[0-9], where zip-0 provides no compression,\n\ +\ and zip-9 provides the best compression.\n\ +\ Default is zip-6.\n\ +\ Deprecated values to be removed in a future release:\n\ +\ 0: No compression. Equivalent to zip-0.\n\ +\ 1: Constant String Sharing\n\ +\ 2: Equivalent to zip-6. plugin.opt.strip-debug=\ \ -G, --strip-debug Strip debug information diff --git a/src/jdk.jlink/share/classes/module-info.java b/src/jdk.jlink/share/classes/module-info.java index 3f3f10e2b06..a7bb8bce187 100644 --- a/src/jdk.jlink/share/classes/module-info.java +++ b/src/jdk.jlink/share/classes/module-info.java @@ -82,5 +82,4 @@ module jdk.jlink { jdk.tools.jlink.internal.plugins.VendorVersionPlugin, jdk.tools.jlink.internal.plugins.CDSPlugin, jdk.tools.jlink.internal.plugins.SaveJlinkArgfilesPlugin; - } diff --git a/test/jdk/tools/jlink/JLinkTest.java b/test/jdk/tools/jlink/JLinkTest.java index 5a5adddedcb..39cf311a330 100644 --- a/test/jdk/tools/jlink/JLinkTest.java +++ b/test/jdk/tools/jlink/JLinkTest.java @@ -309,6 +309,15 @@ public class JLinkTest { "--compress=2:filter=^/java.base/java/lang/*"); } + // Unix style compression arguments + { + testCompress(helper, "compresscmdcompositezip6", "--compress", "zip-6"); + } + + { + testCompress(helper, "compresscmdcompositezip0", "--compress", "zip-0"); + } + // compress 0 { testCompress(helper, "compress0filtercmdcomposite2", @@ -326,6 +335,23 @@ public class JLinkTest { testCompress(helper, "compress2filtercmdcomposite2", "--compress=2:filter=^/java.base/java/lang/*"); } + // compress zip-0 with filter + { + testCompress(helper, "compresszip0filtercmdcomposite2", + "--compress=zip-0:filter=^/java.base/java/lang/*"); + } + + // compress zip-6 with filter + { + testCompress(helper, "compresszip6filtercmdcomposite2", + "--compress=zip-6:filter=^/java.base/java/lang/*"); + } + + // compress zip-9 with filter + { + testCompress(helper, "compresszip9filtercmdcomposite2", + "--compress=zip-9:filter=^/java.base/java/lang/*"); + } // invalid compress level { diff --git a/test/jdk/tools/jlink/plugins/CompressorPluginTest.java b/test/jdk/tools/jlink/plugins/CompressorPluginTest.java index d434940303c..0e29565464c 100644 --- a/test/jdk/tools/jlink/plugins/CompressorPluginTest.java +++ b/test/jdk/tools/jlink/plugins/CompressorPluginTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,6 +146,67 @@ public class CompressorPluginTest { new ResourceDecompressorFactory[]{ new ZipDecompressorFactory(), }, Collections.singletonList(".*Exception.class")); + + // compress level zip-0 == no compression + Properties optionsZip0 = new Properties(); + DefaultCompressPlugin compressPluginZip0 = new DefaultCompressPlugin(); + optionsZip0.setProperty(compressPluginZip0.getName(), "zip-0"); + checkCompress(classes, compressPluginZip0, + optionsZip0, + new ResourceDecompressorFactory[]{ + }); + + // compress level zip-[1-9] == varied compression levels + for(int i = 1; i < 10; i++) { + Properties optionsZip = new Properties(); + compressPlugin = new DefaultCompressPlugin(); + optionsZip.setProperty(compressPlugin.getName(), "zip-" + i); + checkCompress(classes, compressPlugin, + optionsZip, + new ResourceDecompressorFactory[]{ + new ZipDecompressorFactory(), + }); + } + + // compress level zip-[1-9] == varied compression levels + filter + for(int i = 1; i < 10; i++) { + Properties optionsZip = new Properties(); + compressPlugin = new DefaultCompressPlugin(); + optionsZip.setProperty(DefaultCompressPlugin.FILTER, "**Exception.class"); + optionsZip.setProperty(compressPlugin.getName(), "zip-" + i); + checkCompress(classes, compressPlugin, + optionsZip, + new ResourceDecompressorFactory[]{ + new ZipDecompressorFactory(), + }, Collections.singletonList(".*Exception.class")); + } + + testBadCompressProps(classes, "zip-10"); + testBadCompressProps(classes, "zip-badarg"); + testBadCompressProps(classes, "zip-10000000"); + + } + + private void testBadCompressProps(ResourcePool classes, String compressArg) throws Exception { + Properties badProps = new Properties(); + DefaultCompressPlugin compressPlugin = new DefaultCompressPlugin(); + badProps.setProperty(compressPlugin.getName(), compressArg); + try { + checkCompress(classes, compressPlugin, + badProps, + new ResourceDecompressorFactory[]{ + new ZipDecompressorFactory(), + }); + } catch (IllegalArgumentException e) { + if (e.getMessage().contains("Invalid compression level")) { + return; + } else { + throw e; + } + } + + throw new Exception("Expected compression IAE with " + compressArg + " but didn't get one."); + } private ResourcePool gatherResources(Path module) throws Exception {