I've made an RESTful api that returns following simple XML:
<!-- language: lang-xml -->
<?xml version="1.0" encoding="utf-8"?>
<GoldPriceArray>
<GoldPrice>
<Date>2020-06-15</Date>
<Price>219.01</Price>
</GoldPrice>
<GoldPrice>
<Date>2020-06-16</Date>
<Price>216.73</Price>
</GoldPrice>
</GoldPriceArray>
I'm trying to unmarchall Date and Price but cannot get into nested elements - my code returns NullPointerException on unmarchaller() method. Here's my code
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "GoldPriceArray")
public class GoldRates {
private List<GoldRate> goldRateList;
private String goldValue;
public GoldRates() {}
public GoldRates(String goldPrice, List<GoldRate> goldRateList) {
this.goldRateList = goldRateList;
this.goldValue = goldPrice;
}
#XmlElement
public List<GoldRate> getList() {
return goldRateList;
}
public void setList(ArrayList<GoldRate> goldRateList) {
this.goldRateList = goldRateList;
}
#XmlElement
public String getPrice() {
return goldValue;
}
public void setPrice(String goldPrice) {
this.goldValue = goldPrice;}
public class GoldRate {
#XmlElement(name = "Date")
private String dateOfPrice;
#XmlElement(name = "Price")
private String price;
public GoldRate() {
}
public GoldRate(String date, String value) {
this.dateOfPrice = date;
this.price = value;
}
public String getDate() {
return dateOfPrice;
}
public void setDate(String date) {
this.dateOfPrice = date;
}
public String getValue() {
return price;
}
public void setValue(String value) {
this.price = value;
}
#Override
public String toString() {
return "Date: " + dateOfPrice + " value: " + price;
}
}
Unmarchalling method that returns NullPointerException on System.out.println()
public void unmarshaller(String xml) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(GoldRates.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
GoldRates goldRates = (GoldRates) jaxbUnmarshaller.unmarshal(new StringReader(xml));
System.out.println(goldRates.getList().get(0).getValue() + " " + goldRates.getList().get(0).getDate());
} catch (JAXBException e) {
e.printStackTrace();
}
return null;
}
Any hints on this one? I'm really stuck.
Just found solution:
private List<GoldRate> goldRateList
should be named exactly the same as an element of XML that it refers to, so the proper one is:
private List<GoldRate> GoldPrice
This is a part of a complex xml template which i put here for the question :
<?xml version="1.0" encoding="UTF-8"?>
<Document>
<CstmrDrctDbtInitn>
<GrpHdr>
<MsgId>${MsgId}</MsgId>
<CreDtTm>${CreDtTm}</CreDtTm>
<NbOfTxs>${NbOfTxs}</NbOfTxs>
<a> ${val1}
<b>
${val2}
</b>
</a>
<CtrlSum>${CtrlSum}</CtrlSum>
</GrpHdr>
<PmtInf>
<PmtInfId>${PmtInfId}</PmtInfId>
<PmtMtd>${PmtMtd}</PmtMtd>
</PmtInf>
<#list persons as person>
</#list>
</CstmrDrctDbtInitn>
</Document>
I have been using FreeMarker for the previous month and until now the xml models have been easy
Searching over the web on how to approach this template , should i create matching java classes (100 of them ? )... should i use Map? like shown here .
I don't have a clue how to do it ... how to apply FreeMarker on this template ?
So here is a solution for any future users . Firstly i created 3 models which i am calling like below :
Map<String, Object> data = new HashMap<>();
//================= Example Creating HeaderVo //=================
HeaderVo header = new HeaderVo("la","la",5,5,"la","la");
data.put("header", header);
//================= Example Creating MiddleVo //=================
MiddleVo middleVo = new MiddleVo("la","la",5,"la","la","la","la");
data.put("middle", middleVo);
//================= Example Creating internal items =================
InternalVo v1 = new InternalVo(5, 5, 5, "s", true, "zz", "zzzz", "ll","EUR");
InternalVo v2 = new InternalVo(5, 5, 5, "s", true, "zz", "zzzz", "ll","DOLLARS");
InternalVo v3 = new InternalVo(5, 5, 5, "s", true, "zz", "zzzz", "ll","LAT");
//List parsing
List<InternalVo> internalVos = new ArrayList<>();
internalVos.add(v1);
internalVos.add(v2);
internalVos.add(v3);
data.put("vos", internalVos);
//================= //================= //================= //=================
final String message = this.templateManager.composeStringFromTemplate(data, "bankfile.ftl");
So below is the bankfile.ftl which represents the complex xml :
```
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02">
<CstmrDrctDbtInitn>
<GrpHdr>
<MsgId>${header.msgId}</MsgId>
<CreDtTm>${header.creDtTm}</CreDtTm>
<NbOfTxs>${header.nbOfTxs}</NbOfTxs>
<CtrlSum>${header.ctrlSum}</CtrlSum>
<InitgPty>
<Nm>${header.nm}</Nm>
<Id>
<OrgId>
<Othr>
<Id>${header.id}</Id>
</Othr>
</OrgId>
</Id>
</InitgPty>
</GrpHdr>
<PmtInf>
<PmtTpInf>
<SvcLvl>
<Cd>${middle.svcLvlCD}</Cd>
</SvcLvl>
<LclInstrm>
<Cd>${middle.lclInstrmCD}</Cd>
</LclInstrm>
<SeqTp>${middle.seqTp}</SeqTp>
</PmtTpInf>
<ReqdColltnDt>${middle.reqdColltnDt}</ReqdColltnDt>
<Cdtr>
<Nm>${middle.nm}</Nm>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>${middle.iBAN}</IBAN>
</Id>
</CdtrAcct>
<CdtrAgt>
<FinInstnId>
<BIC>${middle.bIC}</BIC>
</FinInstnId>
</CdtrAgt>
<#list vos as vo>
<DrctDbtTxInf> <PmtId> <EndToEndId>${vo.endToEndId}</EndToEndId> </PmtId> <InstdAmt Ccy="${vo.ccy}">${vo.instdAmt}</InstdAmt> <DrctDbtTx> <MndtRltdInf> <MndtId>${vo.mndtId}</MndtId> <DtOfSgntr>${vo.dtOfSgntr}</DtOfSgntr> <AmdmntInd>${vo.amdmntInd?c}</AmdmntInd> </MndtRltdInf> </DrctDbtTx> <DbtrAgt> <FinInstnId> <BIC>${vo.bIC}</BIC> </FinInstnId> </DbtrAgt> <Dbtr> <Nm>${vo.nm}</Nm> </Dbtr> <DbtrAcct> <Id> <IBAN>${vo.iBAN}</IBAN> </Id> </DbtrAcct> </DrctDbtTxInf>
</#list>
</PmtInf>
</CstmrDrctDbtInitn>
</Document>
```
And finally here are the 3 models used for the FTL ( sorry for them being huge , i just wanted to so how complex it can get :) ):
HeaderVo
public class HeaderVo {
private String msgId;
private String creDtTm;
private int nbOfTxs;
private int ctrlSum;
private String nm;
private String id;
public HeaderVo() {
super();
}
public HeaderVo(String msgId, String creDtTm, int nbOfTxs, int ctrlSum, String nm, String id) {
super();
this.msgId = msgId;
this.creDtTm = creDtTm;
this.nbOfTxs = nbOfTxs;
this.ctrlSum = ctrlSum;
this.nm = nm;
this.id = id;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public String getCreDtTm() {
return creDtTm;
}
public void setCreDtTm(String creDtTm) {
this.creDtTm = creDtTm;
}
public int getNbOfTxs() {
return nbOfTxs;
}
public void setNbOfTxs(int nbOfTxs) {
this.nbOfTxs = nbOfTxs;
}
public int getCtrlSum() {
return ctrlSum;
}
public void setCtrlSum(int ctrlSum) {
this.ctrlSum = ctrlSum;
}
public String getNm() {
return nm;
}
public void setNm(String nm) {
this.nm = nm;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
MiddleVo
public class MiddleVo {
private String svcLvlCD;
private String lclInstrmCD;
private int seqTp;
private String reqdColltnDt;
private String nm;
private String iBAN;
private String bIC;
public MiddleVo() {
super();
}
public MiddleVo(String svcLvlCD, String lclInstrmCD, int seqTp, String reqdColltnDt, String nm, String iBAN,
String bIC) {
super();
this.svcLvlCD = svcLvlCD;
this.lclInstrmCD = lclInstrmCD;
this.seqTp = seqTp;
this.reqdColltnDt = reqdColltnDt;
this.nm = nm;
this.iBAN = iBAN;
this.bIC = bIC;
}
public String getSvcLvlCD() {
return svcLvlCD;
}
public void setSvcLvlCD(String svcLvlCD) {
this.svcLvlCD = svcLvlCD;
}
public String getLclInstrmCD() {
return lclInstrmCD;
}
public void setLclInstrmCD(String lclInstrmCD) {
this.lclInstrmCD = lclInstrmCD;
}
public int getSeqTp() {
return seqTp;
}
public void setSeqTp(int seqTp) {
this.seqTp = seqTp;
}
public String getReqdColltnDt() {
return reqdColltnDt;
}
public void setReqdColltnDt(String reqdColltnDt) {
this.reqdColltnDt = reqdColltnDt;
}
public String getNm() {
return nm;
}
public void setNm(String nm) {
this.nm = nm;
}
public String getiBAN() {
return iBAN;
}
public void setiBAN(String iBAN) {
this.iBAN = iBAN;
}
public String getbIC() {
return bIC;
}
public void setbIC(String bIC) {
this.bIC = bIC;
}
}
InternalVo
public class InternalVo {
private int endToEndId;
private int instdAmt;
private int mndtId;
private String dtOfSgntr;
private boolean amdmntInd;
private String bIC;
private String nm;
private String iBAN;
private String ccy;
public InternalVo() {
super();
}
public InternalVo(int endToEndId, int instdAmt, int mndtId, String dtOfSgntr, boolean amdmntInd, String bIC, String nm,
String iBAN,String ccy) {
super();
this.endToEndId = endToEndId;
this.instdAmt = instdAmt;
this.mndtId = mndtId;
this.dtOfSgntr = dtOfSgntr;
this.amdmntInd = amdmntInd;
this.bIC = bIC;
this.nm = nm;
this.iBAN = iBAN;
this.ccy = ccy;
}
public int getEndToEndId() {
return endToEndId;
}
public void setEndToEndId(int endToEndId) {
this.endToEndId = endToEndId;
}
public int getInstdAmt() {
return instdAmt;
}
public void setInstdAmt(int instdAmt) {
this.instdAmt = instdAmt;
}
public int getMndtId() {
return mndtId;
}
public void setMndtId(int mndtId) {
this.mndtId = mndtId;
}
public String getDtOfSgntr() {
return dtOfSgntr;
}
public void setDtOfSgntr(String dtOfSgntr) {
this.dtOfSgntr = dtOfSgntr;
}
public boolean isAmdmntInd() {
return amdmntInd;
}
public void setAmdmntInd(boolean amdmntInd) {
this.amdmntInd = amdmntInd;
}
public String getbIC() {
return bIC;
}
public void setbIC(String bIC) {
this.bIC = bIC;
}
public String getNm() {
return nm;
}
public void setNm(String nm) {
this.nm = nm;
}
public String getiBAN() {
return iBAN;
}
public void setiBAN(String iBAN) {
this.iBAN = iBAN;
}
public String getCcy() {
return ccy;
}
public void setCcy(String ccy) {
this.ccy = ccy;
}
I am a novice in SAXParser. I don't know is it possible to parse complex object with SAXParser. I have a class which contain Item list. And my response xml is like that :
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetPaymentServiceInfoResponse xmlns="http://quetzalcoatlus/EpulPaymentService"><GetPaymentServiceInfoResult><ResultCodes>OK</ResultCodes><Description>User is temporary blocked</Description><Items><Item><Amount>122</Amount></Item><Item><Amount>23232</Amount></Item></Items></GetPaymentServiceInfoResult></GetPaymentServiceInfoResponse></s:Body></s:Envelope>
And my POJO class is like following:
#XmlRootElement(name = "PGResponse")
public class CheckAbonSuccessResponseModel {
private String message;
private String message_code;
private BigDecimal amount;
private String invoiceCode;
private String operationCode;
private List<Item> items;
#XmlElement(name = "message")
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#XmlElement(name = "message_code")
public String getMessage_code() {
return message_code;
}
public void setMessage_code(String message_code) {
this.message_code = message_code;
}
#XmlElement(name = "amount")
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
#XmlElement(name = "invoice_code")
public String getInvoiceCode() {
return invoiceCode;
}
public void setInvoiceCode(String invoiceCode) {
this.invoiceCode = invoiceCode;
}
#XmlElement(name = "operation_code")
public String getOperationCode() {
return operationCode;
}
public void setOperationCode(String operationCode) {
this.operationCode = operationCode;
}
#XmlElement(name = "items")
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
#XmlRootElement(name = "item")
public static class Item {
private String label;
private String value;
#XmlElement(name = "label")
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
#XmlElement(name = "value")
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
How I can parse my xml string to CheckAbonSuccessResponseModel. Is it possible or not? I was trying but it shows just amount inside Result element.I need just know how I must write DefaultHandler class.
Thanks in advance.
I'm working at a Method to filter a collection (FileList) of xml-files if a specific xml-tag has an attribute...
In detail... I want to filter all xml-files where the xml-tag has an attribute "is_special", but I've problems to setup my model-classes for the attribute.
At the end I want to store the name of the file and a list of its items, where the value has the attribute is_special="true"
Also I'm using the JAXB Framework with the Moxy extension...
The XML-Structure as followed:
<document>
<id>75C8866AB078DCE541256D16002CF636</id>
<size>806220</size>
<author>xxx</author>
<last_modified>2017.06.12 07:15:41 GMT</last_modified>
<added_to_file>2016.07.05 09:50:44 GMT</added_to_file>
<created>2003.04.28 08:11:06 GMT</created>
<items>
<item>
<name>someName/name>
<type>LNITEMTYPE_DATETIMES</type>
<values>
<value is_special="true"/>
</values>
<last_modified>2003.04.28 08:11:10 GMT</last_modified>
...
</item>
<item>
<name>someName/name>
<type>LNITEMTYPE_TEXT</type>
<values>
<value>SOMETEXT</value>
<value>SOMETEXT</value>
</values>
<last_modified>2003.04.28 08:11:10 GMT</last_modified>
...
</item>
</items>
Therefor I've got 3 Classes for the XML-File...
"XMLDocument.java" implements the list of "Items.java" which implements the list of "Value.java"
XMLDocument.java
#XmlRootElement(name = "notes_document")
public class XMLDocument {
...
private List<Item> items;
...
#XmlElementWrapper(name = "items")
#XmlElement(name = "item")
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
item.java
#XmlRootElement(name = "items")
public class Item {
private String name;
private List<String> values;
private boolean valueIsSpecial;
#XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElementWrapper(name = "values")
#XmlElement(name = "value")
public List<String> getValues() {
return values;
}
public void setValues(List<String> values) {
this.values = values;
}
#XmlPath("value/#is_special")
public boolean getValueIsSpecial() {
return valueIsSpecial;
}
public void setValueIsSpecial(boolean valueIsSpecial) {
this.valueIsSpecial = valueIsSpecial;
}
}
value.java
#XmlRootElement(name = "values")
public class Value {
#XmlElement(name = "value")
private String itemValue;
#XmlPath("value/#is_special")
private boolean isSpecial;
public String getValue() {
return itemValue;
}
public void setValue(String value) {
this.itemValue = value;
}
public boolean getValueIsSpecial() {
return isSpecial;
}
public void setValueIsSpecial(boolean isSpecial) {
this.isSpecial = isSpecial;
}
}
My Method so far...
public void FilterTree_isSpecial() throws JAXBException, FileNotFoundException {
for(String file: FileList) {
if (file.endsWith(".xml") && !file.contains("databaseinfo.xml")) {
JAXBContext context = JAXBContext.newInstance(NotesDocumentMetaFile.class);
Unmarshaller um = context.createUnmarshaller();
NotesDocumentMetaFile docMetaFile = (XMLDocument) um.unmarshal(new FileReader(file));
for (int i = 0; i < docMetaFile.getItems().size(); i++) {
// CHECK IF THE <value> OF THIS ITEM HAS ATTRIBUTE is_special
}
}
}
}
Much text... I hope anyone can give me a solution :/
Actually the xpath in your Item.java needs to be : values/value/#is_special like #XmlPath("values/value/#is_special")
If you want the is_special in your Value.java also your xpath should be :
#is_special like : #XmlPath(#is_special)
Also your Item.java, Value.java needs a little change. You don't need #XmlRootElement, you already had it in your XmlDocument.java
Your Item.java should be :
public class Item
{
private String name;
private String type;
private String lastModified;
private List<Value> values;
private String isSpecial;
#XmlPath("values/value/#is_special")
public String getIsSpecial() {
return isSpecial;
}
public void setIsSpecial(String isSpecial) {
this.isSpecial = isSpecial;
}
#XmlElement(name="type")
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#XmlElement(name="last_modified")
public String getLastModified() {
return lastModified;
}
public void setLastModified(String lastModified) {
this.lastModified = lastModified;
}
#XmlElement(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElementWrapper(name="values")
#XmlElement(name="value")
public List<Value> getValues() {
return values;
}
public void setValues(List<Value> values) {
this.values = values;
}
}
Your Value.java should be :
public class Value
{
#XmlPath("text()")
private String value;
#XmlPath("#is_special")
private String isSpecial;
public String getIsSpecial() {
return isSpecial;
}
public void setIsSpecial(String isSpecial) {
this.isSpecial = isSpecial;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Note that to get value and is_special in Value.java, you could use #XmlPath.
Now you can call getIsSpecial() on Item.java to check if it is special.
The xml structure I am trying to parse is:
<contentFiles>
<contentFile>
<fileNumbers>
<fileNumber>123<fileNumber>
</fileNumbers>
</contentFile>
<contentFile/>
<contentFiles>
How do I parse this using JAXB ?
I used the annotations on getters described above but I only get the last element in the multiples of FileNumbers saved. I want to save all the elements of FileNumbers in the list. How do I do this ?
EDIT:::
#XmlRootElement(name = "contentFiles")
public class RtSuperQuickMetadata
{
private List<RtSuperQuickMetadataItem> rtSuperQuickMetadataItems;
#XmlElement(name = "contentFile")
public final List<RtSuperQuickMetadataItem> getRtSuperQuickMetadataItems()
{
return rtSuperQuickMetadataItems;
}
// Setter
}
public class RtSuperQuickMetadataItem
{
private List<FileNumber> fileNumbers;
public RtSuperQuickMetadataItem()
{
fileNumbers = new ArrayList<FileNumber>();
}
#XmlElement(name = "fileNumbers")
public List<FileNumber> getFileNumbers()
{
return fileNumbers;
}
//setter
}
#XmlRootElement(name="fileNumber")
public class FileNumber
{
private String fileNumber;
/**
* Default no-arg constructor.
*/
public FileNumber()
{
// public no-arg constructor for JAXB
}
/**
* Accept a filenumber as constructor arg.
* #param fileNumber is the fileNumber
*/
public FileNumber(final String fileNumber)
{
this.fileNumber = fileNumber;
}
/**
* Getter.
* #return the fileNumber
*/
//#XmlElement(name = "fileNumber")
public final String getFileNumber()
{
return fileNumber;
}
/**
* Setter.
* #param fileNumber to be set.
*/
public final void setFileNumber(final String fileNumber)
{
this.fileNumber = fileNumber;
}
#Override
public final String toString()
{
return fileNumber;
}
}
The reason I'm asking for a larger XML file representation is that your code will completely depend on the requirements of the XML file. For instance, this bit of your code works with the following XML file:
Code:
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.bind.*;
public class JaxbTest {
private static final String RESOURCE_NAME = "data.txt";
public static void main(String[] args) {
// marshallTest();
unmarshallTest();
}
private static void unmarshallTest() {
JAXBContext context;
try {
context = JAXBContext.newInstance(RtSuperQuickMetadata.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
RtSuperQuickMetadata metaData = (RtSuperQuickMetadata) unmarshaller
.unmarshal(JaxbTest.class.getResourceAsStream(RESOURCE_NAME));
System.out.println(metaData);
} catch (JAXBException e) {
e.printStackTrace();
}
}
private static void marshallTest() {
RtSuperQuickMetadata data = new RtSuperQuickMetadata();
List<RtSuperQuickMetadataItem> metaItemList = new ArrayList<RtSuperQuickMetadataItem>();
RtSuperQuickMetadataItem metaDataItem = new RtSuperQuickMetadataItem();
List<FileNumber> fileNumbers = new ArrayList<FileNumber>();
fileNumbers.add(new FileNumber("123"));
fileNumbers.add(new FileNumber("124"));
fileNumbers.add(new FileNumber("125"));
fileNumbers.add(new FileNumber("126"));
metaDataItem.setFileNumbers(fileNumbers);
metaItemList.add(metaDataItem);
data.setRtSuperQuickMetadataItems(metaItemList);
JAXBContext context;
try {
context = JAXBContext.newInstance(RtSuperQuickMetadata.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(data, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
#XmlRootElement(name = "contentFiles")
class RtSuperQuickMetadata {
private List<RtSuperQuickMetadataItem> rtSuperQuickMetadataItems;
#XmlElement(name = "contentFile")
public final List<RtSuperQuickMetadataItem> getRtSuperQuickMetadataItems() {
return rtSuperQuickMetadataItems;
}
public void setRtSuperQuickMetadataItems(
List<RtSuperQuickMetadataItem> rtSuperQuickMetadataItems) {
this.rtSuperQuickMetadataItems = rtSuperQuickMetadataItems;
}
#Override
public String toString() {
return "RtSuperQuickMetadata [rtSuperQuickMetadataItems="
+ rtSuperQuickMetadataItems + "]";
}
}
class RtSuperQuickMetadataItem {
private List<FileNumber> fileNumbers;
public RtSuperQuickMetadataItem() {
fileNumbers = new ArrayList<FileNumber>();
}
#XmlElement(name = "fileNumbers")
public List<FileNumber> getFileNumbers() {
return fileNumbers;
}
public void setFileNumbers(List<FileNumber> fileNumbers) {
this.fileNumbers = fileNumbers;
}
#Override
public String toString() {
return "RtSuperQuickMetadataItem [fileNumbers=" + fileNumbers + "]";
}
}
#XmlRootElement(name = "fileNumber")
class FileNumber {
private String fileNumber;
public FileNumber() {}
public FileNumber(final String fileNumber) {
this.fileNumber = fileNumber;
}
// #XmlElement(name = "fileNumber")
public final String getFileNumber() {
return fileNumber;
}
public final void setFileNumber(final String fileNumber) {
this.fileNumber = fileNumber;
}
#Override
public final String toString() {
return fileNumber;
}
}
The xml file, assuming it's in the same directory as your class files:
jaxbTest.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contentFiles>
<contentFile>
<fileNumbers>
<fileNumber>123</fileNumber>
</fileNumbers>
<fileNumbers>
<fileNumber>124</fileNumber>
</fileNumbers>
<fileNumbers>
<fileNumber>125</fileNumber>
</fileNumbers>
<fileNumbers>
<fileNumber>126</fileNumber>
</fileNumbers>
</contentFile>
</contentFiles>
However if this is not your desired XML structure, then the code must change.
Edit
If you want to not nest each fileNumber element in a fileNumbers element, then get rid of the FileNumbers class and instead use a List<String> with the #XmlElementWrapper annotation.
#XmlElementWrapper(name = "fileNumbers")
#XmlElement(name = "fileNumber")
public List<String> getFileNumbers() {
return fileNumbers;
}
For instance please check out this code:
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.bind.*;
public class JaxbTest {
private static final String RESOURCE_NAME = "data.xml";
public static void main(String[] args) {
// marshallTest();
unmarshallTest();
}
private static void unmarshallTest() {
JAXBContext context;
try {
context = JAXBContext.newInstance(RtSuperQuickMetadata.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
RtSuperQuickMetadata metaData = (RtSuperQuickMetadata) unmarshaller
.unmarshal(JaxbTest.class.getResourceAsStream(RESOURCE_NAME));
System.out.println(metaData);
} catch (JAXBException e) {
e.printStackTrace();
}
}
private static void marshallTest() {
RtSuperQuickMetadata data = new RtSuperQuickMetadata();
List<RtSuperQuickMetadataItem> metaItemList = new ArrayList<RtSuperQuickMetadataItem>();
RtSuperQuickMetadataItem metaDataItem = new RtSuperQuickMetadataItem();
// List<FileNumber> fileNumbers = new ArrayList<FileNumber>();
// fileNumbers.add(new FileNumber("123"));
// fileNumbers.add(new FileNumber("124"));
// fileNumbers.add(new FileNumber("125"));
// fileNumbers.add(new FileNumber("126"));
List<String> fileNumbers = new ArrayList<String>();
fileNumbers.add("123");
fileNumbers.add("124");
fileNumbers.add("125");
fileNumbers.add("126");
metaDataItem.setFileNumbers(fileNumbers);
metaItemList.add(metaDataItem);
data.setRtSuperQuickMetadataItems(metaItemList);
JAXBContext context;
try {
context = JAXBContext.newInstance(RtSuperQuickMetadata.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(data, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
#XmlRootElement(name = "contentFiles")
class RtSuperQuickMetadata {
private List<RtSuperQuickMetadataItem> rtSuperQuickMetadataItems;
#XmlElement(name = "contentFile")
public final List<RtSuperQuickMetadataItem> getRtSuperQuickMetadataItems() {
return rtSuperQuickMetadataItems;
}
public void setRtSuperQuickMetadataItems(
List<RtSuperQuickMetadataItem> rtSuperQuickMetadataItems) {
this.rtSuperQuickMetadataItems = rtSuperQuickMetadataItems;
}
#Override
public String toString() {
return "RtSuperQuickMetadata [rtSuperQuickMetadataItems="
+ rtSuperQuickMetadataItems + "]";
}
}
class RtSuperQuickMetadataItem {
private List<String> fileNumbers;
public RtSuperQuickMetadataItem() {
fileNumbers = new ArrayList<String>();
}
#XmlElementWrapper(name = "fileNumbers")
#XmlElement(name = "fileNumber")
public List<String> getFileNumbers() {
return fileNumbers;
}
public void setFileNumbers(List<String> fileNumbers) {
this.fileNumbers = fileNumbers;
}
#Override
public String toString() {
return "RtSuperQuickMetadataItem [fileNumbers=" + fileNumbers + "]";
}
}
Will work with this XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contentFiles>
<contentFile>
<fileNumbers>
<fileNumber>123</fileNumber>
<fileNumber>124</fileNumber>
<fileNumber>125</fileNumber>
<fileNumber>126</fileNumber>
</fileNumbers>
</contentFile>
</contentFiles>
It's been a while since I've done JAX-B but I think this should do the trick (only relevant sections posted). If you want to avoid creating the FileNumberList class you can probably do so with an adapter but that will be more work than it is worth.
public class RtSuperQuickMetadataItem {
#XmlElement
public FileNumberList getFileNumbers() {
}
}
public class FileNumberList {
#XmlElement(name="fileNumber")
public List<String> getList() {
}
}