Reputation: 333
I'm attempting to deserialize an XML payload (body of a SOAP message, but nothing else), with a specific hierarchy of tags / objects. When attempting to aggregate unwrapped objects into a List, a MismatchedInputException is thrown.
Example Payload
<libraryRequest>
<libraryProfile>
<libraryId>
<libraryName>
<newBookInfo>
<bookId>...</bookId>
<bookTitle>...</bookTitle>
<datePublished>...</datePublished>
</newBookInfo>
<currentBooks>
<bookId>...</bookId>
<bookTitle>...<bookTitle>
<datePublished>...</datePublished>
</currentBooks>
<currentBooks>
<bookId>...</bookId>
<bookTitle>...<bookTitle>
<datePublished>...</datePublished>
</currentBooks>
<currentBooks>...</currentBooks>
</libraryProfile>
</libraryRequest>
Java objects are
public class LibraryRequest {
private LibraryProfile libraryProfile;
@XmlElement(name = "libraryProfile")
public LibraryProfile getLibraryProfile(){
...
}
// setters
public class LibraryProfile {
// constructors, getters & setters for primitive types
private List<BookInfo> bookInfos;
public List<BookInfo> getBookInfo(){
return this.BookInfos;
}
// rest of the functions
My issue is that I don't know how many currentBooks tags will come in the XML payload, and they don't come in a wrapper element. I need to keep track of each currentBook element, which is why I was using a Collection, but I am not able to properly fill the collection with the information contained within the currentBooks tags.
Would I be able to use JAXB to group the XML sequence into a Java Collection/List, and if not would I be able to use Jackson's XML functionality to group the unwrapped XML tags into a Java Collection?
The main goal is to use have an XML request come into a Spring Controller and have the XML sequence properly deserialized into a Java List / Collection. Any advice would help.
I'm using Spring Boot 1.5.8 (later version was giving me trouble in a different way), and Jackson version 2.9.5
Upvotes: 1
Views: 73
Reputation: 1339
This is based on the XmlElement explanation from actimem.com.
The mechanics explained:
- @XmlElement
is only needed if the field name is not equal to the xml tag name.
- If you would like to rename your field newBookInfo
to newestBook
but without changing the xml you'd simply rename your field and annotate it with @XmlElement(name="newBookInfo")
- @XmlElementWrapper
is explicitly not used to advice JAXB it should search for the list tags directly in the parent node
The XML represenation classes Book
@XmlAccessorType(XmlAccessType.FIELD)
public static class Book {
private String bookId;
private String bookTitle;
// ... accessors and toString
}
and LibraryProfile
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class LibraryProfile {
private String libraryId;
private String libraryName;
private Book newBookInfo;
// the trick is NOT to use @XmlElementWrapper here
private List<Book> currentBooks;
private String foobar; // just to show a tag after the list
// ... accessors
}
The input based on your question (I skipped the <libraryRequest>
to keep the example short)
<libraryProfile>
<libraryId>1</libraryId>
<libraryName>library of alexandria</libraryName>
<newBookInfo>
<bookId>42</bookId>
<bookTitle>the answer</bookTitle>
</newBookInfo>
<currentBooks>
<bookId>2</bookId>
<bookTitle>the second</bookTitle>
</currentBooks>
<currentBooks>
<bookId>1</bookId>
<bookTitle>the first</bookTitle>
</currentBooks>
<foobar>test-foo</foobar>
</libraryProfile>
And here the testing class:
package com.stackoverflow.answer;
import javax.xml.bind.JAXB;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.StringReader;
public class Tester {
public static final String INPUT = "..."; // here goes your xml
public static void main(String[] args) throws Exception {
LibraryProfile lib = JAXB.unmarshal(new StringReader(INPUT), LibraryProfile.class);
System.out.println(lib.getLibraryName() + " currently contains");
System.out.println(lib.getCurrentBooks());
System.out.println("the newest book is: " + lib.getNewBookInfo());
}
}
The output is now
library of alexandria currently contains
[Book{bookId='2', bookTitle='the second'}, Book{bookId='1', bookTitle='the first'}]
the newest book is: Book{bookId='42', bookTitle='the answer'}
Upvotes: 3