Generate Report XML file Using JAXB
Description of problem: Write java program that should identify vehicle by its type and components. Vehicle type should be identified by its properties i.e. power train, wheels material, number of wheels and frame material.
Java method will take XML file as input that XML file will contain vehicles record also it should be reproduce as well to xml file. Output of the report should be that lists each vehicle id with its type. Report should also provide summary how many vehicles of each type was there in xml file.
Please also write JUnit test for this.
Known Vehicles types by its Characteristics:
Use below table as basis for vehicle identification. Table indicates unique characteristics of the known vehicle types.
Vehicle Type | Frame | Powertrain | Wheels |
Big Wheel | plastic | Human | 3 plastic (front, rear left, rear right) |
Bicycle | metal | Human | 2 metal (front, rear) |
Motorcycle | metal | Internal Combustion | 2 metal (front, rear) |
Hang Glider | plastic | Bernoulli | none |
Car | metal | Internal Combustion | 4 (front right, front left, rear right, rear left) |
Solution:
Tools needed: JAVA 1.6 or up or if you are using JAVA 1.5 include JAXB.jar in your classpath.
Solution description: There are many ways to generate report of given XML file using java program below are some options which can be used to generate report:
- DOM Parser
- Castor
- JIBX
- Apache Digester
- XStream
- XMLBean
- javax.xml.bind.Marshaller and javax.xml.bind.Unmarshaller
- SAX Parser
- XPATH (XML path language)
- JAXB (Preferred)
Explanation: JAXB provide standard approach to convert XML to Java or Java to XML. Below are some points why I have used JAXB in place of others:
- Supports XML document manipulation using object API
- Memory wise its more efficient than DOM
- Its bi-directional
- You don’t need schema: directly you could use annotation in the class to create java object.
- You could access and process without knowing much about XML file
- It’s included in Java 1.6 so you don’t need any extra library to process XML file. If you are using
- Java < 1.6 version then you need only one jar JAXB.jar in your classpath
- Easy to use.
- Directly un-marshal and marshal XML data to java object vice versa.
- Compatibility with XML based web service: JAXB is default binding layer on JAX-WS
- Compatibility with RESTFul web service: JAXB is default binding layer and very easy to use with JAX-RS
- Compatibility with spring: Spring has built in support of XML binding tools and it has used JAXB in all implementations.
Java program solution:
Sample XML file:
<?xml version="1.0" encoding="UTF-8"?> <vehicles> <vehicle> <id>vehicle 1</id> <frame> <material>plastic</material> </frame> <powertrain> <human>Human</human> </powertrain> <wheels> <wheel> <position>rear right rear</position> <material>plastic</material> </wheel> <wheel> <position>front</position> <material>plastic</material> </wheel> <wheel> <position>rear left</position> <material>plastic</material> </wheel> </wheels> </vehicle> <vehicle> <id>vehicle 2</id> <frame> <material>metal</material> </frame> <powertrain> <human>Human</human> </powertrain> <wheels> <wheel> <position>front</position> <material>plastic</material> </wheel> <wheel> <position>rear</position> <material>plastic</material> </wheel> </wheels> </vehicle> <vehicle> <id>vehicle 3</id> <frame> <material>metal</material> </frame> <powertrain> <human>Internal Combustion</human> </powertrain> <wheels> <wheel> <position>front</position> <material>metal</material> </wheel> <wheel> <position>rear</position> <material>metal</material> </wheel> </wheels> </vehicle> <vehicle> <id>vehicle 4</id> <frame> <material>plastic</material> </frame> <powertrain> <human>Bernoulli</human> </powertrain> </vehicle> <vehicle> <id>vehicle 5</id> <frame> <material>metal</material> </frame> <powertrain> <human>Internal Combustion</human> </powertrain> <wheels> <wheel> <position>front right</position> <material>metal</material> </wheel> <wheel> <position>front left</position> <material>metal</material> </wheel> <wheel> <position>rear right</position> <material>metal</material> </wheel> <wheel> <position>rear left</position> <material>metal</material> </wheel> </wheels> </vehicle> <vehicle> <id>vehicle 5</id> <frame> <material>metal</material> </frame> <powertrain> <human>Internal Combustion</human> </powertrain> <wheels> <wheel> <position>front right</position> <material>metal</material> </wheel> <wheel> <position>front left</position> <material>metal</material> </wheel> <wheel> <position>rear right</position> <material>metal</material> </wheel> <wheel> <position>rear left</position> <material>metal</material> </wheel> </wheels> </vehicle> </vehicles>
Steps:
- Create Maven project name: GenerateReportFromXMLByJAXB
- Create bean class: Frame.java, Powertrain.java, Vehicle.java, Vehicles.java, Wheel.java, Wheels.java all class included in project and you could download it from bottom link
- Create class ParseXMLGenerateReport.java using JAXB to parse and read XML file:
package com.javahonk; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.List; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import com.javahonk.bean.Powertrain; import com.javahonk.bean.Vehicle; import com.javahonk.bean.Vehicles; import com.javahonk.bean.Wheel; import com.javahonk.bean.Wheels; public class ParseXMLGenerateReport { public static String generateReportFromXMLToFileAndConsole( String xmlFilePath, String reportFilePath) { BufferedWriter bw = null; String fileProcessMessage = "\n\nFile processed successfully"; try { if (null == xmlFilePath && null == reportFilePath) return "XML and Report file is null"; if (null == xmlFilePath) return "XML file is null"; if (null == reportFilePath) return "Report file is null"; if (null != xmlFilePath && null != reportFilePath && xmlFilePath.trim().equalsIgnoreCase("") && reportFilePath.trim().equalsIgnoreCase("")) return "XML and Report file is empty"; if (null != xmlFilePath && xmlFilePath.trim() .equalsIgnoreCase("")) return "XML file is empty"; if (null != reportFilePath && reportFilePath.trim().equalsIgnoreCase("")) return "Report file is empty"; File writeReportToFile = new File(reportFilePath); if (!writeReportToFile.exists()) { writeReportToFile.createNewFile(); } FileWriter fw = new FileWriter(writeReportToFile .getAbsoluteFile()); bw = new BufferedWriter(fw); File file = new File(xmlFilePath); JAXBContext jaxbContext = JAXBContext .newInstance(Vehicles.class); Unmarshaller jaxbUnmarshaller = jaxbContext .createUnmarshaller(); Vehicles vehicles = (Vehicles) jaxbUnmarshaller .unmarshal(file); List<Vehicle> vehicles1 = vehicles.getVehiclesList(); int bigWheel = 0; int bicycle = 0; int motorcycle = 0; int hangGlider = 0; int car = 0; System.out.println("Each vehicle id and its " + "type report\n"); bw.write("Each vehicle id and its type report\n\n"); if (null != vehicles1) { for (Vehicle vehicle : vehicles1) { String id = vehicle.getId(); String frameMaterial = vehicle.getFrame() .getMaterial(); String powertrainValue = null; String wheelMaterial = null; int noOfWheel = 0; List<Powertrain> powertrainsList = vehicle .getPowertrainsList(); for (Powertrain powertrain : powertrainsList) { powertrainValue = powertrain.getHuman(); } List<Wheels> wheels = vehicle.getWheelsList(); if (null != wheels) { for (Wheels wheels2 : wheels) { noOfWheel = wheels2.getWheelsList().size(); List<Wheel> wheels3 = wheels2.getWheelsList(); for (Wheel wheel : wheels3) { wheelMaterial = wheel.getMaterial(); } } } if (frameMaterial.equalsIgnoreCase("plastic") && powertrainValue.equalsIgnoreCase("Human") && wheelMaterial.equalsIgnoreCase("Plastic") && noOfWheel == 3) { bigWheel++; System.out.println("Vehicle Id: " + id + " Vehicle Type: Big Wheel"); bw.write("Vehicle Id: " + id + " Vehicle Type: Big Wheel\n"); } if (frameMaterial.equalsIgnoreCase("metal") && powertrainValue .equalsIgnoreCase("Human") && wheelMaterial .equalsIgnoreCase("Plastic") && noOfWheel == 2) { bicycle++; System.out.println("Vehicle Id: " + id + " Vehicle Type: Bicycle"); bw.write("Vehicle Id: " + id + " Vehicle Type: Bicycle\n"); } if (frameMaterial.equalsIgnoreCase("metal") && powertrainValue .equalsIgnoreCase("" + "Internal Combustion") && wheelMaterial.equalsIgnoreCase("metal") && noOfWheel == 2) { motorcycle++; System.out.println("Vehicle Id: " + id + " Vehicle Type: Motorcycle"); bw.write("Vehicle Id: " + id + " Vehicle Type: Motorcycle\n"); } if (frameMaterial.equalsIgnoreCase("plastic") && powertrainValue .equalsIgnoreCase("Bernoulli") && noOfWheel == 0) { hangGlider++; System.out.println("Vehicle Id: " + id + " Vehicle Type: Hang Glider"); bw.write("Vehicle Id: " + id + " Vehicle Type: Hang Glider\n"); } if (frameMaterial.equalsIgnoreCase("metal") && powertrainValue .equalsIgnoreCase("Internal Combustion") && wheelMaterial.equalsIgnoreCase("metal") && noOfWheel == 4) { car++; System.out.println("Vehicle Id: " + id + " Vehicle Type: Car"); bw.write("Vehicle Id: " + id + " Vehicle Type: Car\n"); } } } else { bw.write("No matching vehicle found"); fileProcessMessage = "No matching vehicle found"; return fileProcessMessage; } if (bigWheel == 0 && bicycle == 0 && motorcycle == 0 && hangGlider == 0 && car == 0) { bw.write("No matching vehicle found"); fileProcessMessage = "No matching vehicle found"; return fileProcessMessage; } else { System.out.println("\nType of vehicle summary\n"); System.out.println("Total no of vehicle: " + (bigWheel + bicycle + motorcycle + hangGlider + car) + "\n"); System.out.println("Big Wheel: " + bigWheel); System.out.println("Bicycle: " + bicycle); System.out.println("Motorcycle: " + motorcycle); System.out.println("Hang Glider: " + hangGlider); System.out.println("Car: " + car); bw.write("\nType of vehicle summary\n\n"); bw.write("Total no of vehicle: " + (bigWheel + bicycle + motorcycle + hangGlider + car) + "\n\n"); bw.write("Big Wheel: " + bigWheel + "\n"); bw.write("Bicycle: " + bicycle + "\n"); bw.write("Motorcycle: " + motorcycle + "\n"); bw.write("Hang Glider: " + hangGlider + "\n"); bw.write("Car: " + car + "\n"); } } catch (JAXBException e) { fileProcessMessage = e.getCause().toString(); return fileProcessMessage; } catch (IOException e) { fileProcessMessage = e.getCause().toString(); } finally { try { if (null != bw) bw.close(); } catch (IOException e) { e.printStackTrace(); } } return fileProcessMessage; } }
- Create class XMLToJava.java to convert and generate report both on console and file.
package com.javahonk; public class XMLToJava { public static void main(String[] args) { String xmlFilePath = "src\\main\\resources\\vehicles.xml"; String reportFilePath = "VehicleReport.txt"; String status = ParseXMLGenerateReport .generateReportFromXMLToFileAndConsole(xmlFilePath, reportFilePath); System.out.println(status); } }
- Create class JavaToXML.java which will convert java object to same vehicles.xml file:
package com.javahonk; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import com.javahonk.bean.Frame; import com.javahonk.bean.Powertrain; import com.javahonk.bean.Vehicle; import com.javahonk.bean.Vehicles; import com.javahonk.bean.Wheel; import com.javahonk.bean.Wheels; public class JavaToXML { public static void main(String[] args) { try { Vehicle vehicle = new Vehicle(); vehicle.setId("Vehicle 1"); Frame frame = new Frame(); frame.setMaterial("Metal"); vehicle.setFrame(frame); Powertrain powertrain = new Powertrain(); powertrain.setHuman("Human"); List<Powertrain> powertrainList = new ArrayList<Powertrain>(); powertrainList.add(powertrain); vehicle.setPowertrainsList(powertrainList); Wheels wheels = new Wheels(); List<Wheels> wheelsList = new ArrayList<Wheels>(); Wheel wheel = new Wheel(); wheel.setMaterial("Metal"); wheel.setPosition("right rear"); List<Wheel> wheelList = new ArrayList<Wheel>(); wheelList.add(wheel); wheels.setWheelsList(wheelList); wheelsList.add(wheels); vehicle.setWheelsList(wheelsList); Vehicles vehicles = new Vehicles(); List<Vehicle> vehicleList = new ArrayList<Vehicle>(); vehicleList.add(vehicle); vehicles.setVehiclesList(vehicleList); JAXBContext jaxbContext = JAXBContext .newInstance(Vehicles.class); Marshaller jaxbMarshaller = jaxbContext .createMarshaller(); jaxbMarshaller.setProperty(Marshaller .JAXB_FORMATTED_OUTPUT, Boolean.TRUE); File XMLfile = new File("JavaToXMLVehicle"); jaxbMarshaller.marshal(vehicles, XMLfile); jaxbMarshaller.marshal(vehicles, System.out); } catch (JAXBException e) { e.printStackTrace(); } } }
- Create unit test class ParseXMLGenerateReportTest.java inside test folder:
package com.javahonk; import static org.junit.Assert.*; import org.junit.After; import org.junit.Before; import org.junit.Test; public class ParseXMLGenerateReportTest { String xmlFilePath = ""; String reportFilePath = ""; @Before public void setUp() throws Exception { xmlFilePath = "src\\main\\resources\\vehicles.xml"; reportFilePath = "VehicleReport.txt"; } @After public void tearDown() throws Exception { xmlFilePath = ""; reportFilePath =""; } @Test public final void testGenerateReportFromXMLToFileAndConsole() { String actualMessage = ParseXMLGenerateReport.generateReportFromXMLToFileAndConsole(null, null); assertEquals("XML and Report file is null", actualMessage); actualMessage = ParseXMLGenerateReport.generateReportFromXMLToFileAndConsole(xmlFilePath, null); assertEquals("Report file is null", actualMessage); actualMessage = ParseXMLGenerateReport.generateReportFromXMLToFileAndConsole(null, reportFilePath); assertEquals("XML file is null", actualMessage); actualMessage = ParseXMLGenerateReport.generateReportFromXMLToFileAndConsole("", ""); assertEquals("XML and Report file is empty", actualMessage); actualMessage = ParseXMLGenerateReport.generateReportFromXMLToFileAndConsole(xmlFilePath, ""); assertEquals("Report file is empty", actualMessage); actualMessage = ParseXMLGenerateReport.generateReportFromXMLToFileAndConsole("", reportFilePath); assertEquals("XML file is empty", actualMessage); xmlFilePath ="badFilePath"; actualMessage = ParseXMLGenerateReport.generateReportFromXMLToFileAndConsole(xmlFilePath, reportFilePath); assertEquals(actualMessage.indexOf("org.xml.sax.SAXParseException")!=-1, actualMessage.indexOf("org.xml.sax.SAXParseException")!=-1); } }
How to run report:
- Right click VehicleIdentifier.java class inside package com.adp.vehicleidentifier –> Run As –> Java Application
- Note: You will have to pass two parameter to generate report: xmlFilePath and reportFilePath
- Single operation generateReportFromXMLToFileAndConsole has been written to generate report both on console and file. Report will be generated in project root folder. Once you completed run report then refresh project to see generated file in project root folder (File name: VehicleReport.txt)
How to run JUnit report:
- Right click ModifiedCrudeVehicleParserTest.java class with package name com.adp.vehicleidentifier under src/test/java folder –> Run As –> JUnit Test
Report sample generate in file:
Download Project: GenerateReportFromXMLByJAXB
For more information please visit oralce JAXB tutorial
That’s it Generate Report XML file Using JAXB