I have my data model in the form of XSD files from which I then generate the corresponding Java files from xjc using command line.
When I generate JAXB classes from an XSD, List type elements gets a getter method generated for them (with no corresponding setter method), as follows:
public List<Type> getElement3() {
if (element3 == null) {
element3 = new ArrayList<Type>();
}
return this.element3;
}
I have lot of fields in almost every file generated from XSD of List type.
USE case:
Now, I don't want the getter to be generated with the null check. My application code has logic in which the getters of every fields are called often, which leads to their initialization to empty List.
Then while marshaling I have to stop the empty list to pass in the payload to avoid lot of empty lists being sent over the wire.
PS: I have a use case where Empty List is set explicitly by the user, the server has to delete certain items at the back-end. So the differentiation whether the value is explicitly set by the user or is set just because the getter for the List was called during accessing the field.
So, How to make JAXB generate a getter without a null check ??
As, editing the generated java files after compilation will be cumbersome as it's there in lot of files and we have XSD versions getting updated and would have to perform the editing every time a new version comes up.
At first, I would think of using a custom JAXB Binding, but I can´t think of any that would meet this requirement.
In this case, perhaps you could use a wrapper class:
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "employees")
#XmlAccessorType (XmlAccessType.FIELD)
public class Employees
{
#XmlElement(name = "employee")
private List<Employee> employees = null;
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
And then define your business object:
#XmlRootElement(name = "employee")
#XmlAccessorType (XmlAccessType.FIELD)
public class Employee
{
private Integer id;
private String firstName;
private String lastName;
private double income;
//Getters and Setters
}
You will have to control the initialization of the list yourself when generating the objects to be marshalled:
Employees employees = new Employees();
employees.setEmployees(new ArrayList<Employee>());
Source of this example: Here
I've created a small example which you could try. Although it doesn't remove the null-check from the original getter, it is a jaxb-plugin which creates an additional method isXXXNull and allows you to test this case before accessing the getXXX-method. Take a look at the example here
Related
I have a 1:N relationship where a Victim might have lots of EmergencyContacts.
I've created a DTO called VictimDTO and inside of it there's a List and I'm using ModelMapper to convert my DTO into an Entity.
When I get rid of the list just for testing purposes, it works fine placing this code snippet inside of the insert "POST" method in the Controller layer in Java:
VictimEntity victimEntity = modelMapper.map(victimDTO, VictimEntity.class);
But now I've placed this List inside of my VictimDTO and I'm getting an Exception when trying to use this code.
My DTO actual code is this one as it follows below:
public class VictimDTO {
private String name;
private int age;
private String email;
private String phone;
private List<ContactDTO> contactDTOList;
//getters and setters
}
How can I use ModelMapper to convert a POJO with a Collection (List) as an instance variable inside into an Entity?
Thank you for your help.
Best regards,
Lucas Abrão
I would like to get a xml result as below which using JAXB to get java object.
<Mall>
<ProductInfo>
<Product>
<name>chair</name>
<price>150</price>
</Product>
</ProductInfo>
</Mall>
To get this result, I made 3 java classes which are
Define XmlRootElement, XmlElement
component of product (getter/setter)
Main class which insert the value of component
In this way, I could make only 3 depths using XmlRootElement, XmlElement, Component of product.
Hence I need one more depth..
I tried to use a XmlElementWrapper to give one more depth, but there was an error regarding it is not a collecting attribute...
Please help me to solve this out...
Below is class structure that should work
#XmlRootElement (name = "mall")
public class Mall {
Mall(){ }
#XmlElement(name="ProductInfo")
private ProductInfo info; // must create getter and setter
}
}
public class ProductInfo { // you should be missing this
ProductInfo(){
}
#XmlElement(name="Product")
private List<Product> info; // must create getter and setter
}
}
public class Product {
Product(){
}
#XmlElement(name="name")
private ProductInfo info; // must create getter and setter
#XmlElement(name="price")
private ProductInfo info; // must create getter and setter
}
}
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
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'}
I'm working on a hobby/learning project, and I need to persist some data, but I don't want to use a database. After some research, I found that using JAXB could be a good idea, but I can't seem to wrap my head around using it. I read tutorials, and the documentation as well, but it just doesn't click for me.
The program is a receipt storing/budgeting type of thing, so I'd need to save the receipts somehow.
The relevant classes look like this so far:
package classes;
import java.time.*;
import java.util.ArrayList;
import java.util.List;
public class Receipt {
private String shop;
private LocalDate date;
private Double total;
private List<Entry> items;
//...contructor,getters & setters
and
package classes;
public class Entry {
private String name;
private Double price;
//...contructor,getters & setters
And what I'd like to have looks kinda like this:
<Receipts>
<Receipt>
<Shop>Tesco</Shop>
<Date>2016-06-03</Date>
<Total>200</Total>
<Items>
<Item>foo 100</Item>
<Item>bar 100</Item>
</Items>
</Receipt>
...
</Receipts>
So I guess, I have 2 questions:
1. Am I on the right track with JAXB, is it a right way of persisting data for a standalone application?
2. How can I do it? I don't understand all the annotations and schemas and stuff.
I'd appreciate any help, pointing me to a good tutorial, or writing a very didactic guide.
Thank you
JAXB is not is not a persistence engine. You can use it to convert XML to Java objects or objects to XML. The data can be persisted on files or even databases. JAXB does not replace a database. You have no searches, relationships between different entities, indexes, XML data is loaded entirely, etc.
If you want to use it in your learning project these are the main parts. I include only the annotations and changes to code to map your model
Java objects
//Added XmlRootElement and XmlElement for list
#XmlRootElement(name = "Receipts")
public class Receipts {
private List<Receipt> receipts;
#XmlElement(name = "Receipt")
public List<Receipt> getReceipts() {
//Added XmlElementWrapper and XmlElement for list
public class Receipt {
private String shop;
private Date date; //Changed to Date because marshalling is directly supported
private Double total;
private List<Entry> items ;
#XmlElementWrapper(name="Items")
#XmlElement(name = "Item")
public List<Entry> getItems() {
//No changes
public class Entry {
private String name;
private Double price;
Marshall (Java to XML)
JAXBContext jaxbContext = JAXBContext.newInstance(Receipts.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(receipts, new File(file);
Unmarshaller (XML to Java)
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Receipts receiptsUnmarshalled = (Receipts) jaxbUnmarshaller.unmarshal(file);
I am using #XmlRootElement annotation to get XML data from the database.
Right now, if I put #XmlTransient to getters, the fields are ignored.
For example:
public class Student {
private Integer studentId;
private String studentName;
#XmlTransient // Do not get student id
public Integer getStudentId() {
return this.studentId;
}
public String getStudentName() {
return this.studentName;
}
...// Setter goes here
Then, student ids are not appear in the XML file.
However, can I do this in the opposite way? I want to specify fields that I want to have in the XML file - there are too many fields in the Student class.
My server(Spring Framework 3.2.3) also uses the Jackson library, so I wonder I could use it if that is possible.
You could annotate your class with:
#XmlAccessorType(XmlAccessType.NONE)
Now you have to explicitly map properties in order to be serialized. See the Javadoc: http://docs.oracle.com/javaee/7/api/javax/xml/bind/annotation/XmlAccessType.html