diff --git a/.travis.yml b/.travis.yml index 1bcb5bb..c0bd58d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ script: - ./gradlew build - ./gradlew codeCoverageReport after_success: - - '[[ "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" = "develop" ]] && ./gradlew uploadArchives' + - '[[ "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" = "develop" ]] && ./gradlew publish' - bash <(curl -s https://codecov.io/bash) # Ugh. diff --git a/bombe-asm/src/test/java/org/cadixdev/bombe/asm/test/JarEntryRemappingTransformerTests.java b/bombe-asm/src/test/java/org/cadixdev/bombe/asm/test/JarEntryRemappingTransformerTests.java deleted file mode 100644 index 65bd26d..0000000 --- a/bombe-asm/src/test/java/org/cadixdev/bombe/asm/test/JarEntryRemappingTransformerTests.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2018, Jamie Mansfield - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.cadixdev.bombe.asm.test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.cadixdev.bombe.asm.jar.JarEntryRemappingTransformer; -import org.cadixdev.bombe.jar.JarClassEntry; -import org.cadixdev.bombe.jar.JarManifestEntry; -import org.cadixdev.bombe.jar.JarServiceProviderConfigurationEntry; -import org.cadixdev.bombe.jar.ServiceProviderConfiguration; -import org.junit.jupiter.api.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.commons.Remapper; -import org.objectweb.asm.tree.ClassNode; - -import java.io.IOException; -import java.util.Collections; -import java.util.jar.Manifest; - -/** - * Unit tests pertaining to {@link JarEntryRemappingTransformer}. - */ -public final class JarEntryRemappingTransformerTests { - - private static final Remapper REMAPPER = new Remapper() { - @Override - public String map(final String internalName) { - if ("a".equals(internalName)) return "pkg/Demo"; - if ("b".equals(internalName)) return "pkg/DemoTwo"; - return internalName; - } - }; - private static final JarEntryRemappingTransformer TRANSFORMER = - new JarEntryRemappingTransformer(REMAPPER); - - @Test - public void remapsClasses() { - // Create a test class - final ClassWriter obf = new ClassWriter(0); - obf.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "a", null, "java/lang/Object", null); - - // Run it through the transformer - final JarClassEntry entry = TRANSFORMER.transform(new JarClassEntry("a.class", 0, obf.toByteArray())); - assertEquals("pkg/Demo.class", entry.getName()); - - // Verify the contents - final ClassNode node = new ClassNode(); - final ClassReader reader = new ClassReader(entry.getContents()); - reader.accept(node, 0); - assertEquals("pkg/Demo", node.name); - } - - @Test - public void remapsMainClass() { - final Manifest obfManifest = new Manifest(); - { - obfManifest.getMainAttributes().putValue("Manifest-Version", "1.0"); - obfManifest.getMainAttributes().putValue("Main-Class", "a"); - } - - final JarManifestEntry manifestEntry = TRANSFORMER.transform(new JarManifestEntry(0, obfManifest)); - final Manifest deobfManifest = manifestEntry.getManifest(); - assertEquals("pkg.Demo", deobfManifest.getMainAttributes().getValue("Main-Class")); - } - - @Test - public void remapsSimpleManifest() { - final Manifest obfManifest = new Manifest(); - { - obfManifest.getMainAttributes().putValue("Manifest-Version", "1.0"); - } - - TRANSFORMER.transform(new JarManifestEntry(0, obfManifest)); - } - - @Test - public void remapsConfig() { - final ServiceProviderConfiguration obfConfig = new ServiceProviderConfiguration( - "a", - Collections.singletonList("b") - ); - final ServiceProviderConfiguration deobfConfig = - TRANSFORMER.transform(new JarServiceProviderConfigurationEntry(0, obfConfig)).getConfig(); - assertEquals("pkg.Demo", deobfConfig.getService()); - assertEquals(1, deobfConfig.getProviders().size()); - assertTrue(deobfConfig.getProviders().contains("pkg.DemoTwo"), "Provider not present!"); - } - -} diff --git a/bombe-jar/build.gradle b/bombe-jar/build.gradle index 3dd1e0b..8a6e7f3 100644 --- a/bombe-jar/build.gradle +++ b/bombe-jar/build.gradle @@ -1,5 +1,11 @@ dependencies { - compile project(':bombe') - compileOnly "org.ow2.asm:asm-commons:$asmVersion" - testCompile "org.ow2.asm:asm-commons:$asmVersion" -} \ No newline at end of file + api project(':bombe') + implementation "org.ow2.asm:asm-commons:$asmVersion" + testImplementation "org.ow2.asm:asm-commons:$asmVersion" +} + +jar { + manifest.attributes( + 'Automatic-Module-Name': "${project.group}.bombe.jar" + ) +} diff --git a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/AbstractJarEntry.java b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/AbstractJarEntry.java index 2dd771f..dfd8788 100644 --- a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/AbstractJarEntry.java +++ b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/AbstractJarEntry.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.jar.JarOutputStream; /** @@ -42,11 +43,45 @@ */ public abstract class AbstractJarEntry { + /** + * A {@link #getVersion()} value for jar entries that are at the base + * version in the jar. + */ + public static final int UNVERSIONED = -1; + + private static final String META_INF = "META-INF/"; + private static final String VERSIONS_PREFIX = META_INF + "versions/"; + protected final String name; protected final long time; + private String unversionedName; + private int version = UNVERSIONED; private String packageName; private String simpleName; + /** + * Create a new jar entry for a specific multi-release variant. + * + *

If {@code unversionedName} starts with {@code META-INF}, it will be + * treated as being in the base version no matter what value is provided for + * {@code version}, to match the behavior of the JDK's {@link JarFile}.

+ * + * @param version the Java version number to associate this entry with + * @param unversionedName the name without any versioned prefix + * @param time the time the entry was created at + */ + protected AbstractJarEntry(final int version, final String unversionedName, final long time) { + if (version == UNVERSIONED || unversionedName.startsWith(META_INF)) { + this.name = unversionedName; + } + else { + this.version = version; + this.unversionedName = unversionedName; + this.name = VERSIONS_PREFIX + version + '/' + unversionedName; + } + this.time = time; + } + protected AbstractJarEntry(final String name, final long time) { this.name = name; this.time = time; @@ -55,6 +90,8 @@ protected AbstractJarEntry(final String name, final long time) { /** * Gets the fully-qualified name of the jar entry. * + *

This method does not have any special handling for multi-release jars.

+ * * @return The name */ public final String getName() { @@ -70,6 +107,49 @@ public final long getTime() { return this.time; } + /** + * Get the name of this entry, as it will be seen by a multi-release-aware + * jar handler. + * + *

When a file path is in the {@code META-INF/versions/} folder but does + * not provide a valid multi-release version, it will be treated as if it + * were an ordinary, un-versioned resource.

+ * + *

This will always handle multi-release paths, even when the + * {@code Multi-Release} manifest attribute is set to false.

+ * + * @return the full entry name, without any version prefix + */ + public final String getUnversionedName() { + if (this.unversionedName != null) return this.unversionedName; + + if (!this.name.startsWith(VERSIONS_PREFIX)) { + return this.unversionedName = this.name; + } + // / + final String trimmed = this.name.substring(VERSIONS_PREFIX.length()); + final int divider = trimmed.indexOf('/'); + if (divider == -1) { // malformed, ignore + return this.unversionedName = this.name; + } + + final String version = trimmed.substring(0, divider); + final String unversioned = trimmed.substring(divider + 1); + try { + if (!unversioned.startsWith(META_INF)) { // Files already within META-INF cannot be versioned + final int parsedVersion = Integer.parseInt(version); + if (parsedVersion >= 0) { + this.version = parsedVersion; + return this.unversionedName = unversioned; + } + } + } + catch (final NumberFormatException ignored) { // invalid integer, treat as unversioned + // fall through + } + return this.unversionedName = this.name; + } + /** * Gets the package that contains the jar entry, an empty * string if in the root package. @@ -78,9 +158,10 @@ public final long getTime() { */ public final String getPackage() { if (this.packageName != null) return this.packageName; - final int index = this.name.lastIndexOf('/'); + final String name = this.getUnversionedName(); + final int index = name.lastIndexOf('/'); if (index == -1) return this.packageName = ""; - return this.packageName = this.name.substring(0, index); + return this.packageName = name.substring(0, index); } /** @@ -92,12 +173,28 @@ public final String getSimpleName() { if (this.simpleName != null) return this.simpleName; final int packageLength = this.getPackage().isEmpty() ? -1 : this.getPackage().length(); final int extensionLength = this.getExtension().isEmpty() ? -1 : this.getExtension().length(); - return this.simpleName = this.name.substring( + final String name = this.getUnversionedName(); + return this.simpleName = name.substring( packageLength + 1, - this.name.length() - (extensionLength + 1) + name.length() - (extensionLength + 1) ); } + /** + * If this is a multi-release variant of a class file in a multi-release + * jar, the version associated with this variant. + * + * @return the version, or {@link #UNVERSIONED} if this is the base version, + * or a file that would not be interpreted as a multi-release variant + * within the version folder. + * @see #getUnversionedName() for a description of the conditions on multi-release jars + */ + public int getVersion() { + if (this.unversionedName != null) return this.version; + this.getUnversionedName(); // initialize versions + return this.version; + } + /** * Gets the extension of the jar entry. * @@ -132,9 +229,9 @@ public final void write(final JarOutputStream jos) throws IOException { /** * Processes the jar entry with the given transformer. * - * @param vistor The transformer + * @param visitor The transformer * @return The jar entry */ - public abstract AbstractJarEntry accept(final JarEntryTransformer vistor); + public abstract AbstractJarEntry accept(final JarEntryTransformer visitor); } diff --git a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarClassEntry.java b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarClassEntry.java index 51fdbac..3ed0049 100644 --- a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarClassEntry.java +++ b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarClassEntry.java @@ -42,6 +42,11 @@ public class JarClassEntry extends AbstractJarEntry { private final byte[] contents; + public JarClassEntry(final int version, final String unversionedName, final long time, final byte[] contents) { + super(version, unversionedName, time); + this.contents = contents; + } + public JarClassEntry(final String name, final long time, final byte[] contents) { super(name, time); this.contents = contents; @@ -58,8 +63,8 @@ public final byte[] getContents() { } @Override - public final JarClassEntry accept(final JarEntryTransformer vistor) { - return vistor.transform(this); + public final JarClassEntry accept(final JarEntryTransformer visitor) { + return visitor.transform(this); } } diff --git a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarEntryTransformer.java b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarEntryTransformer.java index 95f0865..a16bfac 100644 --- a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarEntryTransformer.java +++ b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarEntryTransformer.java @@ -30,6 +30,9 @@ package org.cadixdev.bombe.jar; +import java.util.Collections; +import java.util.List; + /** * A visitor for {@link AbstractJarEntry}, allowing them be be * transformed. @@ -41,9 +44,12 @@ public interface JarEntryTransformer { /** * Transforms the given class entry. + *

+ * It is possible to remove entries by returning {@code null}, when this + * occurs no further transformers will process the entry. * * @param entry The class entry - * @return The transformed entry + * @return The transformed entry, or {@code null} if the entry should be removed */ default JarClassEntry transform(final JarClassEntry entry) { return entry; @@ -51,9 +57,12 @@ default JarClassEntry transform(final JarClassEntry entry) { /** * Transforms the given resource entry. + *

+ * It is possible to remove entries by returning {@code null}, when this + * occurs no further transformers will process the entry. * * @param entry The resource entry - * @return The transformed entry + * @return The transformed entry, or {@code null} if the entry should be removed */ default JarResourceEntry transform(final JarResourceEntry entry) { return entry; @@ -61,9 +70,12 @@ default JarResourceEntry transform(final JarResourceEntry entry) { /** * Transforms the given manifest entry. + *

+ * It is possible to remove entries by returning {@code null}, when this + * occurs no further transformers will process the entry. * * @param entry The manifest entry - * @return The transformed entry + * @return The transformed entry, or {@code null} if the entry should be removed */ default JarManifestEntry transform(final JarManifestEntry entry) { return entry; @@ -71,12 +83,25 @@ default JarManifestEntry transform(final JarManifestEntry entry) { /** * Transforms the given service provider configuration entry. + *

+ * It is possible to remove entries by returning {@code null}, when this + * occurs no further transformers will process the entry. * * @param entry The service provider configuration entry - * @return The transformed entry + * @return The transformed entry, or {@code null} if the entry should be removed */ default JarServiceProviderConfigurationEntry transform(final JarServiceProviderConfigurationEntry entry) { return entry; } + /** + * Provides a list of {@link AbstractJarEntry jar entries} to add into the + * processed jar file. + * + * @return Entries to add into the final jar + */ + default List additions() { + return Collections.emptyList(); + } + } diff --git a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarManifestEntry.java b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarManifestEntry.java index f55f012..4f66817 100644 --- a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarManifestEntry.java +++ b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarManifestEntry.java @@ -78,8 +78,8 @@ public final byte[] getContents() { } @Override - public JarManifestEntry accept(final JarEntryTransformer vistor) { - return vistor.transform(this); + public JarManifestEntry accept(final JarEntryTransformer visitor) { + return visitor.transform(this); } } diff --git a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarResourceEntry.java b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarResourceEntry.java index 65f94ae..490bf38 100644 --- a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarResourceEntry.java +++ b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarResourceEntry.java @@ -42,6 +42,11 @@ public class JarResourceEntry extends AbstractJarEntry { private final byte[] contents; private String extension; + public JarResourceEntry(final int version, final String unversionedName, final long time, final byte[] contents) { + super(version, unversionedName, time); + this.contents = contents; + } + public JarResourceEntry(final String name, final long time, final byte[] contents) { super(name, time); this.contents = contents; @@ -61,8 +66,8 @@ public final byte[] getContents() { } @Override - public final JarResourceEntry accept(final JarEntryTransformer vistor) { - return vistor.transform(this); + public final JarResourceEntry accept(final JarEntryTransformer visitor) { + return visitor.transform(this); } } diff --git a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarServiceProviderConfigurationEntry.java b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarServiceProviderConfigurationEntry.java index d3ebb96..51fb92c 100644 --- a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarServiceProviderConfigurationEntry.java +++ b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/JarServiceProviderConfigurationEntry.java @@ -79,8 +79,8 @@ public final byte[] getContents() { } @Override - public final JarServiceProviderConfigurationEntry accept(final JarEntryTransformer vistor) { - return vistor.transform(this); + public final JarServiceProviderConfigurationEntry accept(final JarEntryTransformer visitor) { + return visitor.transform(this); } } diff --git a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/asm/JarEntryRemappingTransformer.java b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/asm/JarEntryRemappingTransformer.java index 9252265..777ea45 100644 --- a/bombe-jar/src/main/java/org/cadixdev/bombe/jar/asm/JarEntryRemappingTransformer.java +++ b/bombe-jar/src/main/java/org/cadixdev/bombe/jar/asm/JarEntryRemappingTransformer.java @@ -30,9 +30,12 @@ package org.cadixdev.bombe.jar.asm; +import static java.util.jar.Attributes.Name.MAIN_CLASS; + import org.cadixdev.bombe.jar.JarClassEntry; import org.cadixdev.bombe.jar.JarEntryTransformer; import org.cadixdev.bombe.jar.JarManifestEntry; +import org.cadixdev.bombe.jar.JarResourceEntry; import org.cadixdev.bombe.jar.JarServiceProviderConfigurationEntry; import org.cadixdev.bombe.jar.ServiceProviderConfiguration; import org.objectweb.asm.ClassReader; @@ -41,7 +44,9 @@ import org.objectweb.asm.commons.ClassRemapper; import org.objectweb.asm.commons.Remapper; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.function.BiFunction; import java.util.jar.Attributes; import java.util.stream.Collectors; @@ -55,6 +60,8 @@ */ public class JarEntryRemappingTransformer implements JarEntryTransformer { + private static final Attributes.Name SHA_256_DIGEST = new Attributes.Name("SHA-256-Digest"); + private final Remapper remapper; private final BiFunction clsRemapper; @@ -78,22 +85,32 @@ public JarClassEntry transform(final JarClassEntry entry) { ), 0); // Create the jar entry - final String originalName = entry.getName().substring(0, entry.getName().length() - ".class".length()); + final String originalName = entry.getUnversionedName().substring(0, entry.getUnversionedName().length() - ".class".length()); final String name = this.remapper.map(originalName) + ".class"; - return new JarClassEntry(name, entry.getTime(), writer.toByteArray()); + return new JarClassEntry(entry.getVersion(), name, entry.getTime(), writer.toByteArray()); } @Override public JarManifestEntry transform(final JarManifestEntry entry) { // Remap the Main-Class attribute, if present - if (entry.getManifest().getMainAttributes().containsKey(new Attributes.Name("Main-Class"))) { - final String mainClassObf = entry.getManifest().getMainAttributes().getValue("Main-Class") + if (entry.getManifest().getMainAttributes().containsKey(MAIN_CLASS)) { + final String mainClassObf = entry.getManifest().getMainAttributes().getValue(MAIN_CLASS) .replace('.', '/'); final String mainClassDeobf = this.remapper.map(mainClassObf) .replace('/', '.'); - // Since Manifest is mutable, we need'nt create a new entry \o/ - entry.getManifest().getMainAttributes().putValue("Main-Class", mainClassDeobf); + // Since Manifest is mutable, we needn't create a new entry \o/ + entry.getManifest().getMainAttributes().put(MAIN_CLASS, mainClassDeobf); + } + + // Remove all signature entries + for (final Iterator> it = entry.getManifest().getEntries().entrySet().iterator(); it.hasNext();) { + final Map.Entry section = it.next(); + if (section.getValue().remove(SHA_256_DIGEST) != null) { + if (section.getValue().isEmpty()) { + it.remove(); + } + } } return entry; @@ -119,4 +136,16 @@ public JarServiceProviderConfigurationEntry transform(final JarServiceProviderCo return new JarServiceProviderConfigurationEntry(entry.getTime(), config); } + @Override + public JarResourceEntry transform(final JarResourceEntry entry) { + // Strip signature files from metadata + if (entry.getName().startsWith("META-INF")) { + if (entry.getExtension().equals("RSA") + || entry.getExtension().equals("SF")) { + return null; + } + } + return entry; + } + } diff --git a/bombe-jar/src/test/groovy/org/cadixdev/bombe/jar/test/JarEntrySpec.groovy b/bombe-jar/src/test/groovy/org/cadixdev/bombe/jar/test/JarEntrySpec.groovy index e682c63..e1c7904 100644 --- a/bombe-jar/src/test/groovy/org/cadixdev/bombe/jar/test/JarEntrySpec.groovy +++ b/bombe-jar/src/test/groovy/org/cadixdev/bombe/jar/test/JarEntrySpec.groovy @@ -31,6 +31,7 @@ package org.cadixdev.bombe.jar.test import org.cadixdev.bombe.jar.AbstractJarEntry +import org.cadixdev.bombe.jar.JarClassEntry import org.cadixdev.bombe.jar.JarResourceEntry import spock.lang.Specification @@ -41,6 +42,10 @@ class JarEntrySpec extends Specification { private static final AbstractJarEntry PACKAGED_ENTRY = new JarResourceEntry("pack/beep.boop", 0, null) private static final AbstractJarEntry ROOT_ENTRY = new JarResourceEntry("beep.boop", 0, null) + private static final AbstractJarEntry VERSION_BY_PATH = new JarClassEntry("META-INF/versions/9/module-info.class", 0, null) + private static final AbstractJarEntry VERSION_EXPLICIT = new JarClassEntry(11, "pack/a/b.class", 0, null) + private static final AbstractJarEntry VERSION_MALFORMED = new JarClassEntry("META-INF/versions/ab/module-info.class", 0, null) + private static final AbstractJarEntry VERSION_UNVERSIONABLE = new JarClassEntry("META-INF/versions/14/META-INF/services/a.b\$Provider", 0, null) def "reads name correctly"(final AbstractJarEntry entry, final String packageName, @@ -57,4 +62,22 @@ class JarEntrySpec extends Specification { ROOT_ENTRY | '' | 'beep' | 'boop' } + def "handles multirelease paths correctly"(final AbstractJarEntry entry, + final String fullName, + final int version, + final String name) { + expect: + entry.name == fullName + entry.version == version + entry.unversionedName == name + + where: + entry | fullName | version | name + PACKAGED_ENTRY | "pack/beep.boop" | AbstractJarEntry.UNVERSIONED | "pack/beep.boop" + VERSION_BY_PATH | "META-INF/versions/9/module-info.class" | 9 | "module-info.class" + VERSION_EXPLICIT | "META-INF/versions/11/pack/a/b.class" | 11 | "pack/a/b.class" + VERSION_MALFORMED | "META-INF/versions/ab/module-info.class" | AbstractJarEntry.UNVERSIONED | "META-INF/versions/ab/module-info.class" + VERSION_UNVERSIONABLE | "META-INF/versions/14/META-INF/services/a.b\$Provider" | AbstractJarEntry.UNVERSIONED | "META-INF/versions/14/META-INF/services/a.b\$Provider" + } + } diff --git a/bombe-jar/src/test/groovy/org/cadixdev/bombe/jar/test/asm/JarEntryRemappingTransformerSpec.groovy b/bombe-jar/src/test/groovy/org/cadixdev/bombe/jar/test/asm/JarEntryRemappingTransformerSpec.groovy index c7e4298..fa1ebdc 100644 --- a/bombe-jar/src/test/groovy/org/cadixdev/bombe/jar/test/asm/JarEntryRemappingTransformerSpec.groovy +++ b/bombe-jar/src/test/groovy/org/cadixdev/bombe/jar/test/asm/JarEntryRemappingTransformerSpec.groovy @@ -80,6 +80,28 @@ class JarEntryRemappingTransformerSpec extends Specification { node.name == 'pkg/Demo' } + def "remaps multi-release class"() { + given: + // Create a test class + def obf = new ClassWriter(0) + obf.visit(Opcodes.V9, Opcodes.ACC_PUBLIC, 'a', null, 'java/lang/Object', null) + + // Run it through the transformer + def entry = TRANSFORMER.transform(new JarClassEntry('META-INF/versions/9/a.class', 0, obf.toByteArray())) + + // Use a ClassNode for convenience + def node = new ClassNode() + def reader = new ClassReader(entry.contents) + reader.accept(node, 0) + + expect: + entry.name == 'META-INF/versions/9/pkg/Demo.class' + entry.version == 9 + entry.unversionedName == 'pkg/Demo.class' + node.name == 'pkg/Demo' + + } + def "remaps manifest"() { given: // Create a test Manifest diff --git a/bombe/build.gradle b/bombe/build.gradle index e195ca9..10b7abb 100644 --- a/bombe/build.gradle +++ b/bombe/build.gradle @@ -1,5 +1,12 @@ dependencies { - compile "me.jamiemansfield:string:$stringVersion" - compileOnly "org.ow2.asm:asm-commons:$asmVersion" - testCompile "org.ow2.asm:asm-commons:$asmVersion" + api "me.jamiemansfield:string:$stringVersion" + implementation "org.ow2.asm:asm-commons:$asmVersion" + testImplementation "org.ow2.asm:asm-commons:$asmVersion" } + +jar { + manifest.attributes( + 'Automatic-Module-Name': "${project.group}.bombe" + ) +} + diff --git a/bombe/src/main/java/org/cadixdev/bombe/analysis/InheritanceProvider.java b/bombe/src/main/java/org/cadixdev/bombe/analysis/InheritanceProvider.java index 03bf094..7d85bb4 100644 --- a/bombe/src/main/java/org/cadixdev/bombe/analysis/InheritanceProvider.java +++ b/bombe/src/main/java/org/cadixdev/bombe/analysis/InheritanceProvider.java @@ -432,7 +432,7 @@ public Map getMethods() { @Override public Set provideParents(final InheritanceProvider provider) { if (this.parents == null) { - ClassInfo.super.provideParents(provider, this.parents = new HashSet<>()); + super.provideParents(provider, this.parents = new HashSet<>()); } return this.parents; } diff --git a/bombe/src/main/java/org/cadixdev/bombe/analysis/asm/ClassProviderInheritanceProvider.java b/bombe/src/main/java/org/cadixdev/bombe/analysis/asm/ClassProviderInheritanceProvider.java index b178a31..da70c5b 100644 --- a/bombe/src/main/java/org/cadixdev/bombe/analysis/asm/ClassProviderInheritanceProvider.java +++ b/bombe/src/main/java/org/cadixdev/bombe/analysis/asm/ClassProviderInheritanceProvider.java @@ -31,7 +31,7 @@ package org.cadixdev.bombe.analysis.asm; import org.cadixdev.bombe.analysis.InheritanceProvider; -import org.cadixdev.bombe.jar.ClassProvider; +import org.cadixdev.bombe.provider.ClassProvider; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; diff --git a/bombe/src/main/java/org/cadixdev/bombe/jar/ClassLoaderClassProvider.java b/bombe/src/main/java/org/cadixdev/bombe/provider/ClassLoaderClassProvider.java similarity index 98% rename from bombe/src/main/java/org/cadixdev/bombe/jar/ClassLoaderClassProvider.java rename to bombe/src/main/java/org/cadixdev/bombe/provider/ClassLoaderClassProvider.java index 9cb645c..99ef6c7 100644 --- a/bombe/src/main/java/org/cadixdev/bombe/jar/ClassLoaderClassProvider.java +++ b/bombe/src/main/java/org/cadixdev/bombe/provider/ClassLoaderClassProvider.java @@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.cadixdev.bombe.jar; +package org.cadixdev.bombe.provider; import org.cadixdev.bombe.util.ByteStreams; diff --git a/bombe/src/main/java/org/cadixdev/bombe/jar/ClassProvider.java b/bombe/src/main/java/org/cadixdev/bombe/provider/ClassProvider.java similarity index 98% rename from bombe/src/main/java/org/cadixdev/bombe/jar/ClassProvider.java rename to bombe/src/main/java/org/cadixdev/bombe/provider/ClassProvider.java index 011c060..a0a5e41 100644 --- a/bombe/src/main/java/org/cadixdev/bombe/jar/ClassProvider.java +++ b/bombe/src/main/java/org/cadixdev/bombe/provider/ClassProvider.java @@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.cadixdev.bombe.jar; +package org.cadixdev.bombe.provider; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; diff --git a/bombe/src/main/java/org/cadixdev/bombe/provider/CompositeClassProvider.java b/bombe/src/main/java/org/cadixdev/bombe/provider/CompositeClassProvider.java new file mode 100644 index 0000000..20f0738 --- /dev/null +++ b/bombe/src/main/java/org/cadixdev/bombe/provider/CompositeClassProvider.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018, Jamie Mansfield + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.cadixdev.bombe.provider; + +import java.util.List; + +/** + * A {@link ClassProvider class provider} backed by many other class providers. + * + * @author Jamie Mansfield + * @since 0.5.0 + */ +public class CompositeClassProvider implements ClassProvider { + + private final List providers; + + public CompositeClassProvider(final List providers) { + this.providers = providers; + } + + @Override + public byte[] get(final String klass) { + for (final ClassProvider provider : this.providers) { + final byte[] raw = provider.get(klass); + if (raw != null) return raw; + } + return null; + } + +} diff --git a/bombe/src/main/java/org/cadixdev/bombe/jar/JarFileClassProvider.java b/bombe/src/main/java/org/cadixdev/bombe/provider/JarFileClassProvider.java similarity index 98% rename from bombe/src/main/java/org/cadixdev/bombe/jar/JarFileClassProvider.java rename to bombe/src/main/java/org/cadixdev/bombe/provider/JarFileClassProvider.java index c898326..d771332 100644 --- a/bombe/src/main/java/org/cadixdev/bombe/jar/JarFileClassProvider.java +++ b/bombe/src/main/java/org/cadixdev/bombe/provider/JarFileClassProvider.java @@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.cadixdev.bombe.jar; +package org.cadixdev.bombe.provider; import org.cadixdev.bombe.util.ByteStreams; diff --git a/bombe/src/main/java/org/cadixdev/bombe/type/MethodDescriptor.java b/bombe/src/main/java/org/cadixdev/bombe/type/MethodDescriptor.java index e094bb0..b84fc51 100644 --- a/bombe/src/main/java/org/cadixdev/bombe/type/MethodDescriptor.java +++ b/bombe/src/main/java/org/cadixdev/bombe/type/MethodDescriptor.java @@ -62,7 +62,7 @@ public final class MethodDescriptor { * @return The descriptor */ public static MethodDescriptor of(final String descriptor) { - return new MethodDescriptorReader(descriptor).read(); + return new MethodDescriptorReader(descriptor).readDescriptor(); } /** diff --git a/bombe/src/main/java/org/cadixdev/bombe/type/MethodDescriptorReader.java b/bombe/src/main/java/org/cadixdev/bombe/type/MethodDescriptorReader.java index 4442559..eb2795e 100644 --- a/bombe/src/main/java/org/cadixdev/bombe/type/MethodDescriptorReader.java +++ b/bombe/src/main/java/org/cadixdev/bombe/type/MethodDescriptorReader.java @@ -54,7 +54,7 @@ public MethodDescriptorReader(final String descriptor) { * @return The type * @throws IllegalStateException If the descriptor is invalid */ - public MethodDescriptor read() { + public MethodDescriptor readDescriptor() { final List params = new ArrayList<>(); if (this.peek() != '(') throw new IllegalStateException("Invalid descriptor provided!"); diff --git a/bombe/src/main/java/org/cadixdev/bombe/type/TypeReader.java b/bombe/src/main/java/org/cadixdev/bombe/type/TypeReader.java index 5d331b3..254de71 100644 --- a/bombe/src/main/java/org/cadixdev/bombe/type/TypeReader.java +++ b/bombe/src/main/java/org/cadixdev/bombe/type/TypeReader.java @@ -122,13 +122,15 @@ public BaseType readBaseType() { */ public ObjectType readObjectType() { final int start = this.index(); + + if (this.peek() != 'L') throw new IllegalStateException("Incomplete descriptor provided!"); this.advance(); while (this.available() && this.peek() != ';') { this.advance(); } - if (this.peek() != ';') throw new IllegalStateException("Incomplete descriptor provided!"); + if (!this.available() || this.peek() != ';') throw new IllegalStateException("Incomplete descriptor provided!"); this.advance(); return new ObjectType(this.substring(start + 1, this.index() - 1)); diff --git a/bombe/src/main/java/org/cadixdev/bombe/type/signature/MethodSignature.java b/bombe/src/main/java/org/cadixdev/bombe/type/signature/MethodSignature.java index 5baaf1f..1f3320a 100644 --- a/bombe/src/main/java/org/cadixdev/bombe/type/signature/MethodSignature.java +++ b/bombe/src/main/java/org/cadixdev/bombe/type/signature/MethodSignature.java @@ -65,8 +65,7 @@ public static MethodSignature of(final String name, final String descriptor) { * @return The new method signature */ public static MethodSignature of(final String nameAndDescriptor) { - int methodIndex = nameAndDescriptor.indexOf('('); - return of(nameAndDescriptor.substring(0, methodIndex), nameAndDescriptor.substring(methodIndex)); + return new MethodSignatureReader(nameAndDescriptor).readSignature(); } /** diff --git a/bombe/src/main/java/org/cadixdev/bombe/type/signature/MethodSignatureReader.java b/bombe/src/main/java/org/cadixdev/bombe/type/signature/MethodSignatureReader.java new file mode 100644 index 0000000..6e3c965 --- /dev/null +++ b/bombe/src/main/java/org/cadixdev/bombe/type/signature/MethodSignatureReader.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018, Jamie Mansfield + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.cadixdev.bombe.type.signature; + +import me.jamiemansfield.string.StringReader; +import org.cadixdev.bombe.type.MethodDescriptorReader; + +/** + * An {@link StringReader} for reading {@link MethodSignature}s + * from their raw {@link String} representation. + * + * @author Jamie Mansfield + * @since 0.5.0 + */ +public class MethodSignatureReader extends MethodDescriptorReader { + + public MethodSignatureReader(final String signature) { + super(signature); + } + + /** + * Reads the next {@link MethodSignature} from source. + * + * @return The type + * @throws IllegalStateException If the signature is invalid + */ + public MethodSignature readSignature() { + final int start = this.index(); + while (this.peek() != '(') { + this.advance(); + } + final String name = this.substring(start, this.index()); + + return new MethodSignature(name, this.readDescriptor()); + } + +} diff --git a/bombe/src/main/java/org/cadixdev/bombe/util/ByteStreams.java b/bombe/src/main/java/org/cadixdev/bombe/util/ByteStreams.java index e262b14..1f8decc 100644 --- a/bombe/src/main/java/org/cadixdev/bombe/util/ByteStreams.java +++ b/bombe/src/main/java/org/cadixdev/bombe/util/ByteStreams.java @@ -37,62 +37,37 @@ /** * Utility for working with byte streams. * - * @author Guava Authors + * @author Kyle Wood * @since 0.3.0 */ public final class ByteStreams { - // ------------------------------------------------ - // The following code is taken from Guava (d0d5bd7) - // - // The code remains mostly untouched, only style-differences are present. - // ------------------------------------------------ - // Copyright (C) 2007 The Guava Authors - // - // Licensed 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. - // ------------------------------------------------ - - private static final int BUFFER_SIZE = 8192; - - /** Creates a new byte array for buffering reads or writes. */ - private static byte[] createBuffer() { - return new byte[BUFFER_SIZE]; - } - /** - * Copies all bytes from the input stream to the output stream. Does not close or flush either - * stream. + * Copy all of the data from the {@code from} input to the {@code to} output. * - * @param from the input stream to read from - * @param to the output stream to write to - * @return the number of bytes copied - * @throws IOException if an I/O error occurs + * @param from The input to copy from. + * @param to The output to copy to. + * @param buffer The byte array to use as the copy buffer. + * @throws IOException If an IO error occurs. */ - public static long copy(final InputStream from, final OutputStream to) throws IOException { - final byte[] buf = createBuffer(); - long total = 0; - while (true) { - final int r = from.read(buf); - if (r == -1) { - break; - } - to.write(buf, 0, r); - total += r; + public static void copy(final InputStream from, final OutputStream to, final byte[] buffer) throws IOException { + int read; + while ((read = from.read(buffer)) != -1) { + to.write(buffer, 0, read); } - return total; } - // ------------------------------------------------ - // End of Apache-licensed Guava code. - // ------------------------------------------------ + /** + * Copy all of the data from the {@code from} input to the {@code to} output, + * using a default buffer. + * + * @param from The input to copy from. + * @param to The output to copy to. + * @throws IOException If an IO error occurs. + */ + public static void copy(final InputStream from, final OutputStream to) throws IOException { + copy(from, to, new byte[8192]); + } private ByteStreams() { } diff --git a/bombe/src/test/groovy/org/cadixdev/bombe/test/type/TypeSpec.groovy b/bombe/src/test/groovy/org/cadixdev/bombe/test/type/TypeSpec.groovy index 07856f5..fcb8190 100644 --- a/bombe/src/test/groovy/org/cadixdev/bombe/test/type/TypeSpec.groovy +++ b/bombe/src/test/groovy/org/cadixdev/bombe/test/type/TypeSpec.groovy @@ -35,6 +35,7 @@ import org.cadixdev.bombe.type.BaseType import org.cadixdev.bombe.type.FieldType import org.cadixdev.bombe.type.ObjectType import org.cadixdev.bombe.type.Type +import org.cadixdev.bombe.type.TypeReader import org.cadixdev.bombe.type.VoidType import spock.lang.Specification @@ -74,6 +75,19 @@ class TypeSpec extends Specification { 'Lorg/cadixdev/demo/Test$Inner;' | _ } + def "throw on invalid object type"(final String raw) { + when: + new TypeReader(raw).readObjectType() + + then: + thrown(IllegalStateException) + + where: + raw | _ + 'Ljava/lang/String' | _ + 'Cjava/lang/String;' | _ + } + def "reads base type"(final String raw, final BaseType expected) { given: def type = Type.of(raw) diff --git a/build.gradle b/build.gradle index ffa8610..f11cf63 100644 --- a/build.gradle +++ b/build.gradle @@ -7,27 +7,31 @@ allprojects { } subprojects { - apply plugin: 'java' + apply plugin: 'java-library' apply plugin: 'groovy' - apply plugin: 'maven' + apply plugin: 'maven-publish' - sourceCompatibility = '1.8' - targetCompatibility = '1.8' + java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + + withJavadocJar() + withSourcesJar() + } group = 'org.cadixdev' archivesBaseName = project.name.toLowerCase() - version = '0.4.3' + version = '0.5.0-SNAPSHOT' repositories { mavenCentral() } dependencies { - testCompile 'org.codehaus.groovy:groovy-all:2.5.8' - testCompile 'org.spockframework:spock-core:1.3-groovy-2.5' - testCompile 'org.junit.jupiter:junit-jupiter-api:5.5.1' - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.1' - testRuntime 'org.junit.vintage:junit-vintage-engine:5.5.1' + testImplementation 'org.codehaus.groovy:groovy-all:3.0.7' + testImplementation 'org.spockframework:spock-core:2.0-M4-groovy-3.0' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.1' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.5.1' } test { @@ -46,96 +50,81 @@ subprojects { ) } - task javadocJar(type: Jar, dependsOn: 'javadoc') { - from javadoc.destinationDir - classifier = 'javadoc' - } + publishing { + publications { + mavenJava(MavenPublication) { + artifactId = project.archivesBaseName + from components.java - task sourcesJar(type: Jar, dependsOn: 'classes') { - from sourceSets.main.allSource - classifier = 'sources' - } + pom { + name = project.name + description = project.description + packaging = 'jar' + url = project.url + inceptionYear = project.inceptionYear + + scm { + url = 'https://github.com/CadixDev/Bombe' + connection = 'scm:git:https://github.com/CadixDev/Bombe.git' + developerConnection = 'scm:git:git@github.com:CadixDev/Bombe.git' + } - artifacts { - archives javadocJar - archives sourcesJar - } + issueManagement { + system = 'GitHub' + url = 'https://github.com/CadixDev/Bombe/issues' + } - jacocoTestReport { - reports { - xml.enabled = true - html.enabled = true + licenses { + license { + name = 'BSD 3-Clause' + url = 'https://opensource.org/licenses/BSD-3-Clause' + distribution = 'repo' + } + } + + developers { + developer { + id = 'jamierocks' + name = 'Jamie Mansfield' + email = 'jmansfield@cadixdev.org' + url = 'https://www.jamiemansfield.me/' + timezone = 'Europe/London' + } + } + } + } + } + repositories { + if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword')) { + maven { + url = !version.endsWith('-SNAPSHOT') ? + 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' : + 'https://oss.sonatype.org/content/repositories/snapshots/' + + credentials { + username = ossrhUsername + password = ossrhPassword + } + } + } } } - check.dependsOn jacocoTestReport if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword')) { apply plugin: 'signing' signing { - required { !version.endsWith('-SNAPSHOT') && gradle.taskGraph.hasTask(tasks.uploadArchives) } - sign configurations.archives + required { !version.endsWith('-SNAPSHOT') && gradle.taskGraph.hasTask(tasks.publish) } + sign publishing.publications.mavenJava } } - uploadArchives { - repositories { - mavenDeployer { - // Maven Central - if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword')) { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - - repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') { - authentication(userName: ossrhUsername, password: ossrhPassword) - } - - snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/') { - authentication(userName: ossrhUsername, password: ossrhPassword) - } - } - - pom { - artifactId = project.archivesBaseName - - project { - name = project.name - description = project.description - packaging = 'jar' - url = project.url - inceptionYear = project.inceptionYear - - scm { - url = 'https://github.com/CadixDev/Bombe' - connection = 'scm:git:https://github.com/CadixDev/Bombe.git' - developerConnection = 'scm:git:git@github.com:CadixDev/Bombe.git' - } - - issueManagement { - system = 'GitHub' - url = 'https://github.com/CadixDev/Bombe/issues' - } - - licenses { - license { - name = 'BSD 3-Clause' - url = 'https://opensource.org/licenses/BSD-3-Clause' - distribution = 'repo' - } - } - - developers { - developer { - id = 'jamierocks' - name = 'Jamie Mansfield' - email = 'dev@jamierocks.uk' - url = 'https://www.jamiemansfield.me/' - timezone = 'Europe/London' - } - } - } - } - } + jacocoTestReport { + reports { + xml.enabled = true + html.enabled = true } } + check.dependsOn jacocoTestReport } task codeCoverageReport(type: JacocoReport) { diff --git a/changelogs/0.3.5.md b/changelogs/0.3.5.md new file mode 100644 index 0000000..5f44066 --- /dev/null +++ b/changelogs/0.3.5.md @@ -0,0 +1,15 @@ +Bombe 0.3.5 +=== + +Bombe 0.3.5 is a small release introducing some new APIs to bolster the +capabilities of the jar transformation framework, namely allowing entries to be +introduced. To accomplish this, a `JarEntryTransformer#additions()` method has +been introduced. The `Jars` utility has been updated to support this, and a +release of Atlas will be made shortly to implement this feature. + +The `Jars` utility has been deprecated in this version, advising consumers to +switch to Atlas. Jars was removed in 0.4.0, so this just serves as a final +notice to any lingering applications using the utility. + +The remapping transformer will additionally strip signature files and entries +in the manifest. This transformer may in future be available standalone. diff --git a/changelogs/0.4.4.md b/changelogs/0.4.4.md new file mode 100644 index 0000000..b8b2284 --- /dev/null +++ b/changelogs/0.4.4.md @@ -0,0 +1,11 @@ +Bombe 0.4.4 +=== + +Bombe 0.4.4 is a small release introducing some new APIs to bolster the +capabilities of the jar transformation framework, namely allowing entries to be +introduced. To accomplish this, a `JarEntryTransformer#additions()` method has +been introduced. A release of Atlas will be made shortly to implement this +feature. + +The remapping transformer will additionally strip signature files and entries +in the manifest. This transformer may in future be available standalone. diff --git a/changelogs/0.5.0.md b/changelogs/0.5.0.md new file mode 100644 index 0000000..8c1880b --- /dev/null +++ b/changelogs/0.5.0.md @@ -0,0 +1,14 @@ +Bombe 0.5.0 +=== + +Bombe 0.5.0 is largely a maintenance release, cleaning up the Bombe codebase and +preparing it for newer Java modules. + +## Improvements + +- Handling for multi-release JAR files +- Improved the robustness of reading descriptors + - Introduced a reader for signatures + - [GH-17] Prevent TypeReader reading invalid object descriptors + +[GH-17]: https://github.com/CadixDev/Bombe/issues/17 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a5fe1cb..0d4a951 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 949819d..28ff446 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip