My XML:
<body>
<type>authorizationStatus</type>
<data>
<AuthorizationStatusMessage>
<id>12345679</id>
<email>abc</email>
</AuthorizationStatusMessage>
</data>
</body>
I want to unmarshal this XML to a POJO like that:
public class XMPPMessage {
private String type;
private String data;
}
Jackson unmarshal gives me a HashMap:
{AuthorizationStatusMessage={id_colaborador=12345679, email=rhochman#atech.com}}
But I want keep the data inner XML as a String like that:
<AuthorizationStatusMessage><id>12345679</id><email>abc</email></AuthorizationStatusMessage>
How can I keep the inner XML as a String??
I can see two options.
If you can modify your XML schema, you might want to leverage CDATA section (https://en.wikipedia.org/wiki/CDATA) to keep your <data> contents as String.
You can implement a custom Jackson deserializer to extract type and data only. There are plenty of good references on the web (e.g. http://www.baeldung.com/jackson-deserialization).
I got it someway... I found a library named Conversion Box to convert HashMap to XML.
I create custom Deserializer for storing inner XML as String, example on Kotlin:
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer
import com.fasterxml.jackson.databind.node.ObjectNode
import com.fasterxml.jackson.dataformat.xml.XmlMapper
object XmlInnerDeserializer : StdScalarDeserializer<String>(String::class.java) {
override fun deserialize(jp: JsonParser?, context: DeserializationContext?): String {
val node = jp!!.codec.readTree<ObjectNode>(jp)
val xmlMapper: ObjectMapper = XmlMapper()
val xml = xmlMapper.writeValueAsString(node)
return xml.toString()
}
}
How use it:
#JacksonXmlRootElement(localName = "body")
#JsonIgnoreProperties(ignoreUnknown = true)
class XMPPMessage (
#JsonDeserialize(using = XmlInnerDeserializer::class)
#JacksonXmlProperty(localName = "data")
val data: String
}
Field data contains "<ObjectNode><AuthorizationStatusMessage>... </AuthorizationStatusMessage></ObjectNode>" string.
Related
I'm using jackson csv to parse a csv as pojo
ID,requestId,requestSource,documentIds,trackingIds
documentIds,123456,CLAIMS,123456;223456,
->
#Data
#NoArgsConstructor
#JacksonXmlRootElement(localName = "triggerDocumentExport",namespace = Connection.NAMESPACE_CAS)
public class TriggerDocumentExport {
private Wrapper in;
public TriggerDocumentExport(Wrapper in){this.in = in;}
#Data
public static class Wrapper{
private String requestId,
requestSource;
private List<String> documentIds,
trackingIds;
}
}
I want documentIds to be parsed as a List<String>, with default ArrayElementSeparator(which is ;)
but it keeps parsing it as a single string "123456;223456"
without DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, I got an exception
with the configuration, I got a List with only one element "123456;223456"
If I don't make mistake, should jackson csv support semicolon-seperated list by default?Or there's something I've misunderstood.
My goal is to create a valid XML request string using a Plain Old Java Object. The problem I am having is that I cannot create multiple wrapping elements, nor can I assign namespaces properly. The code I have right now is:
package test_ground;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.util.List;
#JacksonXmlRootElement(localName = "Envelope", namespace =
"http://schemas.xmlsoap.org/soap/envelope/" )
public class RateReqModel {
#JacksonXmlProperty(namespace = "http://schemas.xmlsoap.org/soap/envelope/")
private String Header;
#JacksonXmlElementWrapper(localName = "GetCurrencyRates", namespace = "http://tempuri.org/")
private List<String> RateDate;
public RateReqModel(List<String> RateDate){
this.RateDate = RateDate;
}
}
What I am getting with the above script:
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Header/>
<wstxns1:GetCurrencyRates xmlns:wstxns1="http://tempuri.org/">
<RateDate xmlns="">2021-03-29</RateDate>
</wstxns1:GetCurrencyRates>
</Envelope>
What I need:
<ns1:Envelope xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://tempuri.org/">
<ns1:Header/>
<ns1:Body>
<ns2:GetCurrencyRates>
<ns2:RateDate>2021-03-29</ns2:RateDate>
</ns2:GetCurrencyRates>
</ns1:Body>
</ns1:Envelope>
As you can see, the desired XML structure has 2 namespaces and double wrapping around the RateDate element, which is exactly what I seek.
Is it possible to "intercept" the unmarshalling process of JAXB?
I have an xml reponse that partially should be converted to a different java fields structure:
<xml>
<X_FIELD1></X_FIELD1>
<X_FIELD2></X_FIELD2>
...
<X_FIELD11></X_FIELD11>
</xml>
In my java class, I'd prefer to unmarshal this to a List<String>, instead of 11 String fields.
public class XmlResponse {
private String X_FIELD1;
private String X_FIELD2;
//...
private String X_FIELD11;
// private List<String> xFields;
}
But is that possible?
You should use a custom xml adapter
http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/adapters/XmlJavaTypeAdapter.html
http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/adapters/XmlAdapter.html
apply it on the class level and implement the adapter.
I'd like to have different name for my element when it's serialized to XML (for example "fooXml") and different for JSON (for example "fooJson"). Is it possible?
I'm using XML annotations like:
#XmlElements({
#XmlElement(type = Foo.class, name = "fooXml"),
})
private SortedSet<Foo> fooSet;
I've tried already #JsonProperty, with without any luck.
I've also tried exporting it to getter method, like:
#XmlElement(type = Foo.class, name = "fooXml")
#JsonProperty(value = "fooJson")
public List<Foo> getFooList() {
return new ArrayList<>(fooSet);
}
But it's always ignoring JSON annotations and serializing to XML form (fooXml name).
How shall I do it?
edit: I'm using Jersey-json.
Alright, I had a need for this same functionality and found a solution that works for this:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
#JsonProperty("MyJsonName")
#JacksonXmlProperty(localName = "MyXmlName")
private MyProperty myProperty;
Works for me, and myProperty will be in the 'MyJsonName' field in Json and the 'MyXmlName' in XML.
Using Jackson with the jackson-dataformat-xml module, I am able to serialize POJO to both JSON and XML. There are a few fields (xml attributes) in my object that should only be serialized to XML but not JSON. If I apply the #JsonIgnore annotation, the field is completely ignored even with #JsonXMLProperty.
How can I ignore fields only in JSON but not XML?
You should use Mix-in feature. For example, assume that your POJO class looks like this:
class Pojo {
private long id;
private String xmlOnlyProperty;
// getters, setters
}
Now, you can define annotations for each property using Mix-in interfaces. For JSON it looks like below:
interface PojoJsonMixIn {
#JsonIgnore
String getXmlOnlyProperty();
}
For XML it looks like below:
interface PojoXmlMixIn {
#JacksonXmlProperty(isAttribute = true)
String getXmlOnlyProperty();
}
Finally, example how to use Mix-in feature:
Pojo pojo = new Pojo();
pojo.setId(12);
pojo.setXmlOnlyProperty("XML attribute");
System.out.println("JSON");
ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(Pojo.class, PojoJsonMixIn.class);
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(pojo));
System.out.println("XML");
ObjectMapper xmlMapper = new XmlMapper();
xmlMapper.addMixInAnnotations(Pojo.class, PojoXmlMixIn.class);
System.out.println(xmlMapper.writeValueAsString(pojo));
Above program prints:
JSON
{
"id" : 12
}
XML
<Pojo xmlns="" xmlOnlyProperty="XML attribute"><id>12</id></Pojo>