Jackson XML - Deserialize from specific node - java

I'm new to Jackson XML and I would like to do the following:
Here is the XML I'd like to convert to Java DTO:
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<cotacaoTaxaCambioResponse
xmlns="http://tempuri.org/">
<cotacaoTaxaCambioResult
xmlns:a="http://schemas.datacontract.org/2004/07/Exchange"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:TaxasCambio>
<a:CotacaoTaxaCambio>
<a:CLIENTEC>0</a:CLIENTEC>
<a:CLIENTEV>0</a:CLIENTEV>
<a:COMERCIALC>0</a:COMERCIALC>
<a:COMERCIALV>30</a:COMERCIALV>
<a:DATA>2021-12-15T00:00:00</a:DATA>
<a:HORARIO>1027</a:HORARIO>
<a:MOEDA>978</a:MOEDA>
<a:PARIDADEC>1</a:PARIDADEC>
<a:PARIDADEV>1</a:PARIDADEV>
<a:TURISMOC>0</a:TURISMOC>
<a:TURISMOV>30</a:TURISMOV>
</a:CotacaoTaxaCambio>
</a:TaxasCambio>
<a:serviceStatus>
<a:CODRETORNO>0</a:CODRETORNO>
<a:MENSAGEM>Sucesso</a:MENSAGEM>
<a:MENSAGEMEN>OK</a:MENSAGEMEN>
<a:NRREFERENCE>0</a:NRREFERENCE>
</a:serviceStatus>
</cotacaoTaxaCambioResult>
</cotacaoTaxaCambioResponse>
</s:Body>
</s:Envelope>
Info I need is attributes of a:CotacaoTaxaCambio node.
Created this DTO
#JacksonXmlRootElement(localName = "a:CotacaoTaxaCambio")
public class CotacaoResDTO {
#JacksonXmlProperty(localName = "a:DATA")
private String data;
#JacksonXmlProperty(localName = "a:HORARIO")
private String hora;
#JacksonXmlProperty(localName = "a:MOEDA")
private String codMoeda;
#JacksonXmlProperty(localName = "a:COMERCIALV")
private Double valorComercial;
#JacksonXmlProperty(localName = "a:TURISMOV")
private Double valorTurismo;
}
If I set this subset as input, it does work:
<a:CotacaoTaxaCambio>
<a:CLIENTEC>0</a:CLIENTEC>
<a:CLIENTEV>0</a:CLIENTEV>
<a:COMERCIALC>0</a:COMERCIALC>
<a:COMERCIALV>30</a:COMERCIALV>
<a:DATA>2021-12-15T00:00:00</a:DATA>
<a:HORARIO>1027</a:HORARIO>
<a:MOEDA>978</a:MOEDA>
<a:PARIDADEC>1</a:PARIDADEC>
<a:PARIDADEV>1</a:PARIDADEV>
<a:TURISMOC>0</a:TURISMOC>
<a:TURISMOV>30</a:TURISMOV>
</a:CotacaoTaxaCambio>
But it doesn't deserialize if I set full xml as input.
Is there any configuration or anotation that I can use to archieve this?
Thanks in advance,

Unfortunately at the moment the jackson library does not support directly the SOAP protocol, but you can read the part you are interested with the XMLStreamReader class directly pointing the involved tag:
XMLInputFactory f = XMLInputFactory.newFactory();
XMLStreamReader sr = f.createXMLStreamReader(new FileInputStream(xml));
XmlMapper mapper = new XmlMapper();
sr.nextTag();
while (!sr.getLocalName().equals("CotacaoTaxaCambio")) {
sr.nextTag();
}
CotacaoResDTO value = mapper.readValue(sr, CotacaoResDTO.class);
sr.close();
You have to modify also your CotacaoResDTO class ignoring the unknown properties :
#JsonIgnoreProperties(ignoreUnknown = true)
public class CotacaoResDTO {
#JacksonXmlProperty(localName = "DATA")
private String data;
#JacksonXmlProperty(localName = "HORARIO")
private String hora;
#JacksonXmlProperty(localName = "MOEDA")
private String codMoeda;
#JacksonXmlProperty(localName = "COMERCIALV")
private Double valorComercial;
#JacksonXmlProperty(localName = "TURISMOV")
private Double valorTurismo;
}

Related

Trying to parse XML with attribute and map key values in a Map

I have to parse an XML:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<contentType>Document</contentType>
<siteName>mySite</siteName>
<listName>myLib</listName>
<folderName>docset-folder</folderName>
<documentSetName>documentSet</documentSetName>
<fields>
<field name="META_1">123456789</field>
<field name="META_2">Someone</field>
<field name="META_3">Germany</field>
<field name="META_4">Abonnement2 LC</field>
</fields>
</data>
I created a simple POJO class for mapping this XML. I set properties of the XML file.
Concerning the field, I can have as many data with unique name.
#Data
#XmlRootElement(name = "data")
public class MetaDataSharePoint {
#JacksonXmlProperty(localName = "contentType")
private String contentType;
#JacksonXmlProperty
private String siteName;
#JacksonXmlProperty
private String listName;
#JacksonXmlProperty
private String folderName;
#JacksonXmlProperty
private String documentSetName;
#JacksonXmlElementWrapper(localName = "fields")
#JacksonXmlProperty(localName = "field")
private Map<String, Object> fields;
}
My objective is to map correctly this XML and handle a POJO. The following code allow to open an XML file and read its content. The XMLMapper object allows to match the xml and the object.
public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException, XMLStreamException, TransformerException {
String path = "src/test/resources/bill.xml";
XMLInputFactory f = XMLInputFactory.newFactory();
XMLStreamReader sr = f.createXMLStreamReader(new FileInputStream(path));
XmlMapper mapper = new XmlMapper();
sr.next();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
MetaDataSharePoint metaDataSharePoint = mapper.readValue(sr, MetaDataSharePoint.class);
// start test
System.out.println(metaDataSharePoint);
System.out.println("contentType : " + metaDataSharePoint.getContentType());
System.out.println("DocumentSetName : " + metaDataSharePoint.getDocumentSetName());
System.out.println("ListName : " + metaDataSharePoint.getListName());
System.out.println("SiteName : " + metaDataSharePoint.getSiteName());
System.out.println("FolderName : " + metaDataSharePoint.getFolderName());
metaDataSharePoint.getFields().forEach((key, value) -> {
System.out.println(key);
System.out.println(value);
});
// end test
sr.close();
}
I successfully map part of my object.
I print the following:
MetaDataSharePoint(contentType=Document, siteName=mySite, listName=myLib, folderName=docset-folder, documentSetName=documentSet, fields={field={name=META_4, =Abonnement2 LC}})
contentType : Document
DocumentSetName : documentSet
ListName : myLib
SiteName : mySite
FolderName : docset-folder
field
{name=META_4, =Abonnement2 LC}
My map is not returning the expected results. I would like to add to a map keys and values.
I would expect something like this:
key: META_1
value: 123456789
key: META_2
value: Someone
...
I tried using several methods to map this XML unsuccesfully.
Thanks
I simple modified my POJO :
#Data
#AllArgsConstructor #NoArgsConstructor
#Builder
#XmlRootElement(name = "data")
public class MetaDataSharePoint {
#JacksonXmlProperty(localName = "contentType")
private String contentType;
#JacksonXmlProperty
private String siteName;
#JacksonXmlProperty
private String listName;
#JacksonXmlProperty
private String folderName;
#JacksonXmlProperty
private String documentSetName;
#JacksonXmlProperty
private List<MetaDataFields> fields;
}
I replaced the Map with a list of objects. For this I implemented this POJO :
#Data
#Builder
#AllArgsConstructor #NoArgsConstructor
#XmlRootElement(name = "field")
public class MetaDataFields {
#JacksonXmlProperty(isAttribute = true)
private String name;
#JacksonXmlText
private String value;
}
I retrieve the data as I expect. that's cool...

Jackson parsing XML

I'm trying to serialize POJO class to Amazon XML format to aggregate the date from the service.
The goal is to have an xml like:
<ShipmentEventList>
<ShipmentEvent>
<ShipmentItemList>
<ShipmentItem></ShipmentItem>
</ShipmentItemList>
<AmazonOrderId>AAAA</AmazonOrderId>
<PostedDate>BBBB</PostedDate>
<MarketplaceName>CCCC</MarketplaceName>
<SellerOrderId>DDDD</SellerOrderId>
</ShipmentEvent>
</ShipmentEventList>
Here are my POJO classes
ShipmentEventList
public class ShipmentEventList {
#JacksonXmlElementWrapper(localName = "ShipmentEventList")
#JacksonXmlProperty(localName = "ShipmentEvent")
private List<ShipmentEvent> shipmentEventList;
}
ShipmentEvent
#JacksonXmlRootElement(localName = "ShipmentEvent")
public class ShipmentEvent {
#JacksonXmlElementWrapper(localName = "ShipmentItemList")
private List<ShipmentItem> shipmentItemList;
#JacksonXmlProperty(localName = "AmazonOrderId")
private String amazonOrderId;
#JacksonXmlProperty(localName = "PostedDate")
private String postedDate;
#JacksonXmlProperty(localName = "MarketplaceName")
private String marketplaceName;
#JacksonXmlProperty(localName = "SellerOrderId")
private String sellerOrderId;
}
Unfortunatelly, as a result of the serialization I have:
<ShipmentEventList>
<ShipmentEventList>
<ShipmentEvent>
<AmazonOrderId>A</AmazonOrderId>
<PostedDate>B</PostedDate>
<MarketplaceName>C</MarketplaceName>
<SellerOrderId>D</SellerOrderId>
</ShipmentEvent>
<ShipmentEvent>
<AmazonOrderId>B</AmazonOrderId>
<PostedDate>C</PostedDate>
<MarketplaceName>D</MarketplaceName>
<SellerOrderId>E</SellerOrderId>
</ShipmentEvent>
</ShipmentEventList>
</ShipmentEventList>
Could you explain me how does the serialization of collections work in Jackson?
You need to set useWrapping flag to false:
class ShipmentEventList {
#JacksonXmlElementWrapper(useWrapping = false)
#JacksonXmlProperty(localName = "ShipmentEvent")
private List<ShipmentEvent> shipmentEventList;
}

Jackson Serialization of XML with multiple attributes

Trying to figure out how to serialize an xml payload with jackson that has multiple attributes(?) as well as namespaces or locals.
I need the payload to look like this:
<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc" xmlns:fade="http://www.bit-sys.com/fade" service="WFS" version="1.1.0" resultType="results" maxFeatures="150001" outputFormat="application/json">
<wfs:Query srsName="EPSG:4326" typeName="ExampleTypeName">
<Filter xmlns="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml">
...
And I am working on creating a pojo to use to map the data necessary for this payload to the correct location, but just having trouble differentiating the namespace vs localName parts. The pojo I have so far isn't really producing the desired result (even for the first <GetFeature /> part.
public class MyXmlObject {
#JacksonXmlRootElement(localName = "wfs", namespace = "wfs")
class GetFeature {
#JacksonXmlProperty(isAttribute = true)
private String wfs = "http://www.opengis.net/wfs";
#JacksonXmlProperty(isAttribute = true)
private String ocg = "http://www.opengis.net/ogc";
#JacksonXmlProperty(isAttribute = true)
private String fade = "http://www.bit-sys.com/fade";
#JacksonXmlProperty(isAttribute = true)
private String service;
#JacksonXmlRootElement(localName = "wfs")
public class Query {
#JacksonXmlProperty(isAttribute = true)
private String srsName = "exampleSrsName";
#JacksonXmlProperty(isAttribute = true)
private String typeName = "exampleTypeName";
}
}
}
Right now only running a simple test to see how my xml payload looks as I work on it produces <MyXmlObject /> with nothing else in it, not too sure what I am doing wrong.
#Test
public void whenJavaSerializedToXmlStr_thenCorrect()
throws JsonProcessingException {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
String xml = xmlMapper.writeValueAsString(new MistXmlObject());
System.out.print(xml);
}

Reading xml file in Java - only selected elements

I have just started to learn how to make a java object from a XML. However, now I have a tricky input and I don't really know how to solve it.
This is the input:
<?xml version="1.0" encoding="UTF-8"?>
<return>
<productChange cd_product="711" ds_product="MBL40337 I151 BLACK P" cd_species="UN" cd_tipi="61062000" cd_cst="5" qt_weight="" cd_nbm="" dt="2016-05-04 11:47:36">
<productvalue cd_company="1" cd_product="711" tp_value="P" cd_value="1" vl_product="61.39">
<tipovaluePrd tp_value="P" cd_value="1" ds_value="SALE" cd_corrency="1" />
</productvalue>
<productvalue cd_company="1" cd_product="711" tp_value="P" cd_value="4" vl_product="129.8">
<tipovaluePrd tp_value="P" cd_value="4" ds_value="SALE STORE" cd_corrency="1" />
</productvalue>
<productvalue cd_company="1" cd_product="711" tp_value="P" cd_value="5" vl_product="64.9">
<tipovaluePrd tp_value="P" cd_value="5" ds_value="SALE AT" cd_corrency="1" />
</productvalue>
<productvalue cd_company="1" cd_product="711" tp_value="P" cd_value="8" vl_product="122.78">
<tipovaluePrd tp_value="P" cd_value="8" ds_value="SALE FQ" cd_corrency="1" />
</productvalue>
</productChange>
</return>
To consume this xml with JaxB (XML provided by a third party company) I have built the following classes:
#XmlAccessorType(XmlAccessType.FIELD)
public class ProductUpdateResponse {
#XmlAttribute(name = "cd_product")
private Integer productCode;
#XmlAttribute(name = "ds_product")
private String productDescription;
#XmlAttribute(name = "cd_species")
private String productSpecie;
#XmlAttribute(name = "cd_tipi")
private Integer productTIPI;
#XmlAttribute(name = "cd_cst")
private Integer productCST;
#XmlAttribute(name = "qt_weight")
private String productWeight;
#XmlAttribute(name = "cd_nbm")
private String productNBM;
#XmlAttribute(name = "dt")
private String productDate;
#XmlElement(name = "productvalue")
private ProductValueType productValue;
// getters and setters
}
#XmlAccessorType(XmlAccessType.FIELD)
public class ProductValue {
#XmlAttribute(name = "cd_product")
private Integer productCode;
#XmlAttribute(name = "cd_company")
private Integer companyCode;
#XmlAttribute(name = "tp_value")
private String valueType;
#XmlAttribute(name = "cd_value")
private Integer valueCode;
#XmlAttribute(name = "vl_product")
private BigDecimal productValue;
#XmlElement(name = "tipovaluePrd")
private ProductValueType productValueType;
//getters and seters
}
#XmlAccessorType(XmlAccessType.FIELD)
public class ProductValueType {
#XmlAttribute(name = "tp_value")
private String valueType;
#XmlAttribute(name = "cd_value")
private String valueCode;
#XmlAttribute(name = "ds_value")
private String valueDescription;
#XmlAttribute(name = "cd_corrency")
private Integer valueCurrency;
//getters and seters
}
However, the main information, for me, is comming as null (productvalue) I wonder if it is because there are four tags productvalue in the xml (I just need the one whose tipovaluePrd.cd_value is 4 ).
Below is the method I'm using to parse the XML:
private ProductUpdateResponse buildResponse(String rawResponse, Class<T> responseClass) {
JAXBContext jaxbContext = null;
try {
jaxbContext = JAXBContext.newInstance(responseClass);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(rawResponse);
return (ProductUpdateResponse) unmarshaller.unmarshal(reader);
} catch (JAXBException | ClassCastException e) {
return null;
}
}
So, I wonder if there is a way to read specifically the value I want (productvalue element that has tipovaluePrd.cd_value = 4) and how could I do that. If there isn't, how should I build my class so I can read properly everything?
Changing the input is not an option here...
Thanks in advance for any help.
I'm actually surprised you're getting a result from JAXB with your current setup.
You lack a class representing your root element :
#XmlRootElement(name="return")
#XmlAccessorType(XmlAccessType.FIELD)
public class Return {
#XmlElement(name="productchange")
private ProductUpdateResponse response;
//getters and setters
}
Also, in your ProductUpdateResponse class, you should change :
#XmlElement(name = "productvalue")
private ProductValueType productValue;
by
#XmlElement(name = "productvalue")
private List<ProductValue> productValues;
Finally, in your buildResponse method, make sure the responseClass argument is Return.class.
With this, you should have a list with all your productvalue element. You just have to get the productvalue your interested in from it.
If you only want to get the element you're interested with :
As swasa suggested it, you can use the javax.xml.xpath to make an Xpath request on your XML.
If you're willing to change your JAXB Implementation : EclipseLink JAXB Implementation implements an #XmlPath annotation that allows you to bind objects according to an XPath request :
#XmlPath(name = "productvalue/tipovaluePrd[#cd_value=4]")
private ProductValueType productValueType;

Using jackson xml mapper to map java list in xml

I've a problem with xml Mapper.
I'm using the com.fasterxml.jackson.xml.XmlMapper library.
Practically, this is my java bean that map the values in this way:
#JsonAutoDetect
#JacksonXmlRootElement(localName ="Patient")
public class Patient implements Serializable {
private static final long serialVersionUID = -2981849269841429849L;
#JsonProperty("patientId")
#JacksonXmlProperty(isAttribute = true)
private String patientId;
#JsonProperty("patientName")
#JacksonXmlProperty(isAttribute = true)
private String patientName;
#JacksonXmlProperty(localName = "Series")
#JacksonXmlElementWrapper(useWrapping=false)
private ArrayList<Serie> listSerie;
}
and generate in the main class the xml with:
Wado mapp = new Wado();
mapp.setvalue("bla bla");
String xmlWado = new XmlMapper().writeValueAsString(wado);
the result is:
<Patient patientId="" patientName="">
<Series>
<Series></Series>
<Series></Series>
<Series></Series>
</Series>
that's not I was expected. I want:
<Patient patientId="" patientName="">
<Series></Series>
<Series></Series>
<Series></Series>
Any suggestions?

Categories

Resources