Upgrading to kotlin 1.9.0 seems to have broken a hacky workaround that I've been using to force chan...
m
Upgrading to kotlin 1.9.0 seems to have broken a hacky workaround that I've been using to force change the project name and version in the output
package.json
of my multiplatform project with
compilations["main"].packageJson
. Not sure if this should be considered a bug and if there are alternatives. More details in thread. edit: turned out to be an issue with gradle caching/serialization so some data was not available in the packageJson closure, see thread.
1
The gradle kts code that breaks :
Copy code
compilations["main"].packageJson {
    customField("name", npmArtifactName)
    customField("version", npmArtifactVersion)
}
Build fails with the following error :
Copy code
Failed to query the value of task ':jsPackageJson' property 'npmResolutionManager'.
> Could not isolate value org.jetbrains.kotlin.gradle.targets.js.npm.KotlinNpmResolutionManager$Parameters_Decorated@be493fd of type KotlinNpmResolutionManager.Parameters
   > Could not serialize value of type Build_gradle...
Setting other custom fields that the normal build would not set still works. It breaks in the same way using :
Copy code
compilations["main"].packageJson {
    name = npmArtifactName
    version = npmArtifactVersion
}
Both were still working with kotlin 1.8.22.
r
along these lines, I discovered that once you query the packageJson's contents, you can no longer add handlers (somewhere in the pipe it caches)
I worked around this by using Gson to serialize the object so I could see what's already registered inside of the handler itself. still hacky, but does the job
(my use case was different, and it was composing multiple passes at mocha overrides)
e
name
works here. Setting a
version
breaks
kotlinNpmInstall
somehow
a
try
version.toString()
never mind, ignore, I misread
m
I'm starting to think this might be a gradle issue, I'm not fluent with it unfortunately, but setting the value with literal values or a locally defined String works
Copy code
customField("name", "newName")
customField("version", "3.0.0")
r
yeah that's suspicious. where were you getting the values from before?
m
It's defined at the top of the build script. Even just doing this :
Copy code
val npmArtifactVersion = version
...
        compilations["main"].packageJson {
            customField("version", npmArtifactVersion)
        }
breaks the build for me
a
what about defining (or redefining) the version inside the
packageJson {}
block?
Copy code
compilations["main"].packageJson {
  val npmArtifactVersion = version
  customField("version", npmArtifactVersion)
}
👀 1
even redefining it should work. It seems dumb though.
Copy code
val npmArtifactVersion = version

kotlin {
  ...
        compilations["main"].packageJson {
            val npmArtifactVersion = npmArtifactVersion
            customField("version", npmArtifactVersion)
        }
}
r
I know the default for the gradle version is frequently "unspecified" which i imagine would cause most node system to throw fits. you may want to check for a valid version and if its not valid replace it with "0.0.0" or something. just throwing out ideas
@Adam S is 100% right though. The error is about capturing the String value, and accessing the version inside the closure it tries to serialize something that its not happy about
m
Yes it works well with this, thank you ! At least I can update my workaround !
I had some issues because this is how the actual value is defined :
Copy code
val npmPublishId = "some-other-id"
val npmArtifactVersion = "$version-$npmPublishId"
and npmPublishId has to be defined in the closure as well, otherwise it still breaks (I don't have to access it outside so it's fine for me)
a
to explain a little bit more about the workings, because this problem comes up a lot, it’s a combination of two things 1. Kotlin scripts are copied into a ‘pretend’ class 2. Java Serialization suuuuucks
All .kts scripts are, basically, copied into a new Kotlin class, that you never see. The class name is based on the file name, though, which is where the
type Build_gradle
comes from. And the contents go into an init block.
Copy code
class Build_gradle: GradleBuildScriptContext {
  init {
    /* .kts script contents goes here*/
  }
}
So when you define your value
val npmPublishId
at the top level, you’ve got a value that basically depends on the outer Build_gradle type. And that type extends from some Gradle scripting context type, which is where all of the Gradle functions come from
Copy code
class Build_gradle: GradleBuildScriptContext {
  init {
    val npmPublishId = "..." // inexorably linked with the Build_gradle class
  }
}
Gradle, in order to try to speed things up, tries to save/load/cache configurations to disk. On paper, Java Serialization is the way to do that. It’s supposed to be able to save any Java object, without any configuration. Except… it doesn’t. It’s way too flakey and conditional and insecure and dangerous and generally horrible. See • Towards Better Serialization • Why We Hate Java Serialization

https://www.youtube.com/watch?v=dOgfWXw9VrI

But Gradle uses it any way, as best it can. So Java Serialization tries to serialize
npmPublishId
, and even though
npmPublishId
is just a string, it depends on
Build_gradle
, which extends from the Gradle scripting context, and that is far too complicated to serialize. And so you end up with lovely errors like
Could not serialize value of type Build_gradle
🙌 1
m
Thanks a lot for the explanation ! It does explain why this kind of issue can happen as a side effect of some change that should, on surface, not have modified my script's behavior.
a
my pleasure!
e
My error instead was:
Copy code
version = "2.0"
This cannot work, the correct one is
Copy code
version = "2.0.0"
So there is no conversion done internally, it has to follow semantic versioning
👍 1