diff --git a/api/shadow.api b/api/shadow.api index bea4872d9..a82d5997b 100644 --- a/api/shadow.api +++ b/api/shadow.api @@ -112,6 +112,7 @@ public abstract interface class com/github/jengelman/gradle/plugins/shadow/reloc public abstract fun applyToSourceContent (Ljava/lang/String;)Ljava/lang/String; public abstract fun canRelocateClass (Ljava/lang/String;)Z public abstract fun canRelocatePath (Ljava/lang/String;)Z + public fun getSkipStringConstants ()Z public abstract fun relocateClass (Lcom/github/jengelman/gradle/plugins/shadow/relocation/RelocateClassContext;)Ljava/lang/String; public abstract fun relocatePath (Lcom/github/jengelman/gradle/plugins/shadow/relocation/RelocatePathContext;)Ljava/lang/String; } @@ -127,7 +128,8 @@ public class com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocat public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Z)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ZZ)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun applyToSourceContent (Ljava/lang/String;)Ljava/lang/String; public fun canRelocateClass (Ljava/lang/String;)Z public fun canRelocatePath (Ljava/lang/String;)Z @@ -135,10 +137,12 @@ public class com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocat public fun exclude (Ljava/lang/String;)V public final fun getExcludes ()Ljava/util/Set; public final fun getIncludes ()Ljava/util/Set; + public fun getSkipStringConstants ()Z public fun hashCode ()I public fun include (Ljava/lang/String;)V public fun relocateClass (Lcom/github/jengelman/gradle/plugins/shadow/relocation/RelocateClassContext;)Ljava/lang/String; public fun relocatePath (Lcom/github/jengelman/gradle/plugins/shadow/relocation/RelocatePathContext;)Ljava/lang/String; + public fun setSkipStringConstants (Z)V } public abstract interface class com/github/jengelman/gradle/plugins/shadow/tasks/DependencyFilter : java/io/Serializable { diff --git a/docs/changes/README.md b/docs/changes/README.md index b9ea958ca..7bd6cf4cd 100644 --- a/docs/changes/README.md +++ b/docs/changes/README.md @@ -4,6 +4,7 @@ **Added** +- Support skipping string constant remapping. ([#1401](https://github.com/GradleUp/shadow/pull/1401)) - Let `assemble` depend on `shadowJar`. ([#1524](https://github.com/GradleUp/shadow/pull/1524)) - Fail build when inputting AAR files or using Shadow with AGP. ([#1530](https://github.com/GradleUp/shadow/pull/1530)) diff --git a/docs/configuration/relocation/README.md b/docs/configuration/relocation/README.md index 3cfe0e8d0..c8fc680dd 100644 --- a/docs/configuration/relocation/README.md +++ b/docs/configuration/relocation/README.md @@ -93,6 +93,63 @@ expression in `%regex[]` before passing it to `include`/`exclude`. } ``` +## Skipping Relocation for String Constants + +If there is a class like: + +```java +package foo; + +public class Bar { + public static void main(String[] args) { + System.out.println("foo.Bar"); + } +} +``` + +in your project, and you configure the relocation like: + +=== "Kotlin" + + ```kotlin + tasks.shadowJar { + relocate("foo", "my.foo") + } + ``` + +=== "Groovy" + + ```groovy + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + relocate 'foo', 'my.foo' + } + ``` + +the string constant `"foo.Bar"` will be relocated to `"my.foo.Bar"` by default. This may not be what you want, you can +skip relocating string constants in the classes like: + +=== "Kotlin" + + ```kotlin + tasks.shadowJar { + relocate("foo", "my.foo") { + // Optionally, defaults to `false`. + skipStringConstants = true + } + } + ``` + +=== "Groovy" + + ```groovy + tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + relocate('foo', 'my.foo') { + // Optionally, defaults to `false`. + skipStringConstants = true + } + } + ``` + ## Automatically Relocating Dependencies Shadow is shipped with a task that can be used to automatically configure all packages from all dependencies to be diff --git a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt index 083d955ce..d8c42802c 100644 --- a/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt +++ b/src/functionalTest/kotlin/com/github/jengelman/gradle/plugins/shadow/RelocationTest.kt @@ -585,16 +585,7 @@ class RelocationTest : BasePluginTest() { @Test fun relocateStringConstantsByDefault() { - writeClass { - """ - package my; - public class Main { - public static void main(String[] args) { - System.out.println("junit.framework.Test"); - } - } - """.trimIndent() - } + writeClassWithStringRef() projectScriptPath.appendText( """ $shadowJar { @@ -614,6 +605,46 @@ class RelocationTest : BasePluginTest() { ) } + @Issue( + "https://github.com/GradleUp/shadow/issues/232", + ) + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun canDisableRelocateStringConstants(skipStringConstants: Boolean) { + writeClassWithStringRef() + projectScriptPath.appendText( + """ + $shadowJar { + manifest { + attributes '$mainClassAttributeKey': 'my.Main' + } + relocate('junit', 'foo.junit') { + skipStringConstants = $skipStringConstants + } + } + """.trimIndent(), + ) + + run(shadowJarTask) + val result = runProcess("java", "-jar", outputShadowJar.use { it.toString() }) + + val expected = if (skipStringConstants) "junit.framework.Test" else "foo.junit.framework.Test" + assertThat(result).contains(expected) + } + + private fun writeClassWithStringRef() { + writeClass { + """ + package my; + public class Main { + public static void main(String[] args) { + System.out.println("junit.framework.Test"); + } + } + """.trimIndent() + } + } + private companion object { @JvmStatic fun prefixProvider() = listOf( 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 index d362996b1..232f5eccd 100644 --- 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 @@ -19,13 +19,20 @@ internal class RelocatorRemapper( override fun mapValue(value: Any): Any { return if (value is String) { - map(value) + mapName(value, mapLiterals = true) } else { super.mapValue(value) } } - override fun map(name: String): String { + override fun map(internalName: String): String = mapName(internalName) + + fun mapPath(path: String): String { + val dotIndex = path.indexOf('.') + return if (dotIndex == -1) path else map(path.take(dotIndex)) + } + + private fun mapName(name: String, mapLiterals: Boolean = false): String { var newName = name var prefix = "" var suffix = "" @@ -38,7 +45,9 @@ internal class RelocatorRemapper( } for (relocator in relocators) { - if (relocator.canRelocateClass(newName)) { + if (mapLiterals && relocator.skipStringConstants) { + return name + } else if (relocator.canRelocateClass(newName)) { return prefix + relocator.relocateClass(newName) + suffix } else if (relocator.canRelocatePath(newName)) { return prefix + relocator.relocatePath(newName) + suffix @@ -47,8 +56,4 @@ internal class RelocatorRemapper( return name } - - fun mapPath(path: String): String { - return map(path.substringBefore('.')) - } } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/Relocator.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/Relocator.kt index 073c29726..50616f83e 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/Relocator.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/Relocator.kt @@ -1,6 +1,7 @@ package com.github.jengelman.gradle.plugins.shadow.relocation import com.github.jengelman.gradle.plugins.shadow.transformers.CacheableTransformer +import org.gradle.api.tasks.Input /** * Modified from [org.apache.maven.plugins.shade.relocation.Relocator.java](https://github.com/apache/maven-shade-plugin/blob/master/src/main/java/org/apache/maven/plugins/shade/relocation/Relocator.java). @@ -19,6 +20,14 @@ public interface Relocator { public fun applyToSourceContent(sourceContent: String): String + /** + * Indicates whether this relocator should skip relocating string constants. + * + * Defaults to `false`. + */ + @get:Input + public val skipStringConstants: Boolean get() = false + public companion object { public val ROLE: String = Relocator::class.java.name } diff --git a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.kt b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.kt index ad2d7d0e5..1ae34df27 100644 --- a/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.kt +++ b/src/main/kotlin/com/github/jengelman/gradle/plugins/shadow/relocation/SimpleRelocator.kt @@ -19,6 +19,7 @@ public open class SimpleRelocator @JvmOverloads constructor( includes: List? = null, excludes: List? = null, private val rawString: Boolean = false, + @get:Input override var skipStringConstants: Boolean = false, ) : Relocator { private val pattern: String private val pathPattern: String @@ -137,6 +138,7 @@ public open class SimpleRelocator @JvmOverloads constructor( if (this === other) return true if (other !is SimpleRelocator) return false return rawString == other.rawString && + skipStringConstants == other.skipStringConstants && pattern == other.pattern && pathPattern == other.pathPattern && shadedPattern == other.shadedPattern && @@ -149,6 +151,7 @@ public open class SimpleRelocator @JvmOverloads constructor( override fun hashCode(): Int { var result = rawString.hashCode() + result = 31 * result + skipStringConstants.hashCode() result = 31 * result + pattern.hashCode() result = 31 * result + pathPattern.hashCode() result = 31 * result + shadedPattern.hashCode()