XML unmarshal to Object in Java/Kotlin - java

I want to change a xml string to a object but it seems like keeps throwing error to me and I'm not sure how to use those #XmlRootElement stuff
Just view/reply it as JAVA also can although written in kotlin
Here it's the XML string
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx0b6dc231d20b379f1]]></appid>
<mch_id><![CDATA[1508319851]]></mch_id>
<nonce_str><![CDATA[mqy4nB6xGoyC1QPY]]></nonce_str>
<sign><![CDATA[2D9A3195E196F679D3916C5DC74754B4]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<prepay_id><![CDATA[wx2116190646297891sfae86747980208850875]]></prepay_id>
<trade_type><![CDATA[JSAPI]]></trade_type>
</xml>
Here it's my data class
#XmlRootElement
data class WxPayResult(
val return_code: String = "",
val return_msg: String = "",
//return_code as SUCCESS will only return the following params
val appid: String? = null,
val mch_id: String? = null,
val device_info: String? = null,
val nonce_str: String? = null,
val sign: String? = null,
val result_code: String? = null,
val err_code: String? = null,
val err_code_des: String? = null,
//return_code and result_code both as success will only return the following params
val trade_type: String? = null,
val prepay_id: Int? = null,
val code_url: String? = null
)
Here it's my code, "xmlreturn" is the xml string
val jaxbContext = JAXBContext.newInstance(WxPayResult::class.java)
val unmarshaller = jaxbContext.createUnmarshaller()
val reader = StringReader(xmlreturn)
val person = unmarshaller.unmarshal(reader)
Here it's the error
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"xml"). Expected elements are <{}wxPayResult>
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:741)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:262)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:257)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:124)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1149)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:574)
I know probably i need to add something into the data class but i don know what to add. Thanks in advance.

Your root element's name differs from your xml root element, which also the message suggests. It expects wxPayResult, but you give it a xml.
Either deliver an XML with wxPayResult as root element or supply the name to XMLRootElement, e.g.
#XmlRootElement(name = "xml")

Related

How to reuse a custom object serializer for a list of objects?

I've written a custom "student" serializer and want to reused it for a list of student. Do I need to write a new Serializer for the Type List<Student> or can I reuse StudentSerializer?
For example:
class Student(
var id: Long? = null,
var name: String? = null,
var courses: MutableList<Courses> = mutableListOf()
)
class Course(
var id: Long? = null,
var name: String? = null,
var students: MutableList<Student> = mutableListOf()
)
class StudentSerializer : JsonSerializer<Student>() {
override fun serialize(student: Student?, gen: JsonGenerator, serializers: SerializerProvider?) {
gen.writeStartObject()
// ...
gen.writeEndObject()
}
}
How can I reuse this Serializer for this scenario?
Do I need to write a new Serializer for the Type List or can
I reuse StudentSerializer
You can reuse the StudentSerializer serializer already defined: in your case you can annotate your studentsfield in the Course class with the JsonSerialize annotation with contentUsing directive where contentusing indicates the serializer class to use for serializing contents (elements of a Collection/array, values of Maps) of one annotated property:
class Course(
var id: Long? = null,
var name: String? = null,
#JsonSerialize(contentUsing= StudentSerializer::class)
var students: MutableList<Student> = mutableListOf()
)

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"}]}}

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