Skip to content

Commit

Permalink
Don't expose JsonElement
Browse files Browse the repository at this point in the history
  • Loading branch information
BraisGabin committed Feb 13, 2024
1 parent b4c23be commit 3b51d8c
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 28 deletions.
7 changes: 3 additions & 4 deletions src/commonMain/kotlin/io/github/detekt/sarif4k/Merging.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

package io.github.detekt.sarif4k

import kotlinx.serialization.json.JsonArray
import kotlin.jvm.JvmName

fun SarifSchema210.merge(other: SarifSchema210): SarifSchema210 {
Expand Down Expand Up @@ -32,12 +31,12 @@ fun SarifSchema210.merge(other: SarifSchema210): SarifSchema210 {

fun PropertyBag.merge(other: PropertyBag): PropertyBag {
var merge = this + other
val aTags = this["tags"] as? JsonArray
val bTags = other["tags"] as? JsonArray
val aTags = this["tags"] as? Collection<*>
val bTags = other["tags"] as? Collection<*>

if (aTags != null && bTags != null) {
merge = merge.toMutableMap().also {
it["tags"] = JsonArray((aTags + bTags).distinct())
it["tags"] = (aTags + bTags).distinct()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,24 +346,22 @@ data class Address (
*/
@Serializable(with = PropertyBagSerializer::class)
@JvmInline
value class PropertyBag(private val value: JsonObject) : Map<String, JsonElement> by value {
constructor(value: Map<String, JsonElement>) : this(JsonObject(value))
value class PropertyBag(private val value: Map<String, Any?>) : Map<String, Any?> by value {
/**
* A set of distinct strings that provide additional information.
*/
val tags: List<String>? get() = (value["tags"] as Collection<*>?)?.map { it as String }
}

/**
* A set of distinct strings that provide additional information.
*/
val PropertyBag.tags: List<String>? get() = this["tags"]?.let { Json.decodeFromJsonElement(it) }

object PropertyBagSerializer : KSerializer<PropertyBag> {
override val descriptor: SerialDescriptor = JsonObject.serializer().descriptor

override fun deserialize(decoder: Decoder): PropertyBag {
return PropertyBag(decoder.decodeSerializableValue(JsonObject.serializer()))
return PropertyBag(decoder.decodeSerializableValue(JsonObject.serializer()).toMap())
}

override fun serialize(encoder: Encoder, value: PropertyBag) {
encoder.encodeSerializableValue(JsonObject.serializer(), JsonObject(value))
encoder.encodeSerializableValue(JsonObject.serializer(), value.toJsonElement())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package io.github.detekt.sarif4k
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive

object SarifSerializer {
private val json = Json {
Expand All @@ -15,4 +20,54 @@ object SarifSerializer {
fun toJson(sarif: SarifSchema210): String = json.encodeToString(sarif)

fun fromJson(json: String): SarifSchema210 = Json.decodeFromString(json)
}
}

// Extracted from https://github.com/Kotlin/kotlinx.serialization/issues/296#issuecomment-1859572541
private fun Any?.toJsonElement(): JsonElement = when (this) {
null -> JsonNull
is JsonElement -> this
is Map<*, *> -> toJsonElement()
is Collection<*> -> toJsonElement()
is ByteArray -> this.toList().toJsonElement()
is CharArray -> this.toList().toJsonElement()
is ShortArray -> this.toList().toJsonElement()
is IntArray -> this.toList().toJsonElement()
is LongArray -> this.toList().toJsonElement()
is FloatArray -> this.toList().toJsonElement()
is DoubleArray -> this.toList().toJsonElement()
is BooleanArray -> this.toList().toJsonElement()
is Array<*> -> toJsonElement()
is Boolean -> JsonPrimitive(this)
is Number -> JsonPrimitive(this)
is String -> JsonPrimitive(this)
is Enum<*> -> JsonPrimitive(this.toString())
else -> error("Can't serialize unknown type: $this")
}

internal fun Map<*, *>.toJsonElement(): JsonObject {
return JsonObject(this.map { (key, value) -> key as String to value.toJsonElement() }.toMap())
}

private fun Collection<*>.toJsonElement(): JsonArray {
return JsonArray(this.map { it.toJsonElement() })
}

private fun Array<*>.toJsonElement(): JsonArray {
return JsonArray(this.map { it.toJsonElement() })
}

private fun JsonElement.toMap(): Any? {
return when (this) {
JsonNull -> null
is JsonArray -> this.map { it.toMap() }
is JsonObject -> this.toMap()
is JsonPrimitive -> if (isString) content else {
content.toBooleanStrictOrNull() ?: content.toDoubleOrNull() ?: content.toLongOrNull()
?: error("Unknown primitive type")
}
}
}

internal fun JsonObject.toMap(): Map<String, Any?> {
return this.map { (key, value) -> key to value.toMap() }.toMap()
}
19 changes: 5 additions & 14 deletions src/jvmTest/kotlin/io/github/detekt/sarif4k/SarifSerializerTest.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
package io.github.detekt.sarif4k

import kotlinx.serialization.json.add
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonArray
import kotlinx.serialization.json.putJsonObject
import org.junit.jupiter.api.Test
import java.io.File
import kotlin.test.assertEquals
Expand Down Expand Up @@ -50,14 +45,10 @@ class SarifSerializerTest {
)
),
properties = PropertyBag(
buildJsonObject {
putJsonArray("tags") {
add("tag")
}
putJsonObject("foo") {
put("bar", "buz")
}
}
mapOf(
"tags" to listOf("tag"),
"foo" to mapOf("bar" to "buz")
)
),
)
)
Expand Down Expand Up @@ -106,4 +97,4 @@ class SarifSerializerTest {
)
assertEquals(sarifSchema210, actual)
}
}
}

0 comments on commit 3b51d8c

Please sign in to comment.