如何使用命令行运行带有 OkHttp 的 Kotlin 代码?

huangapple go评论56阅读模式
英文:

How do I run Kotlin code using OkHttp from the command line?

问题

I tried running Kotlin code on macOS 13 from the command line, first I installed it with:

brew install kotlin

then I made a directory and downloaded the latest versions of some jar files that seemed relevant:

mkdir -p /tmp/kotlin
cd /tmp/kotlin
curl https://repo1.maven.org/maven2/com/squareup/okhttp3/okhttp/4.11.0/okhttp-4.11.0.jar > okhttp-4.11.0.jar
curl https://repo1.maven.org/maven2/com/squareup/okio/okio/3.3.0/okio-3.3.0.jar > okio-3.3.0.jar
curl https://repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar > kotlin-stdlib-1.8.21.jar

(ChatGPT told me to install kotlin-stdlib too, I'm not sure that makes sense...)

then I created a sample file called OkHttpExample.kt with these contents:

import java.io.IOException;
import okhttp3.OkHttpClient
import okhttp3.Request

fun main() {
    val client = OkHttpClient()

    val request = Request.Builder()
        .url("https://example.com")
        .build()

    client.newCall(request).execute().use { response ->
        if (!response.isSuccessful) throw IOException("Unexpected code $response")

        println(response.body!!.string())
    }
}

and tried to compile and run it

kotlinc -classpath okhttp-4.11.0.jar:kotlin-stdlib-1.8.21.jar:okio-3.3.0.jar OkHttpExample.kt -include-runtime -d OkHttpExample.jar
java -classpath okhttp-4.11.0.jar:kotlin-stdlib-1.8.21.jar:okio-3.3.0.jar:OkHttpExample.jar OkHttpExampleKt

but the java command fails with this error:

Exception in thread "main" java.lang.NoClassDefFoundError: okio/Buffer
	at okhttp3.ResponseBody$Companion.create(ResponseBody.kt:248)
	at okhttp3.ResponseBody$Companion.create$default(ResponseBody.kt:247)
	at okhttp3.internal.Util.<clinit>(Util.kt:65)
	at okhttp3.OkHttpClient.<clinit>(OkHttpClient.kt:1073)
	at OkHttpExampleKt.main(OkHttpExample.kt:6)
	at OkHttpExampleKt.main(OkHttpExample.kt)
Caused by: java.lang.ClassNotFoundException: okio.Buffer
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
	... 6 more
英文:

I tried running Kotlin code on macOS 13 from the command line, first I installed it with

brew install kotlin

then I made a directory and downloaded the latest versions of some jar files that seemed relevant:

mkdir -p /tmp/kotlin 
cd /tmp/kotlin 
curl https://repo1.maven.org/maven2/com/squareup/okhttp3/okhttp/4.11.0/okhttp-4.11.0.jar &gt; okhttp-4.11.0.jar 
curl https://repo1.maven.org/maven2/com/squareup/okio/okio/3.3.0/okio-3.3.0.jar &gt; okio-3.3.0.jar 
curl https://repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar &gt; kotlin-stdlib-1.8.21.jar

(ChatGPT told me to install kotlin-stdlib too, I'm not sure that makes sense...)

then I created a sample file called OkHttpExample.kt with these contents:

import java.io.IOException;
import okhttp3.OkHttpClient
import okhttp3.Request

fun main() {
    val client = OkHttpClient()

    val request = Request.Builder()
        .url(&quot;https://example.com&quot;)
        .build()

    client.newCall(request).execute().use { response -&gt;
        if (!response.isSuccessful) throw IOException(&quot;Unexpected code $response&quot;)

        println(response.body!!.string())
    }
}

and tried to compile and run it

kotlinc -classpath okhttp-4.11.0.jar:kotlin-stdlib-1.8.21.jar:okio-3.3.0.jar OkHttpExample.kt -include-runtime -d OkHttpExample.jar
java -classpath okhttp-4.11.0.jar:kotlin-stdlib-1.8.21.jar:okio-3.3.0.jar:OkHttpExample.jar OkHttpExampleKt

but the java command fails with this error:

Exception in thread &quot;main&quot; java.lang.NoClassDefFoundError: okio/Buffer
	at okhttp3.ResponseBody$Companion.create(ResponseBody.kt:248)
	at okhttp3.ResponseBody$Companion.create$default(ResponseBody.kt:247)
	at okhttp3.internal.Util.&lt;clinit&gt;(Util.kt:65)
	at okhttp3.OkHttpClient.&lt;clinit&gt;(OkHttpClient.kt:1073)
	at OkHttpExampleKt.main(OkHttpExample.kt:6)
	at OkHttpExampleKt.main(OkHttpExample.kt)
Caused by: java.lang.ClassNotFoundException: okio.Buffer
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
	... 6 more

答案1

得分: 1

解决您的具体问题

NoClassDefFoundError: okio/Buffer 表示某些代码尝试使用 okio.Buffer 类,但该类不在您放在类路径上的任何jar文件中。

这可能是因为您刚刚手动挑选了一些要下载的jar文件,并且忽略了传递性依赖关系。例如,您可能缺少了 okio 本身的依赖项 okio-jvm

一种解决方法是自行查找所有传递性依赖项(例如,查看Maven Central中的.pom文件),然后手动下载更多jar文件,但这并不是非常实际的方法。

推荐方法

相反,我强烈建议在这里有两个选项:

  1. 创建一个“标准”的Kotlin项目,并使用构建工具如Gradle来管理依赖项和编译。这需要一些设置,但对大多数人来说会更加熟悉,而且您可以轻松找到在线示例。

  2. 如果您只是在玩耍,可以尝试使用Kotlin脚本,使用.main.kts脚本定义,这可能简化您的工作流程,但请注意它是实验性的并且不是很知名。

我将在这里详细介绍选项2,因为关于它的信息较难找到。

要使用main-kts定义,请确保您的文件以.main.kts结尾。然后将您的代码直接放在文件的顶层,而不是将其包装在main()函数中。

不需要手动下载jar文件,只需在文件顶部使用@file:DependsOn添加依赖项,其中包含依赖项的Maven坐标(您无需添加传递性依赖项,只需添加您直接使用的依赖项):

script.main.kts(扩展名很重要!)

@file:DependsOn("com.squareup.okhttp3:okhttp:4.11.0")

import java.io.IOException
import okhttp3.OkHttpClient
import okhttp3.Request

val client = OkHttpClient()
val request = Request.Builder().url("https://example.com").build()
client.newCall(request).execute().use { response ->
    if (!response.isSuccessful) throw IOException("Unexpected code $response")

    println(response.body!!.string())
}

然后,您可以使用一个简单的命令来编译并运行它:

kotlin script.main.kts

这里有一个更“官方”的关于main.kts使用的示例:
https://github.com/Kotlin/kotlin-script-examples/blob/master/jvm/main-kts/MainKts.md

英文:

Fixing your specific problem

NoClassDefFoundError: okio/Buffer means that some code tries to use the okio.Buffer class but the class is not in any jar that you put on the classpath.

This may happen because you just manually cherry-picked some jars to download, and you missed transitive dependencies. For instance, it's likely you're missing the okio-jvm dependency, which is a dependency of okio itself.

One solution is to find all transitive dependencies yourself (for instance by looking at .pom files in Maven Central) and download more and more jars by hand, but it's not very practical.

Instead, I highly suggest 2 options here:

  1. create a "standard" Kotlin project and use a build tool like Gradle to manage dependencies and compilation. It requires a bit of setup, but it will be more familiar to most people, and you may easily find examples online.

  2. if you're just playing around, you can try to use Kotlin Scripting with the .main.kts script definition, which may simplify your workflow here, but note that it's experimental and not very well known.

I'll elaborate on option 2 here because it's harder to find information about it.

To use the main-kts definition, make sure your file ends with .main.kts. Then put your code directly at the top level without wrapping it in a main() function.

Instead of manually downloading jars, add dependencies to it using @file:DependsOn at the top of the file, with the maven coordinates of the dependencies (you don't need to put transitive dependencies, just the ones you want to use directly):

script.main.kts (the extension matters!)

@file:DependsOn(&quot;com.squareup.okhttp3:okhttp:4.11.0&quot;)

import java.io.IOException
import okhttp3.OkHttpClient
import okhttp3.Request

val client = OkHttpClient()
val request = Request.Builder().url(&quot;https://example.com&quot;).build()
client.newCall(request).execute().use { response -&gt;
    if (!response.isSuccessful) throw IOException(&quot;Unexpected code $response&quot;)

    println(response.body!!.string())
}

Then you can compile and run it in one simple command:

kotlin script.main.kts

Here is a more "official" example about main.kts usage:
https://github.com/Kotlin/kotlin-script-examples/blob/master/jvm/main-kts/MainKts.md

huangapple
  • 本文由 发表于 2023年5月7日 17:42:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76193145.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定