Moshi toJson ignored some of the fields, as compared to Gson library - kotlin

How can I achieve, using Moshi library, the same output (toJson) as Gson library, which would contain all fields from the object's class as well as from all its superclasses?
The real environment is more complex, but lets assume the following classes:
#JsonClass(generateAdapter = true)
open class Entity(
val type: String,
val id: String = "",
val comment: String
)
#JsonClass(generateAdapter = true)
open class Animal(
val name: String,
val description: String
): Entity(
type = "animal",
comment = "living"
)
And assume the following testing code, showing what I tried:
fun testJson() {
val dog = Animal("dog", "friendly")
val moshi = Moshi.Builder().build()
println("moshi as Animal: " + moshi.adapter(Animal::class.java).lenient().serializeNulls().failOnUnknown().toJson(dog))
println("moshi as Entity: " + moshi.adapter(Entity::class.java).lenient().serializeNulls().failOnUnknown().toJson(dog))
val moshiWithPoly = Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Entity::class.java, "type")
.withSubtype(Animal::class.java, "animal"))
.add(KotlinJsonAdapterFactory())
.build()
println("moshi with Poly: " + moshiWithPoly.adapter(Entity::class.java).lenient().serializeNulls().failOnUnknown().toJson(dog))
val gson = Gson()
println("gson: " + gson.toJson(dog))
}
The function generates the following, showing that all the moshi attempts are discarding some of the fields.
moshi as Animal: {"name":"dog","description":"friendly"}
moshi as Entity: {"type":"animal","id":"","comment":"living"}
moshi with Poly: {"type":"animal","name":"dog","description":"friendly"}
gson: {"name":"dog","description":"friendly","type":"animal","id":"","comment":"living"}
How can I achieve same output from moshi as from gson lib?

Related

Jackon JSON Adding deserializer module doesn't work, but annotation on class does

I am trying to implement a custom deserializer and when I try to install it on the ObjectMapper it never gets invoked, but when I use it directly as an annotation on the class, it does. Can someone explain why and how I can actually install it on the object mapper itself?
This is never invoked
val bug = ObjectMapper().registerModule(KotlinModule.Builder().build())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(SimpleModule().addDeserializer(Bug::class.java, BugDeserializer()))
.readValue(bugStream, Bug::class.java)
data class Bug(
#JsonProperty("rptno")
val id: Long,
#JsonProperty("status")
#JsonDeserialize(using = StatusDeserializer::class)
val status: Status,
#JsonProperty("reported_date")
val reportedDate:Instant,
#JsonProperty("updated_date")
val updatedDate: Instant,
// val pillar: String = "",
#JsonProperty("product_id")
#JsonDeserialize(using = ProductDeserializer::class)
val product: Product,
#JsonProperty("assignee")
val assignee: String,
// val serviceRequests: List<Long> = listOf(),
#JsonProperty("subject")
val title: String,
#JsonProperty("bug_type")
val type: String
)
But, this does:
val bug = ObjectMapper().registerModule(KotlinModule.Builder().build())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.readValue(bugStream, Bug::class.java)
#JsonDeserialize(using = BugDeserializer::class)
data class Bug(
#JsonProperty("rptno")
val id: Long,
#JsonProperty("status")
#JsonDeserialize(using = StatusDeserializer::class)
val status: Status,
#JsonProperty("reported_date")
val reportedDate:Instant,
#JsonProperty("updated_date")
val updatedDate: Instant,
// val pillar: String = "",
#JsonProperty("product_id")
#JsonDeserialize(using = ProductDeserializer::class)
val product: Product,
#JsonProperty("assignee")
val assignee: String,
// val serviceRequests: List<Long> = listOf(),
#JsonProperty("subject")
val title: String,
#JsonProperty("bug_type")
val type: String
)
```kotlin

How to use the data type java.util.UUID in Moshi?

I used the data type java.util.UUID in my data models and I have used Moshi for serialization.
But I encountered an error saying that "Platform class java.util.UUID requires explicit JsonAdapter to be registered"
I have gone through the documentation of Moshi for writing custom adapters and I tried to replicate it accordingly.
I wrote an adapter and added it to a moshi instance. But still I encounter the same error .
Adapter
class UUIDAdapter {
#ToJson
fun toJson(value:java.util.UUID):java.util.UUID{
return value
}
#FromJson
fun fromJson(value: String):java.util.UUID{
return java.util.UUID.fromString(value)
}
}
Model
#JsonClass(generateAdapter = true)
data class AddWorkspace(
#Json(name = "user_id")
val user_id: UUID,
#Json(name = "name")
val name:String,
#Json(name = "descp")
val descp:String,
#Json(name = "created_at")
val created_at:String
)
Moshi
private val moshi = Moshi.Builder()
.add(UUIDAdapter())
.build()
private val retrofitBuilder = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(MoshiConverterFactory.create(moshi))
What else am I missing so that I can use the adapter correctly ?
Edit : Well, the methods toJson and fromJson are not being called in the first place. I tried to implement the JsonAdapter class and override the methods toJson and fromJson, but the issue I face here is that in case of the method toJson, I need to send a java.util.UUID value, but the JsonWriter cannot write a value of such data type.
Please suggest me a way to work my way through this. Thanks :)
UUID adapter
class UUIDAdapter:JsonAdapter<UUID>(){
#FromJson
override fun fromJson(reader: JsonReader): UUID? {
return UUID.fromString(reader.readJsonValue().toString())
}
#ToJson
override fun toJson(writer: JsonWriter, value: UUID?) {
writer.jsonValue(value)
}
}
You're so close. Change the #ToJson to this:
#ToJson
fun toJson(value:java.util.UUID): String {
return value.toString()
}
as Jesse described just use:
class UuidAdapter {
#FromJson
fun fromJson(uuid: String): UUID = UUID.fromString(uuid)
#ToJson
fun toJson(value: UUID): String = value.toString()
}

How to parse LinkedHashMap in moshi (kotlin)

I am trying to create a JSON adapter for the following json
{
"message": {
"affenpinscher": [],
"african": [],
"airedale": [],
"akita": [],
"appenzeller": [],
"australian": [
"shepherd"
]
},
"status": "success"
}
I have tried the following
#JsonClass(generateAdapter = true)
data class BreedList(
val message: HashMap<String,List<String>> = HashMap<String,List<String>>()
)
and
#JsonClass(generateAdapter = true)
data class BreedList(
val message: Breed
)
#JsonClass(generateAdapter = true)
data class Breed(
val breed: List<String>
)
But both scenarios give me the errors, is there a way to parse the following object, I need the key as well as the list from the response
There is no need to create a custom adapter.
To parse the JSON you posted:
data class Base (
#field:Json(name = "message")
val message : Message,
#field:Json(name = "status")
val status : String
)
data class Message (
#field:Json(name = "affenpinscher")
val affenpinscher : List<String>,
#field:Json(name = "african")
val african : List<String>,
#field:Json(name = "airedale")
val airedale : List<String>,
#field:Json(name = "akita")
val akita : List<String>,
#field:Json(name = "appenzeller")
val appenzeller : List<String>,
#field:Json(name = "australian")
val australian : List<String>
)
Note: instead of String you can use whatever data type you need or create custom classes like Message.

JsonProperty names are not being respected on Jackson

I would like to have custom names when writing my object but it's not printing what I have defined in annotation #JsonProperty:
data class Banking(
#JsonProperty("personita_id")
val clientId: String?,
#JsonProperty("contita_id")
val accountId: String?
)
val mapper = ObjectMapper()
val xpto = mapper.writeValueAsString(Banking("mammamia", "miaccuenta"))
xpto prints:
{"clientId": "mammamia", "accountId": "miaccuenta"}
What is missing in my code?
You can register the KotlinModule on the ObjectMapper from jackson-module-kotlin
val mapper = ObjectMapper().registerModule(KotlinModule())
or depending on the used version
val mapper = ObjectMapper().registerKotlinModule();

Create customise Data class model using Kotlin Koin

I'm new to Kotlin & understanding the concepts as I move. Stuck in creating one type of Data class model where the response json structure as shown below
data class SPLPlayer(
#field:Json(name ="id") val playerId: String?,
val type: String?,
#field:Json(name ="value") val currentValue: String?,
#field:Json(name ="Confirm_XI") val isIn_XI: Boolean = false,
#field:Json(name ="Matches") val totalMatchs: String?,
#field:Json(name ="Position") val position: String?,
#field:Json(name ="Skill") val skill: String?,
#field:Json(name ="skill_name") val skillName: String?,
val teamId: String?,
val name: String?, // other keys to refer Name_Full, short_name
#field:Json(name ="Bowling") val bowler: SPLBowler? = null,
#field:Json(name ="Batting") val batsmen: SPLBatsmen? = null
)
data class SPLTeamInfo (
**How to parse the Team object which is dictionary**
)
Thanks & appreciate to every reader. Looking forward for the solution.
You should be able to use your own deserializer by adding annotation to a setter #set:JsonDeserialize() and passing your own deserializer implementation.
along the lines of:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.JsonDeserializer
.. rest of imports
// for a given simplified json string
val json: String = """{"teams":{"1":{"name":"foo"},"2":{"name":"bar"}}}"""
class MyDeserializer : JsonDeserializer<List<Team>> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): List<Team>? {
// iterate over each json element and return list of parsed teams
}
}
data class JsonResp (
#set:JsonDeserialize(using = MyDeserializer::class)
var teams: List<Team>
)
data class Team (
var id: String, // this is going to be a team key
var name: String
)
Tried GitHub search with query #set:JsonDeserialize and it shows thousands of examples.