Reputation: 1
I have a List of java objects with structure as follows
@XmlRootElement(name = "employee")
@XmlAccessorType (XmlAccessType.FIELD)
public class Employee
{
private Integer id;
private String firstName;
private String lastName;
private double income;
//Getters and Setters
}
I want to convert it to an XML file whose contents would just be the list without any root element.
Expected Output:
< ?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<employee>
<id>l</id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<income>100. 0</income>
</employee>
<employee>
<id>2</id>
<firstName>John</firstName>
<lastName>Mclane</lastName>
<income>200. 0</income>
</employee>
Is there a way to achieve this with Jaxb classes or any other java to xml libraries ? Also is there a way to unmarshall the same back to java POJO?
I tried to marshall a list as is but it just gave out an
If I tried to create a wrapper class and then marshall it, it would just add the wrapper
Code:
@XmlRootElement(name = "employees")
@XmlAccessorType (XmlAccessType.FIELD)
public class Employees
{
@XmlElement(name = "employee")
private List<Employee> employees = null;
}
Output:
< ?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<employees>
<employee>
<id>l </id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<income>100. 0</income>
</employee>
<employee>
<id>2</id>
<firstName>John</firstName>
<lastName>Mclane</lastName>
<income>200. 0</income>
</employee>
</employees>
Upvotes: 0
Views: 124
Reputation: 476
Although JAXB requires a top level XML element, it does not require the immediate, physical container to be a file. The message can be unmarshaled as an input stream from anywhere. We can use this observation to contain each XML message in its own Base64
stream which can then be stored as a list of streams (line-by-line) in one meta-container file.
This example reads each line of an input file as a Base64
encoded stream. Each encoded line contains one Employee
XML element; thus, each line can be unmarshaled and put into a list of Employee
objects. Also, the object list can be marshaled, encoded and stored as a single file.
This is a stand-alone Maven project (zip). You can run the test using:
mvn -Ptest clean test
The output shows the test results.
This Maven project includes:
Employee
modelEmployee
data.hisrc-higherjaxb-maven-plugin
Employees
src
main
java
resources
employee.xjb
employee.xsd
test
java
org/example/employee/EmployeeTest.java
resources
simplelogger.properties
samples
Employee1.xml
Employee2.xml
Employees.b64
pom.xml
The JAXB classes are generated by this plugin in this project's pom.xml
<plugin>
<groupId>org.patrodyne.jvnet</groupId>
<artifactId>hisrc-higherjaxb-maven-plugin</artifactId>
<version>${hisrc-higherjaxb-maven-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
and are generated to:
target/generated-sources/xjc/
org.example.employee
Employee.java
ObjectFactory.java
The JUnit test class, EmployeeTest, scans for the sample files and invokes the method checkSample(File sample)
to provide each file to the tester. For this project, a JAXBContext
is created and each file in the samples path is unmarshaled to an employee
object. When successful, the employee
object is marshaled for logging and your review.
In particular, the data file Employees.b64 demonstrates how a list of XML streams can be stored in one file. The sample file contains two Base64 encoded streams, each on its own line; but, there can be any number of such lines, each representing an XML stream that JAXB can unmarshal.
This code fragment from EmployeeTest
shows how a data source file can be read line-by-line to decode and unmarshal the Employee
data. Then, in reverse, each Employee
object is marshaled and encoded before writing the list to a target file.
EmployeeTest#testEmployees()
...
// Read Source
try ( FileReader fr = new FileReader(employeesB64Source) )
{
LineNumberReader lnr = new LineNumberReader(fr);
String employeeB64 = null;
while ( (employeeB64 = lnr.readLine()) != null )
{
String employeeXml = new String(decoder.decode(employeeB64), UTF_8);
Object root = unmarshaller.unmarshal(new StringReader(employeeXml));
if ( root instanceof Employee )
employeeList.add((Employee) root);
}
}
...
...
// Write Target
try ( FileWriter fw = new FileWriter(employeesB64Target) )
{
for ( Employee employee : employeeList )
{
String employeeXml = null;
employeeXml = marshalToString(employee, marshaller);
String employeeB64 = encoder.encodeToString(employeeXml.getBytes(UTF_8));
fw.write(employeeB64 + nl);
}
}
As a bonus, the Linux Bash base64
command can be used to quickly decode all lines in the b64 file:
Bash Shell
$ base64 --decode Employees.b64
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<id>1</id>
<firstName>Lokesh</firstName>
<lastName>Gupta</lastName>
<income>100.0</income>
</employee>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<id>2</id>
<firstName>John</firstName>
<lastName>Mclane</lastName>
<income>200.0</income>
</employee>
Upvotes: 0