有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用Shadow重新定位的包中的java Kotlin属性不起作用

我试图用Shadow重新定位一个包(具体来说是OkHttp 4),并使用以下Gradle配置:

apply plugin: 'java'
apply plugin: 'com.github.johnrengelman.shadow'

shadowJar {
    archiveBaseName.set('my_archive')
    archiveClassifier.set(null)
    version = null

    relocate 'okhttp3', 'my.prefix.okhttp3'
    relocate 'okio', 'my.prefix.okio'
}

dependencies {
    implementation("com.squareup.okhttp3:okhttp:4.2.1") {
        exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib"
    }
}

(我省略了buildscript部分,重要的一点是使用的Shadow版本是5.1.0。包前缀等也已更改)

在OkHttp 3.12.0及更早版本中,这是完全Java的。既然OkHttp 4是用Kotlin编写的,我在使用属性时遇到了问题,尤其是在Kotlin代码中。从Java使用时,重新定位的OkHttp工作正常。但是访问Kotlin中的属性,比如:

val cache = httpClient.cache

。。。结果出现异常:

java.lang.NoSuchMethodError: No virtual method getCache()Lmy/prefix/okhttp3/Cache; in class Lmy/prefix/okhttp3/OkHttpClient; or its super classes (declaration of 'my.prefix.okhttp3.OkHttpClient' appears in /data/app/redacted.redacted-0yalPGR5aw0RSY2Zdxnq7Q==/base.apk)

如你所见,该应用程序是安卓应用程序,以防万一

知道我的配置有什么问题吗


共 (2) 个答案

  1. # 1 楼答案

    我们在一个非android项目中也经历了类似的事情。 包级别的“things”(在本例中是一个扩展函数)实际上在编译器生成的类(在本例中称为ExtensionKt.class)上是静态的

    我可以从Java或Scala代码访问该类。 然而,在Kotlin代码中,编译器不允许我访问ExtensionKt类,而shadow Jar重新定位的包以某种方式破坏了原始语法,因此无法再通过包名访问它。作为一种临时解决方法,我们可以从Java访问包范围内的内容:

    因此,取而代之的是Kotlin代码:

    import my.package.name.niceExtensionFunction
    
    ...
    
    val x = SomeClass()
    val y = x.niceExtensionFunction()
    

    我们在Java中这样做:

    import my.package.name.ExtensionKt;
    
    ...
    
    SomeClass x = new SomeClass;
    Object y = ExtensionKt.niceExtensionFunction(x)
    
    
  2. # 2 楼答案

    这并不是一个完美的解决方案,但至少在一定程度上可以让事情顺利进行。与其完全排除嵌入式Kotlin stdlib,不如随它去,并重新定位它。最简单的方法是将所有内容重新定位到同一前缀,并将其添加到build.gradle

    task relocateShadowJar(type: ConfigureShadowRelocation) {
        target = tasks.shadowJar
        prefix = "my.prefix"
    
    }
    
    tasks.shadowJar.dependsOn tasks.relocateShadowJar
    

    您可能还需要在shadowJar任务中排除一些Kotlin META-INF

    这种方法的问题(至少对我来说)在于,虽然一切或多或少都能正常工作,但现在你的应用程序中可能有两个Kotlin stdlib:一个是你的前缀版本,另一个是你通常使用的版本。此外,属性语法也不起作用。就像问题中的例子一样

    val cache = httpClient.cache
    

    实际上变成了

    val cache = httpClient.cache()
    

    。。。这不太好

    我现在面临的另一个问题是,在Android Studio中,生成的jar中的所有内容在代码编辑器中显示为红色,即Android Studio看不到jar中的内容。所有的东西都编译得很好,只是编辑代码本身是一件痛苦的事情,因为你没有完成任何代码,Android Studio有时会干扰你的导入。(因为它显然认为这些进口是无效的)