java.lang.IllegalArgumentException: 日志标记 "okhttp3.mockwebserver.MockWebServer" 超过 23 个字符的限制

java.lang.IllegalArgumentException: Log tag "okhttp3.mockwebserver.MockWebServer" exceeds limit of 23 characters

澄清这不是有人建议的重复问题的几点:


原题:

我正在使用 ExpressoMockWebServer 进行 Android 网络服务测试,但是我遇到以下异常,告诉我日志标记问题:

"okhttp3.mockwebserver.MockWebServer" exceeds limit of 23 characters.

详细堆栈跟踪如下:

2020-08-13 11:31:13.277 16901-17085/com.xxx.app I/okhttp.OkHttpClient: <-- HTTP FAILED: java.net.SocketTimeoutException: timeout
2020-08-13 11:31:13.280 16901-17346/com.xxx.app E/AndroidRuntime: FATAL EXCEPTION: MockWebServer TaskRunner
    Process: com.xxx.app, PID: 16901
    java.lang.IllegalArgumentException: Log tag "okhttp3.mockwebserver.MockWebServer" exceeds limit of 23 characters
    
        at android.util.Log.isLoggable(Native Method)
        at okhttp3.internal.platform.android.AndroidLog.androidLog$okhttp(AndroidLog.kt:66)
        at okhttp3.internal.platform.android.AndroidLogHandler.publish(AndroidLog.kt:39)
        at java.util.logging.Logger.log(Logger.java:615)
        at java.util.logging.Logger.doLog(Logger.java:636)
        at java.util.logging.Logger.log(Logger.java:725)
        at okhttp3.mockwebserver.MockWebServer$serveConnection$$inlined$execute.runOnce(TaskQueue.kt:224)
        at okhttp3.internal.concurrent.TaskRunner.runTask(TaskRunner.kt:116)
        at okhttp3.internal.concurrent.TaskRunner.access$runTask(TaskRunner.kt:42)
        at okhttp3.internal.concurrent.TaskRunner$runnable.run(TaskRunner.kt:65)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
        at java.lang.Thread.run(Thread.java:762)
2020-08-13 11:31:13.293 16901-17346/com.xxx.app I/Process: Sending signal. PID: 16901 SIG: 9

这是由于日志 API 不允许超过 23 个字符的标签。

您可以按照 禁用 lint 检查,但您已收到警告。

为了更好地理解访问:

在深入研究 MockWebServer.kt 的源代码后,我找到了解决此问题的方法。在这个文件中,有一个 属性 如下所示:

private val logger = Logger.getLogger(MockWebServer::class.java.name)

MockWebServer::class.java.name 将 return 一个完整的 class 名称 okhttp3.mockwebserver.MockWebServer,显然,这个名称作为 Android 日志标记已经超过 23 个字符.修复是使用 Kotlin 反射来替换记录器 属性。反射代码如下:

fun <T : Any> T.setPrivateProperty(variableName: String, data: Any): Any? {
    return javaClass.getDeclaredField(variableName).let { field ->
        field.isAccessible = true
        field.set(this, data)
        return@let field.get(this)
    }
}

@before 方法中,使用 simpleName

设置记录器标签
val mockWebServer = MockWebServer() // this is declared inside test class.

@Before
fun setup() {

    mockWebServer.setAndReturnPrivateProperty("logger", 
        Logger.getLogger(MockWebServer::class.java.simpleName))

    mockWebServer.start(8080)
}    

MockWebServer::class.java.simpleName 将 return 更短的 class 名称并解决问题。