Hi, for a project, I need to download some JSONs a...
# gradle
a
Hi, for a project, I need to download some JSONs and generate Kotlin code from these JSONs before building the project, or just at some time using a gradle task, how can I achieve this ? (It's for generating an enum containing all the blocks of Minecraft for a project that I own that let's you generate Minecraft Java DataPacks from Kotlin code, the enum will be there to have better typings when targeting a block instead of just a String)
v
Either make a task that downloads the files and another task that transforms them, or one task that does both, whatever you prefer. Then register that task as
srcDir
for the source set.
m
I'd do in in 2 steps else the download task will never be up-to-date, right?
You don't want to download from the network every time you build
unless using a manually controlled input
FWIW, I did something very similar as a standalone .kts script. I then commited the generated kotlin files. The good parts is that you know between 2 game releases what assets changed with a diff so that you can update the callsites accordingly
v
You don't want to download from the network every time you build
I don't think it is relevant for that whether you use one or two tasks. The input is a network location, so the question is how to define that in a way that Gradle knows whether it needs to redownload. But you are right, two tasks are better either way, because even if you redownload in every build, the actual generation could stay up-to-date.
a
I think I'll create a script for these tasks, then launch the script when I want to create a release, and I can use GitHub Actions to automate this behavior so it won't be neither a problem 🙂
m
The script I linked above is a bit outdated, you can use `*.main.kts`now instead of kscript but the idea should be the same
a
WDYM by
*.main.kts
?
v
The Kotlin native scritping support for standalone Kotlin scripts. Instead of using kscript which was a previous 3rd-party take on it.
m
Exactly, just replace
Copy code
#!/usr/bin/env kscript
with
Copy code
#!/usr/bin/env kotlin
and name your file with a
.main.kts
extension and you should be good to go
a
I don't understand, how can I download the dependencies ?
m
Just like you would do with Ktor (or use OkHttp). I haven't used it in a long time so won't be able to help much there
One thing to note is that scripts are JVM only and don't understand Gradle metadata
So you'll most likely have to do
Copy code
@file:DependsOn("com.example:lib-jvm:1.0")
instead of just
Copy code
@file:DependsOn("com.example:lib:1.0")
(not sure if that's your issue above but might be related)
a
Ah thanks ! It was the issue yes :)
How can I apply the kotlinx.serialization gradle plugin to my script ? as I can't create serializable classes, I'm getting the following error :
Copy code
kotlinx.serialization compiler plugin is not applied to the module, so this annotation would not be processed. Make sure that you've setup your buildscript correctly and re-import project.
m
You can't. Or at least not trivially. What you can do though is parse to a JsonElement and then do things dynamically
I have this utility I used quite often
Copy code
fun JsonElement.toAny(): Any? = when (this) {
    is JsonObject -> this.mapValues { it.value.toAny() }
    is JsonArray -> this.map { it.toAny() }
    is JsonPrimitive -> {
        when {
            isString -> this.content
            this is JsonNull -> null
            else -> booleanOrNull ?: intOrNull ?: longOrNull ?: doubleOrNull ?: error("cannot decode $this")
        }
    }
    else -> error("cannot convert $this to Any")
}
You can feed it the result of
Json.parseToJsonElement(responseText)
There's a solution to use the serialization plugin in there. I just don't bother in scripts. If the project becomes big enough that it needs typesafe json I turn it into a proper Gradle build
a
Nice, I'll stick with JsonElement for now ! And everything works fine :)
j
You can use reflection based libraries like gson or moshi