diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/PackageMapper.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/PackageMapper.kt new file mode 100644 index 000000000..e5a2fcdd9 --- /dev/null +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/PackageMapper.kt @@ -0,0 +1,55 @@ +package com.github.jengelman.gradle.plugins.shadow.internal + +import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator +import com.github.jengelman.gradle.plugins.shadow.relocation.relocateClass +import com.github.jengelman.gradle.plugins.shadow.relocation.relocatePath +import java.util.regex.Pattern + +/** + * Modified from [org.apache.maven.plugins.shade.DefaultShader.PackageMapper.java](https://github.com/apache/maven-shade-plugin/blob/5115e41e66ac19f10b661e63f8de76ad3e5905d2/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java#L725-L735). + */ +internal interface PackageMapper { + + /** + * Map an entity name according to the mapping rules known to this package mapper + * + * @param entityName entity name to be mapped + * @param mapPaths map "slashy" names like paths or internal Java class names, e.g. `com/acme/Foo`? + * @param mapPackages map "dotty" names like qualified Java class or package names, e.g. `com.acme.Foo`? + * @return mapped entity name, e.g. `org/apache/acme/Foo` or `org.apache.acme.Foo` + */ + fun map(entityName: String, mapPaths: Boolean, mapPackages: Boolean): String +} + +/** + * Modified from [org.apache.maven.plugins.shade.DefaultShader.DefaultPackageMapper.java](https://github.com/apache/maven-shade-plugin/blob/5115e41e66ac19f10b661e63f8de76ad3e5905d2/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java#L740-L774). + */ +internal class DefaultPackageMapper( + private val relocators: Set, +) : PackageMapper { + + override fun map(entityName: String, mapPaths: Boolean, mapPackages: Boolean): String { + var value = entityName + var prefix = "" + var suffix = "" + + val matcher = classPattern.matcher(value) + if (matcher.matches()) { + prefix = matcher.group(1) + "L" + suffix = ";" + value = matcher.group(2) + } + + for (relocator in relocators) { + if (mapPackages && relocator.canRelocateClass(value)) { + return prefix + relocator.relocateClass(value) + suffix + } else if (mapPaths && relocator.canRelocatePath(value)) { + return prefix + relocator.relocatePath(value) + suffix + } + } + + return value + } +} + +private val classPattern: Pattern = Pattern.compile("(\\[*)?L(.+);") diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocatorRemapper.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocatorRemapper.kt deleted file mode 100644 index 42c0e69d1..000000000 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/RelocatorRemapper.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.github.jengelman.gradle.plugins.shadow.internal - -import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator -import com.github.jengelman.gradle.plugins.shadow.relocation.relocateClass -import com.github.jengelman.gradle.plugins.shadow.relocation.relocatePath -import java.util.regex.Pattern -import org.objectweb.asm.commons.Remapper - -/** - * Modified from [org.apache.maven.plugins.shade.DefaultShader.RelocatorRemapper](https://github.com/apache/maven-shade-plugin/blob/83c123d1f9c5f6927af2aca12ee322b5168a7c63/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java#L689-L772). - * Modified from [org.apache.maven.plugins.shade.DefaultShader.DefaultPackageMapper](https://github.com/apache/maven-shade-plugin/blob/199ffaecd26a912527173ed4edae366e48a00998/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java#L737-L774). - * - * @author John Engelman - */ -internal class RelocatorRemapper( - private val relocators: Set, -) : Remapper() { - private val classPattern: Pattern = Pattern.compile("(\\[*)?L(.+)") - - override fun mapValue(value: Any): Any { - return if (value is String) { - map(value) - } else { - super.mapValue(value) - } - } - - override fun map(name: String): String { - var newName = name - var prefix = "" - var suffix = "" - - val matcher = classPattern.matcher(newName) - if (matcher.matches()) { - prefix = matcher.group(1) + "L" - suffix = "" - newName = matcher.group(2) - } - - for (relocator in relocators) { - if (relocator.canRelocateClass(newName)) { - return prefix + relocator.relocateClass(newName) + suffix - } else if (relocator.canRelocatePath(newName)) { - return prefix + relocator.relocatePath(newName) + suffix - } - } - - return name - } - - fun mapPath(path: String): String { - return map(path.substring(0, path.indexOf('.'))) - } -} diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowClassRemapper.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowClassRemapper.kt new file mode 100644 index 000000000..d4151bd73 --- /dev/null +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/internal/ShadowClassRemapper.kt @@ -0,0 +1,47 @@ +package com.github.jengelman.gradle.plugins.shadow.internal + +import org.objectweb.asm.ClassVisitor +import org.objectweb.asm.commons.ClassRemapper +import org.objectweb.asm.commons.Remapper + +/** + * Modified from [org.apache.maven.plugins.shade.DefaultShader.ShadeClassRemapper.java](https://github.com/apache/maven-shade-plugin/blob/5115e41e66ac19f10b661e63f8de76ad3e5905d2/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java#L808-L844). + */ +internal class ShadowClassRemapper( + classVisitor: ClassVisitor, + private val packageMapper: PackageMapper, + private val pkg: String, + remapper: Remapper = object : Remapper() { + override fun mapValue(value: Any): Any { + return if (value is String) { + packageMapper.map(value, mapPaths = true, mapPackages = true) + } else { + super.mapValue(value) + } + } + + override fun map(internalName: String): String { + return packageMapper.map(internalName, mapPaths = true, mapPackages = false) + } + }, +) : ClassRemapper(classVisitor, remapper), + PackageMapper { + private var remapped = false + + override fun visitSource(source: String?, debug: String?) { + if (source == null) return super.visitSource(null, debug) + + val fqSource: String = pkg + source + val mappedSource = map(fqSource, mapPaths = true, mapPackages = false) + val filename = mappedSource.substring(mappedSource.lastIndexOf('/') + 1) + super.visitSource(filename, debug) + } + + override fun map(entityName: String, mapPaths: Boolean, mapPackages: Boolean): String { + val mapped = packageMapper.map(entityName, mapPaths, mapPackages) + if (!remapped) { + remapped = mapped != entityName + } + return mapped + } +} diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt index 9eb262ffd..e523d79c4 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/tasks/ShadowCopyAction.kt @@ -1,6 +1,7 @@ package com.github.jengelman.gradle.plugins.shadow.tasks -import com.github.jengelman.gradle.plugins.shadow.internal.RelocatorRemapper +import com.github.jengelman.gradle.plugins.shadow.internal.DefaultPackageMapper +import com.github.jengelman.gradle.plugins.shadow.internal.ShadowClassRemapper import com.github.jengelman.gradle.plugins.shadow.internal.cast import com.github.jengelman.gradle.plugins.shadow.internal.zipEntry import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator @@ -24,7 +25,6 @@ import org.gradle.api.tasks.WorkResult import org.gradle.api.tasks.WorkResults import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassWriter -import org.objectweb.asm.commons.ClassRemapper /** * Modified from [org.gradle.api.internal.file.archive.ZipCopyAction.java](https://github.com/gradle/gradle/blob/b893c2b085046677cf858fb3d5ce00e68e556c3a/platforms/core-configuration/file-operations/src/main/java/org/gradle/api/internal/file/archive/ZipCopyAction.java). @@ -124,7 +124,7 @@ public open class ShadowCopyAction( private inner class StreamAction( private val zipOutStr: ZipOutputStream, ) : CopyActionProcessingStreamAction { - private val remapper = RelocatorRemapper(relocators) + private val packageMapper = DefaultPackageMapper(relocators) init { logger.info("Relocator count: ${relocators.size}.") @@ -155,7 +155,7 @@ public open class ShadowCopyAction( } fileDetails.remapClass() } else { - val mapped = remapper.map(path) + val mapped = packageMapper.map(path, mapPaths = true, mapPackages = true) if (transform(fileDetails, mapped)) return fileDetails.writeToZip(mapped) } @@ -184,7 +184,8 @@ public open class ShadowCopyAction( // that use the constant pool to determine the dependencies of a class. val cw = ClassWriter(0) val cr = ClassReader(inputStream) - val cv = ClassRemapper(cw, remapper) + val pkg = name.substring(0, name.lastIndexOf('/') + 1) + val cv = ShadowClassRemapper(cw, packageMapper, pkg) try { cr.accept(cv, ClassReader.EXPAND_FRAMES) @@ -195,7 +196,9 @@ public open class ShadowCopyAction( // Temporarily remove the multi-release prefix. val multiReleasePrefix = "^META-INF/versions/\\d+/".toRegex().find(path)?.value.orEmpty() val newPath = path.replace(multiReleasePrefix, "") - val mappedName = multiReleasePrefix + remapper.mapPath(newPath) + val mappedName = multiReleasePrefix + packageMapper.map(newPath, mapPaths = true, mapPackages = false) + // Need to take the .class off for remapping evaluation + .substringBeforeLast('.') try { val entry = zipEntry("$mappedName.class", preserveFileTimestamps, lastModified) { unixMode = UnixStat.FILE_FLAG or permissions.toUnixNumeric()