Monday, December 11, 2006

Java: JaxB Part 3 - Implementing JaxB Classes In Java

The third and final part of the JaxB article is here. Previously, I had created an XML schema using Eclipse Web Tools XML Schema Designer, then I used JaxB to create a set of Java classes for use inside of a Java project. So now comes the final part, the project itself…

Few things to note, then I will post the code. First, Eclipse, for some “odd” reason, would not recognize the JaxB generated files in my project folder until I Right-Mouse Clicked on the project, chose Go-Into, and then refreshed. Not sure what the deal was with that. Also, I had to add all the JAR files under the following directories:
C:\Sun\jwsdp-2.0\jwsdp-shared\lib
C:\Sun\jwsdp-2.0\jaxb\lib
C:\Sun\jwsdp-2.0\sjsxp\lib

But with that out of the way, I created a new Java Class called CreateXMLFileFromSystem in a package called com.digiassn.blogspot.filestructure.
The code is below:
package com.digiassn.blogspot.filestructure;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.GregorianCalendar;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;

public class CreateXMLFileFromSystem {

private static void populateFiles(final ObjectFactory factory, final Lfile parent) {
// Get the list of files in the current folder, and store in
// the files variable
final String[] files = new File(parent.getPath()).list();

// For each of the files, check if it is a directory, and add
// to the tree object
for (final String temp : files)
// Try statement added. Reason being, if the current file has
// special access permissions, Java does not handle correctly
// and causes a runtime exception and causes a stop in processing
try {
// Get current file
final File f = new File(parent.getPath() + "/" + temp);

// Create the local file based on our current file
final Lfile t = factory.createLfile();

// Set all attributes for the file
t.setName(f.getName());
t.setIsDirectory(f.isDirectory());
t.setPath(f.getPath());
t.setSize(f.length());

// Setting the time requires the use of the XMLGregorianCalendar
// object
// so here we will create a temporary gregoriancalendar
// and set up the XMLGregorian using the constructor that
// supports
// Gregorian calendar
final GregorianCalendar tempDate = new GregorianCalendar();
tempDate.setTimeInMillis(f.lastModified());

t.setDateLastUpdate(DatatypeFactory.newInstance()
.newXMLGregorianCalendar(tempDate));

// Check if it is a directory
if (f.isDirectory()) {
// If this is a directory, it will have
// sub directories, so add a new
// FilesInFolder object
t.subFiles = factory.createFilesInFolder();

// Make a recursive call, populating LFile with
// all child directories
populateFiles(factory, t);
}

// Go ahead and add to the parent
parent.getSubFiles().getFiles().add(t);
} catch (final DatatypeConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (final RuntimeException e) {
// Do nothing
}
}

public static void main(final String[] args) {
try {
// Setup the JAXBContent and Marshaller
final JAXBContext jcontext = JAXBContext
.newInstance("com.digiassn.blogspot.filestructure");
final Marshaller m = jcontext.createMarshaller();

// Setup the file objects for outputting to our XML file
final File xmlOutput = new File("fileList.xml");
final FileOutputStream outputFile = new FileOutputStream(xmlOutput);

// Create the factory object that will instantiate the JAXB created
// XML handler objects
final ObjectFactory factory = new ObjectFactory();

// Create the JAXB generated classes
final FilesInFolder root = factory.createFilesInFolder();
final Lfile currentFile = factory.createLfile();

// Set our current file to the root of C and add a new FilesInFolder
// object to the subfiles variable since we will "always" have
// subfiles
// and folders in the root of C
currentFile.setName("C:/");
currentFile.setPath("C:/");
currentFile.setIsDirectory(Boolean.TRUE);
currentFile.setReadOnly(Boolean.FALSE);
currentFile.setSize(0);
currentFile.subFiles = factory.createFilesInFolder();

// Start the recursive function calls on our current file. Once complete,
//The currentfile will have all child entries populated in the object
populateFiles(factory, currentFile);

// Add the C:/ file entry and all subsequent child nodes to the
// root element FilesInFolder object in the JaxB class
root.getFiles().add(currentFile);

// Create the JAXB handler and put the Root file as the initial
// constructingg XML element. Since it has already been built, we
// do not need to do anything else
final JAXBElement<FilesInFolder> ds = factory
.createDirectoryStructure(root);

// Set the Formatted Output option to true (trust me, after sitting
// for over an hour and having to increase the JVM heap to over a
// gig just
// to get Eclipses XML editor to even open this file, its easier to
// set formatted output and open in the much less memory hungry VI
// to confirm
// propert output
//
// Once that property is set, write out the file.
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(ds, outputFile);
} catch (final FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (final JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}



As you can see, using JaxB is incredibly easy. For an example like this, however, the resulting file was huge, in the area of 80 Megs to list my file structure. Perhaps XML is not the best format to store that information, but since it is structured it does provide a good example. Opening the resulting file in Eclipse, however, crashed Eclipse with a Out of Heap error, which caused me to have to up the heap space in Eclipse to view the file using the XML viewer. Notice I use the JAXB_FORMATTED_OUTPUT option in the marshaller. The reason being, opening that file in VI proved to be a better option than using Eclipse, and without the Formatted Output option, I ended up with a huge XML file all run together on one line.

No comments: