org.jetbrains.kotlin.gradle.targets.js.npm.PackageJsonTypeAdapter.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.targets.js.npm
import com.google.gson.*
import com.google.gson.annotations.SerializedName
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import java.lang.reflect.Field
// Necessary to get rid of all fields with null value (private, workspace etc)
// But we need to leave customFields because it is user's null value and it is ok
// Here we remove all null-valuable fields, read customFields, add them to jsonObject as elements and remove customFields field
// It helps to not get such json
// { name: "foo", private: null, customFields: { customField1: null }, customField1: null }
// but just
// { name: "foo", customField1: "foo" }
class PackageJsonTypeAdapter : TypeAdapterFactory {
override fun create(gson: Gson, type: TypeToken): TypeAdapter? {
if (type.rawType != PackageJson::class.java) return null
fun Field.serializedName() = declaredAnnotations
.filterIsInstance()
.firstOrNull()?.value ?: name
val declaredFields = type.rawType.declaredFields
val customFieldsField = declaredFields
.single { it.name == PackageJson::customFields.name }
return object : TypeAdapter() {
private val delegateAdapter = gson.getDelegateAdapter(this@PackageJsonTypeAdapter, type)
private val elementAdapter = gson.getAdapter(JsonElement::class.java)
override fun write(writer: JsonWriter, value: T?) {
val jsonObject = delegateAdapter.toJsonTree(value).asJsonObject
customFieldsField.isAccessible = true
val customFields = customFieldsField.get(value) as Map<*, *>
customFields
.forEach { (key, value) ->
val valueElement = gson.toJsonTree(value)
key as String
jsonObject.add(key, valueElement)
}
declaredFields
.map { it.serializedName() }
.filter { jsonObject.get(it) is JsonNull }
.forEach { jsonObject.remove(it) }
jsonObject.remove(customFieldsField.serializedName())
val originalSerializeNulls = writer.serializeNulls
writer.serializeNulls = true
elementAdapter.write(writer, jsonObject)
writer.serializeNulls = originalSerializeNulls
}
override fun read(reader: JsonReader): T {
return delegateAdapter.read(reader)
}
}
}
}