我有一个模块化项目,其中 api 层被分成自己的模块。由于它不依赖于 Android SDK,因此我将其设为仅 kotlin 的模块。这在构建文件中有如下所示的 kotlin jvm 插件。当我尝试使用 MockWebServer 时,这会导致 java.lang.NoSuchFieldError: Companion 错误(只有这个,其他一切正常)。
在构建文件中使用 kotlin dsl,build.gradle.kts 文件如下所示:
plugins {
kotlin("jvm")
kotlin("kapt")
}
dependencies {
implementation(kotlin("stdlib"))
implementation("com.squareup.retrofit2:retrofit:2.7.0")
implementation("com.squareup.retrofit2:converter-moshi:2.7.0")
implementation("com.squareup.moshi:moshi-kotlin:1.9.2")
implementation("com.squareup.okhttp3:logging-interceptor:4.4.0")
testImplementation("com.squareup.okhttp3:mockwebserver:4.4.0")
testImplementation("junit:junit:4.13")
kapt("com.squareup.moshi:moshi-kotlin-codegen:2.7.0")
// There are various other libraries, but I'm including the only ones I feel are relevant
// in case my problem is to do with conflicting versions of libraries
}
这是我的单元测试的片段。我实例化 MockWebServer() 的行失败并出现 NoSuchFieldError: Companion:
class LoginServiceTest {
private val mockWebServer: MockWebServer = MockWebServer()
和堆栈跟踪:
java.lang.NoSuchFieldError: Companion
at okhttp3.internal.Util.<clinit>(Util.kt:69)
at okhttp3.mockwebserver.MockWebServer.<init>(MockWebServer.kt:101)
at com.mobilleo.data.webapi.service.core.user.LoginServiceTest.<init>(LoginServiceTest.kt:29)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:250)
at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:260)
at org.junit.runners.BlockJUnit4ClassRunner$2.runReflectiveCall(BlockJUnit4ClassRunner.java:309)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Process finished with exit code 255
经过各种实验,我发现了以下内容:
- 将 okhttp3 库回滚到版本 3.xx 可以消除此错误,但随后我失去了许多需要的 okhttp3 功能,例如拦截器、身份验证器等。
- 我相信改造使用 okhttp3 3.14,但是在我尝试使用 MockWebServer 之前,我对使用 4.4.0 的 okttp3:logging-interceptor 没有任何问题
- 当我将模块切换到 kotlin android 模块时,它按预期工作。因此将构建文件更改为以下内容:
工作 build.gradle.kts:
plugins {
id("com.android.library")
kotlin("android")
kotlin("kapt")
}
android {
compileSdkVersion(29)
// etc. etc. Android config, that all seems a bit pointless just to get MockWebServer working
我的直觉告诉我,与仅使用 kotlin jvm 编译器相比,kotlin android 使用 Companion 对象或静态方法等编译 Kotlin 的方式存在一些差异,但我承认对“幕后”发生的事情知之甚少有了这一切。
如何使用 kotlin("jvm") 插件让 MockWebServer 在仅限 kotlin 的模块中工作?