-
Notifications
You must be signed in to change notification settings - Fork 621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to convert map into json string #746
Comments
Use |
@sandwwraith It would be great to have such functionality with raw map. Can it be submitted as a feature request? |
@gabin8 No it won't. Could you pleas give a use-case for that? |
sometime we need to provide some scalability. we need to dynamically put data into jsonobject. but the interface dont have a method to do it. At present, I implemented it by converting jsonobject.content to mutablemap, and then I encountered many problems in IOS platform. I don't know how to solve them.i am a android developer, this way can work in android. |
You can use |
use case: body = mapOf(
"login" to email,
"password" to password,
"tcConsent" to true,
"gdprMarketingConsent" to true
)
) Actual behavior: body = JsonObject(
mapOf(
"login" to JsonPrimitive(email),
"password" to JsonPrimitive(password),
"tcConsent" to JsonPrimitive(true),
"gdprMarketingConsent" to JsonPrimitive(true)
)
) |
One use case I came across is that I'm using Firestore as a DB, which returns values as The only solution left for this is to convert the Map to a JSON string and then use the |
As another use case: Flutter's platform channels uses a HashMap |
there is no json available in kotlinx import kotlinx.serialization.json.* |
@sreexamus are you talking about |
I am evaluating if importing to my project or not. |
Could you please show an example ow |
case 1:
case 2:
When I migrated to Moshi from Gson, I didn't need to modify data. |
I have also a problem finding the right way to de/serialize a data class with a field of I hope it's OK to add this example here.
(this is a simple example. Our |
Any news for this issue? |
Hi @sandwwraith We have an AWS lambda that passes its input as a LinkedHashMap where the key is a string and the E.g. public APIGatewayProxyResponseEvent handleRequest(LinkedHashMap request, Context context) Currently, we use gson to create a JsonElement so we can parse the input request and then parse it as a String to convert it to an object. JsonElement requestJson = gson.toJsonTree(request, LinkedHashMap.class); I couldn't find anything similar in Kotlin Serialization, is it possible to achieve the same thing? |
@markchristopherng Simply convert |
@sandwwraith Thanks for that, it would be good if there was some type of convenience method because if developers get used to using this on Gson or whatever other framework they use for JSON parsing then they would expect it for new libraries like this. It would be good to provide a migration guide from Gson -> Kotlin Serialization Could help with adoption and also undercover whether Kotlin Serialization is harder or easier to use than these existing frameworks. I know that Kotlin Serialization provides more than just JSON parsing but having good documentation & migration guides is key to adoption. |
I'm used to using like this.
|
+1 for this -- its really common for libraries to treat JSON data as a |
Even I just use this then deserialize JSONObject.toString() with kotlinx. |
If anyone is looking for generic @Serializable
data class Generic<T>(
val data: T? = null,
val extensions: Map<String, @Serializable(with = AnySerializer::class) Any>? = null
)
object AnySerializer : KSerializer<Any> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Any")
override fun serialize(encoder: Encoder, value: Any) {
val jsonEncoder = encoder as JsonEncoder
val jsonElement = serializeAny(value)
jsonEncoder.encodeJsonElement(jsonElement)
}
private fun serializeAny(value: Any?): JsonElement = when (value) {
is Map<*, *> -> {
val mapContents = value.entries.associate { mapEntry ->
mapEntry.key.toString() to serializeAny(mapEntry.value)
}
JsonObject(mapContents)
}
is List<*> -> {
val arrayContents = value.map { listEntry -> serializeAny(listEntry) }
JsonArray(arrayContents)
}
is Number -> JsonPrimitive(value)
is Boolean -> JsonPrimitive(value)
else -> JsonPrimitive(value.toString())
}
override fun deserialize(decoder: Decoder): Any {
val jsonDecoder = decoder as JsonDecoder
val element = jsonDecoder.decodeJsonElement()
return deserializeJsonElement(element)
}
private fun deserializeJsonElement(element: JsonElement): Any = when (element) {
is JsonObject -> {
element.mapValues { deserializeJsonElement(it.value) }
}
is JsonArray -> {
element.map { deserializeJsonElement(it) }
}
is JsonPrimitive -> element.toString()
}
} *obviously it will only work with primitives and maps/arrays of primitives - if you attempt to serialize/deserialize complex objects it won't work. Guess you could use reflections to iterate over all fields but wouldn't that be overkill? |
Used kotlinx.serialization although it makes it unnecessarily difficult to convert Converting Map<String, Any> to JSON. Used this solution: Kotlin/kotlinx.serialization#746 (comment)
I ended up using reflections.... updated private fun serializeAny(value: Any?): JsonElement = when (value) {
null -> JsonNull
is Map<*, *> -> {
val mapContents = value.entries.associate { mapEntry ->
mapEntry.key.toString() to serializeAny(mapEntry.value)
}
JsonObject(mapContents)
}
is List<*> -> {
val arrayContents = value.map { listEntry -> serializeAny(listEntry) }
JsonArray(arrayContents)
}
is Number -> JsonPrimitive(value)
is Boolean -> JsonPrimitive(value)
is String -> JsonPrimitive(value)
else -> {
val contents = value::class.memberProperties.associate { property ->
property.name to serializeAny(property.getter.call(value))
}
JsonObject(contents)
}
} |
Taking @WontakKim's solution a step further, this appears to work nicely (although could come with caveats I don't yet understand) fun Any?.toJsonElement(): JsonElement = when (this) {
is Number -> JsonPrimitive(this)
is Boolean -> JsonPrimitive(this)
is String -> JsonPrimitive(this)
is Array<*> -> this.toJsonArray()
is List<*> -> this.toJsonArray()
is Map<*, *> -> this.toJsonObject()
is JsonElement -> this
else -> JsonNull
}
fun Array<*>.toJsonArray() = JsonArray(map { it.toJsonElement() })
fun Iterable<*>.toJsonArray() = JsonArray(map { it.toJsonElement() })
fun Map<*, *>.toJsonObject() = JsonObject(mapKeys { it.key.toString() }.mapValues { it.value.toJsonElement() })
fun Json.encodeToString(vararg pairs: Pair<*, *>) = encodeToString(pairs.toMap().toJsonElement()) usage val json = Json {}
val str = json.encodeToString(
"key1" to "string value",
"key2" to 123,
"key3" to true,
)
println(str) // {"key1":"string value","key2":123,"key3":true} |
I'm using the
|
After two days of research, combine @neumannk 's code, I used the following scheme to complete the serialization of any class, although it uses Kotlin reflection. Because I hope he can complete the serialization of Map, List and some Data classes import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.*
import kotlinx.serialization.serializer
import kotlin.reflect.full.createType
fun Any?.toJsonElement(): JsonElement = when (this) {
null -> JsonNull
is JsonElement -> this
is Number -> JsonPrimitive(this)
is Boolean -> JsonPrimitive(this)
is String -> JsonPrimitive(this)
is Array<*> -> JsonArray(map { it.toJsonElement() })
is List<*> -> JsonArray(map { it.toJsonElement() })
is Map<*, *> -> JsonObject(map { it.key.toString() to it.value.toJsonElement() }.toMap())
else -> Json.encodeToJsonElement(serializer(this::class.createType()), this)
}
fun Any?.toJsonString(): String = Json.encodeToString(this.toJsonElement()) |
var Results:MutableMap<String,@Serializable(with = AnySerializer::class)Any> =LinkedHashMap()
Results["extensions"]=mapOf(
"a" to 3,
"b" to 7,
"c" to listOf<Int>(1,2,3),
"d" to mapOf(
"e" to 12,
"f" to listOf<String>("")
)
)
val s2=Json.encodeToString(Results)
println(s2) it reports exception: |
I'm a bit puzzled - I got a similar exception
Where I try to save The test runs on JVM the exception happens in the Android Runtime. Does anyone have an explanation? |
@emartynov Then it is a separate issue, you can create new ticket with full stacktrace & reproducer |
@sandwwraith how do you know that it is a separate issue? Can you light a bit of detail what is the cause? Actually, I'm wrong I don't see exception that I mentioned in this ticket. Also already forgot how did I land here. Please ignore 👆🏼. |
I don't understand why this issue was closed as completed as this issue wasn't fixed yet. Yes there are workarounds here but they could easily be included in kotlinx.serialization instead. |
This
|
I'm tryed, this method below could solute this issue in kotlin code: @POST("app/xxx") suspend fun appXxxRequest(@Body request: |
example
val params = mutableMapOf<String, Any>()
params.put("long", 100L)
params.put("int", 10)
params.put("string", "haha")
params.put("map", mutableMapOf("longg" to 10L, "stringg" to "ok"))
LogUtil.d("test", json.stringify(params))
The text was updated successfully, but these errors were encountered: