How use kotlinx.serialization decode generics list? - java

i have a json like this:
{"code":200,"msg":"111",data:[{"name":"va","list":[{"code":"11"}]},{"name":"va","list":[{"code":"11"}]}]}
my class like this:
#Serializable
class ServerResponse<T> {
#SerialName(value = "code")
var code = 0
#SerialName(value = "msg")
var msg: String? = null
#SerialName(value = "data")
var data: T? = null
private set
}
#Serializable
data class PluginInfo(
#SerialName(value = "name")
val name: String,
#SerialName(value = "list")
val list: MutableList<PluginConfig>
)
#Serializable
data class PluginConfig(
#SerialName(value = "code")
val code: String
)
when i use JSON.decodeFromString:
val response =
json.decodeFromString<ServerResponse<MutableList<PluginInfo>>>(pluginInfoJson)
this throw exception:
kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 271: Expected quotation mark '"', but had '1' instead at path: $.data[0].

Related

Why getting Gson MalFormatException

I have json string as below i want to convert to object
{"Init":{"MOP":[{"Id":"1","Type":"0","ProtocolVersion":"1.0","MopCode":"*NEXB","TerminalId":"P400Plus-275008565","IP":"10.0.0.0:900","Currency":"EUR"},{"Id":"2","Type":"0","ProtocolVersion":"1.0","MopCode":"*NEXF","TerminalId":"P400Plus-275008565","IP":"10.0.0.0:901","Currency":"EUR"}]}}
My json is valid , i tried on here also i created POJO class on here but i'm getting com.google.gson.stream.MalformedJsonException
Here my code
val receiveString = "{"Init":{"MOP":[{"Id":"1","Type":"0","ProtocolVersion":"1.0","MopCode":"*NEXB","TerminalId":"P400Plus-275008565","IP":"10.0.0.0:900","Currency":"EUR"},{"Id":"2","Type":"0","ProtocolVersion":"1.0","MopCode":"*NEXF","TerminalId":"P400Plus-275008565","IP":"10.0.0.0:901","Currency":"EUR"}]}}"
val root = gson.fromJson(receiveString,TestClass.Root::class.java) //getting error here
Here my POJO class
class Root {
#JsonProperty("Init")
var init: Init? = null
}
class MOP {
#JsonProperty("Id")
var id: String? = null
#JsonProperty("Type")
var type: String? = null
#JsonProperty("ProtocolVersion")
var protocolVersion: String? = null
#JsonProperty("MopCode")
var mopCode: String? = null
#JsonProperty("TerminalId")
var terminalId: String? = null
#JsonProperty("IP")
var ip: String? = null
#JsonProperty("Currency")
var currency: String? = null
}
class Init {
#JsonProperty("MOP")
var mop: List<MOP>? = null
}
What yu can suggest me?
doubleQuote (") in your string must be escaped like "
I solved my problem with adding extra quotes missing parts as below
{"Init":{"MOP":[{"Id":"1","Type":"0","ProtocolVersion":"1.0","MopCode":"*NEXB","TerminalId":"'P400Plus-275008565'","IP":"'192.168.1.15'","Currency":"EUR"},{"Id":"2","Type":"0","ProtocolVersion":"1.0","MopCode":"*NEXF","TerminalId":"'P400Plus-275008565'","IP":"'10.0.0.0:901'","Currency":"EUR"}]}}

How to convert a map to Json string in kotlin?

I have a mutableMap,
val invoiceAdditionalAttribute = mutableMapOf<String, Any?>()
invoiceAdditionalAttribute.put("clinetId",12345)
invoiceAdditionalAttribute.put("clientName", "digital")
invoiceAdditionalAttribute.put("payload", "xyz")
I want to convert it into json string
the output should be,
"{\"clinetId\"=\"12345\", \"clientName\"=\"digital\", \"payload\"=\"xyz\"}"
Currently, I am using Gson library,
val json = gson.toJson(invoiceAdditionalAttribute)
and the output is
{"clinetId":12345,"clientName":"digital","payload":"xyz"}
The right json formatting string is:
{"clinetId":12345,"clientName":"digital","payload":"xyz"}
So this is the right method to get it:
val json = gson.toJson(invoiceAdditionalAttribute)
If you want a string formatted like this:
{"clinetId"=12345, "clientName"="digital", "payload"="xyz"}
just replace : with =:
val json = gson.toJson(invoiceAdditionalAttribute).replace(":", "=")
But if you truly want to have a string with backslashes and clinetId value to be inside quotes:
val invoiceAdditionalAttribute = mutableMapOf<String, Any?>()
invoiceAdditionalAttribute["clinetId"] = 12345.toString()
invoiceAdditionalAttribute["clientName"] = "digital"
invoiceAdditionalAttribute["payload"] = "xyz"
val json = gson.toJson(invoiceAdditionalAttribute)
.replace(":", "=")
.replace("\"", "\\\"")
EDIT:
As pointed int he comments .replace(":", "=") can be fragile if some string values contain a ":" character.
To avoid it I would write a custom extension function on Map<String, Any?>:
fun Map<String, Any?>.toCustomJson(): String = buildString {
append("{")
var isFirst = true
this#toCustomJson.forEach {
it.value?.let { value ->
if (!isFirst) {
append(",")
}
isFirst = false
append("\\\"${it.key}\\\"=\\\"$value\\\"")
}
}
append("}")
}
// Using extension function
val customJson = invoiceAdditionalAttribute.toCustomJson()

Why is #JacksonXmlProperty ignoring parameters in Spring Boot with Kotlin?

So I'm trying to serialize/deserialize RSS feeds using Jackson XML in Kotlin. However, currently it's not doing either properly. When I instantiate the RSS object manually and print out the xml, it seems like it's ignoring the localName and namespace parameters in #JacksonXmlProperty. Here is my code:
#JacksonXmlRootElement(localName="rss")
class RSSFeed(
#JacksonXmlProperty(localName="channel")
var channel: Channel
) {
constructor() : this(Channel())
}
class Channel(
#JacksonXmlProperty(localName="title")
var title: String? = null,
#JacksonXmlCData
#JacksonXmlProperty(localName="description")
var description: String? = null,
#JacksonXmlProperty(localName="image")
var image: RSSImage? = null,
#JacksonXmlProperty(localName = "explicit", namespace="itunes")
var isExplicit: String? = "no",
#JacksonXmlProperty(localName = "pubDate")
var publishDate: String? = null,
#JacksonXmlProperty(localName = "type", namespace="itunes")
var episodeType: String? = null,
#JacksonXmlProperty(localName = "link", namespace="atom")
var atomLink: AtomLink? = null,
#JacksonXmlProperty(localName = "new-feed-url", namespace="itunes")
var newFeedUrl: String? = null
)
Then I just do:
println(XmlMapper().writeValueAsString(RSSFeed(Channel(title = "blah", description = "blah", image = RSSImage(url = "https://someurl.com", link = "somelink"), isExplicit = "yes", atomLink = AtomLink(href="blah.com"), newFeedUrl = "thisisthenewfeed"))))
However, when I print that out it ignores the namespace and localName properties and just uses the variable names. What am I doing wrong?
Xml output: <rss><channel><title>blah</title><description><![CDATA[blah]]></description><image><url>https://someurl.com</url><title/><link><![CDATA[somelink]]></link></image><publishDate/><episodeType/><atomLink href="blah.com"/><newFeedUrl>thisisthenewfeed</newFeedUrl></channel></rss>
edit: it also doesn't seem to be printing the isExplicit property for some reason, not sure what that's about.
Well I figured it out! It turns out this was a Kotlin issue. I just had to do this: val xmlMapper = XmlMapper().registerModule(KotlinModule())
...and make sure that this is in your dependencies (I use gradle):
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
Anyways I hope this helps someone in the future.

JAXB unmarshalling xml list element to single Kotlin object

I have following XML to create nested Kotlin objects but it is not mapping all TimeCycleData element
<TimeCycle>
<Last>
<Date>2001-06-13T01:00:00.000Z</Date>
<TimeCycleData>
<Hours type="F">123</Hours>
</TimeCycleData>
<TimeCycleData>
<Cycles>1234</Cycles>
</TimeCycleData>
<TimeCycleData>
<Land>1234</Land>
</TimeCycleData>
</Last>
</TimeCycle>
and want to map following Kotlin data classes
data class TimeCycle(
#field:XmlElement(name = "Last")
val last: Last? = null
)
data class Last(
#field:XmlElement(name = "Date")
#field:XmlJavaTypeAdapter(value = LocalDateTimeAdapter::class, type = LocalDateTime::class)
val date: LocalDateTime? = null,
#field:XmlElement(name = "TimeCycleData")
val timeCycleData: TimeCycleData? = null
)
data class TimeCycleData(
#field:XmlElement(name = "Hours")
val hours: DurationDetails? = null,
#field:XmlElement(name = "Cycles")
val cycles: Int? = null,
#field:XmlElement(name = "Land")
val land: Int? = null
)
data class DurationDetails(
#field:XmlValue
#field:XmlJavaTypeAdapter(value = DurationAdapter::class, type = Duration::class)
val value: Duration? = null,
#field:XmlAttribute(name = "type")
val type: String = ""
)
when I unmarshal the XML, only the first TimeCycleData with Hours is filled. How can I merge all TimeCycleData into one single object?
UPDATE: corrected submitted xml
I guess
#field:XmlElement(name = "TimeCycleData")
val timeCycleData: TimeCycleData? = null
should be declared in somehow this way
#field:XmlElement(name = "TimeCycleData")
#field:XmlElementWrapper(name = "TimeCycleInfo")
val timeCycleInfo: List<TimeCycleData>? = null
.

Java SimpleXml. How to parse XML, which contains Base64-encoded xml?

I'm writing an Android app which retrieves xml data from the server. For manipulating such data I use Retrofit-SimpleXmlConverter(http://simple.sourceforge.net/home.php, https://github.com/square/retrofit/tree/master/retrofit-converters/simplexml) pipeline. I need to get this list of transactions:
<?xml version="1.0"?>
<Transactions>
<Transaction>
<Transaction_Time>12-01-2018</Transaction_Time>
<Transaction_Bonuses>123.11</Transaction_Bonuses>
<Summ>123.11</Summ>
<Transaction_Type>12</Transaction_Type>
<Dop_Info>BLOB Base64 data with cyrillic symbols</Dop_Info>
</Transaction>
<Transaction>
<Transaction_Time>12-01-2018</Transaction_Time>
<Transaction_Bonuses>123.11</Transaction_Bonuses>
<Summ>123.11</Summ>
<Transaction_Type>12</Transaction_Type>
<Dop_Info>no/Dop_Info>
</Transaction>
My problem is that xml has tag with BASE-64 encoded xml. From encoded xml I need follow data:
<CHECK>
<LINE name="Name of dish", quantity="1", summ="123,5"></LINE>
<LINE name="Name of dish", quantity="1", summ="123,5"></LINE>
<LINE name="Name of dish", quantity="1", summ="123,5"></LINE>
</CHECK>
Data classes:
#Root(name = "Transactions")
data class Transactions #JvmOverloads constructor(
#field:ElementList(inline = true, required = false)
#param:ElementList(inline = true, required = false)
val list: List<Transaction>? = null
) {
#Root(name = "Transaction")
data class Transaction #JvmOverloads constructor(
#field:Element(name = "Transaction_Time")
#param:Element(name = "Transaction_Time")
var transactionTime: String? = null,
#field:Element(name = "Transaction_Bonuses")
#param:Element(name = "Transaction_Bonuses")
val transactionBonuses: Double? = 0.0,
#field:Element(name = "Summ")
#param:Element(name = "Summ")
val summ: Double? = 0.0,
#field:Element(name = "Transaction_Type")
#param:Element(name = "Transaction_Type")
val transactionType: Int? = 0,
#field:Element(name = "Dop_Info")
#param:Element(name = "Dop_Info")
val dopInfo: ByteArray ? = null
){
#Root(name = "CHECK")
data class Check #JvmOverloads constructor(
#field:ElementList(inline = true, required = false)
#param:ElementList(inline = true, required = false)
#field:Path("CHECKDATA/CHECKLINES")
#param:Path("Holders_Cards/Holder_Card/Card")
val list: List<Line>? = null
){
#Root(name = "LINE")
data class Line #JvmOverloads constructor(
#field: Attribute(name = "name", required = false)
#param: Attribute(name = "name", required = false)
val name: String? = null,
#field: Attribute(name = "quantity", required=false)
#param: Attribute(name = "quantity", required=false)
val quantity: Int? = null,
#field: Attribute(name = "summ", required = false)
#param: Attribute(name = "summ", required = false)
val summ: Double? = null
)
}
}
}
At this point I'm confused - how can I correctly serialize the xml in the way I could get instead of blob-data Check model? What are next steps?
P.S For solution I tried to use guide from http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php#callback but it didn't find anything helpful

Categories

Resources