Archive for July, 2013

JAXB – PART 3 : (un)marshalling xml file with DOCTYPE declaration

Although many XML files have a DOCTYPE declaration, browsing the internet and my safary library account haven´t helped that much to unmarshall (and marshall) my mbeans descriptors with JAXB. It tooks me several hours to find a way out.
Supposing that the xml root element is called “Bean”, you can get the header, simply converting the xml file in a string and taking all the content until the first root element tag (). This might be very useful if you want to scan a folder in which the xml files have different headers (like jboss services configurationes ones).

	public static String getHeader(String filePath) {

		String header = "";
		String xmlContent = "";
		int headerLastIndex = 0;

		File file = new File(filePath);

		String text = "";
		try {
			text = FileUtils.readFileToString(file, "UTF-8");

			headerLastIndex = text.indexOf("<mbean>");
			header = text.substring(0, headerLastIndex);

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return header;

	}
	public static void marshaller(Mbean mbean, String filePath, String header)
			throws CustomizerException {

		stringWriter = new StringWriter();

		File file = new File(filePath);
		try {

			jaxbContext = JAXBContext.newInstance(Mbean.class);

			fileWriter = new FileWriter(file);

			marshaller = jaxbContext.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);

			marshaller.marshal(mbean, stringWriter);

			System.out.println(stringWriter.toString());

			fileWriter.write(header+stringWriter.toString());

			fileWriter.flush();
			fileWriter.close();

		} catch (MarshalException ex) {

			throw new CustomizerException("Marshalling the file: " + filePath
					+ "not possible. Wrong file content");

		} catch (JAXBException e) {

			throw new CustomizerException("Could not parse the XML file: "
					+ filePath);

		} catch (IOException e) {

			throw new CustomizerException("Couldn´t access the file: "
					+ filePath);
		}

		finally {

			try {
				fileWriter.close();
			} catch (IOException e) {

				throw new CustomizerException(
						"Couldn´t close the fileWriter for: " + filePath);
			}
		}

	}

I would like to make it in a better way with JAXB, but I think that the second version is still a bit raw. Currently there are no unmarshalling properties provided. You can invoke the method setProperty(java.lang.String name, java.lang.Object value), but there are still no properties provided by the API. I would like to contribute to the project…

JAXB – TEAM EXAMPLE – PART 2: Marshalling to console and to file

In the following java class you can see how to marshal an xml file from an xsd schema to the output console and to a brand new file.
Let´s consider the example that I showed you in the PART 1.

package de.team;

import java.awt.List;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;


public class TeamMarshalling {

	/**
	 * @param args
	 * @throws JAXBException
	 * @throws IOException 
	 */
	public static void main(String[] args) throws JAXBException, IOException {

		// JAXBContext jaxbContext = JAXBContext.newInstance(Team.class);

		String path = "/home/laura/";
		File f_ = new File(path);
		f_.mkdirs();

		// make new file
		FileWriter filewriter = new FileWriter(path + "SoftwareTeam.xml");

		JAXBContext jaxbContext = JAXBContext
				.newInstance(new Class[] { Team.class });

		Marshaller marshaller = jaxbContext.createMarshaller();
		
		StringWriter stringWriter = new StringWriter();
		
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);


		Team team = new Team();
		
		ArrayList<Member> memberList = new ArrayList<Member>();

		team.setCategory("developer");

		Member member1 = new Member();
		member1.setRole("junior");
		member1.setValue("Laura");

		Member member2 = new Member();
		member2.setRole("senior");
		member2.setValue("Mike");

		memberList.add(member1);
		memberList.add(member2);
		
                team.member= memberList;

                //marshal to output console --------------------------

                marshaller.marshal(team, stromgWriter);

                System.out.printlnstring(Wwriter.toString());

                //marshal to file ------------------------------------
	        fileWriter.write(stringWriter.toString());
			
	        fileWriter.close();

	}

}

The output is the following:

<team category="developer">
    <Member role="junior">Laura</Member>
    <Member role="senior">Mike</Member>
</team>

Resource leaks in Java: FileWriter not closing issue

In the following method example you can see a correct way to handle a resource leak. By putting it all in a try-catch block, the catch list (shown below) would cause the warning message “Resource leak: ‘FileWriter’ is not closed at this location” for the Marshal and JAXB exceptions.

try { 
...
fileWriter.close();
} 
catch (MarshalException ex) {

		} catch (JAXBException e) {

		} catch (IOException e) {

		}

To suppress the warning (and the Resource leak), you can add a finally statement which will try to close the fileWriter anyway with a nested try-catch block.
The following example method might be helpful:

public static void marshaller(JAXBContext jaxbContext, Bean bean,
			String newPath) {

		StringWriter writer = new StringWriter();
		FileWriter fileWriter = null; // = new FileWriter(newPath);

		try {

			fileWriter = new FileWriter(newPath);

			Marshaller marshaller = jaxbContext.createMarshaller();

			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
			marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);

			marshaller.marshal(bean, writer);

			fileWriter.write(writer.toString());

			fileWriter.close();

		} catch (MarshalException ex) {
                  e.getMessage();
		} catch (JAXBException e) {
                 e.getMessage();
		} catch (IOException e) {
                e.getMessage();		
                }

		finally {
			try {
				fileWriter.close();
			} catch (IOException e) {
				e.getMessage();
			}
		}
	}

Generating JAXB classes from a xsd schema in a Maven project

If you want to geenrate JAXB classes from a xsd schema in a Maven project, you need to specify the dependencies for jaxb and the plugin.

The pom.xml file is like the following:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>de.demo.maven.jaxb</groupId>
	<artifactId>MAVEN_JAXB_DEMO</artifactId>
	<version>0.0.1-SNAPSHOT</version>

<dependencies>
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.2.5</version>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.2.5</version>
</dependency>
</dependencies>
	
 <build>
    <plugins>
        <!-- JAXB xjc plugin that invokes the xjc compiler to compile XML schema into Java classes.-->
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>jaxb2-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>xjc</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <!-- The schema directory or xsd files. -->
                <schemaDirectory>${basedir}/src/main/resources</schemaDirectory>
                <!-- The package in which the source files will be generated. -->
                <packageName>de.demo.team</packageName>
                <!-- The working directory to create the generated java source files. -->
                <outputDirectory>${basedir}/src/main/java</outputDirectory>
            </configuration>
        </plugin>
    </plugins>
  </build>
	
</project>

in the configuration tags you need to specify “schemaDirectory” (the location of the .xsd file) and in the “outputDirectory” the destination folder for the generated classes.

First of all you need to run the maven compile command. Then you can generate the JAXB classes: in eclipse, for example, you can right-click on the project and run New>Other>JAXB>”JAXB Classes from a Schema”.
Of course you need to add the Eclipse plugin first.

Eclipse won´t generate automatically the @XmlRootElement annotation. You will have to add it on your own, like this:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MBean", propOrder = {
    "attribute"
})
@XmlRootElement
public class MBean {
...
}

JAXB – TEAM EXAMPLE – PART 1: XSD schema with root attribute and child element with attribute and value

In this post I will show you how to represent an XSD schema with root attribute and child element with attribute and value. For example, let´s consider a software development team:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<team category="software development">
    <Member role="junior">Laura</Member>
    <Member role="senior">Erik</Member>
    <Member role="graduate">Mike</Member>
</team>

The xsd schema generally represent a a working team :

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://acme.com/schema/type/team/v1" xmlns:team="http://acme.com/schema/type/team/v1"
	xmlns:company="http://acme.com/schema/type/company/v1"
	elementFormDefault="qualified">

	<xsd:element name="Team" type="team:Team" />

	<xsd:complexType name="Team">
		<xsd:annotation>
			<xsd:documentation>Represents a working team </xsd:documentation>
		</xsd:annotation>
		<xsd:sequence maxOccurs="unbounded">
			<xsd:element name="Member">
				<xsd:complexType>
					<xsd:simpleContent>
						<xsd:extension base="xsd:string">
							<xsd:attribute name="role" type="xsd:string" />
						</xsd:extension>
					</xsd:simpleContent>
				</xsd:complexType>
			</xsd:element>
		</xsd:sequence>
		<xsd:attribute name="category" type="xsd:string" />
	</xsd:complexType>
</xsd:schema>

Although it seems to be a typical case, I have spent several hours reading books, tutorials and forum, trying to map a web service xml file with such a structure.
I have finally found the solution on a google forums post.

A better solution would be using the type attribute and make a separate “complexType” tag, because in this way JAXB would be able to create a different bean class for each element (also the nested ones). So an equivalent version of the schema is the following:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://acme.com/schema/type/team/v1" xmlns:team="http://acme.com/schema/type/team/v1"
	xmlns:company="http://acme.com/schema/type/company/v1"
	elementFormDefault="qualified">

	<xsd:element name="Team" type="team:Team" />

	<xsd:complexType name="Team">
		<xsd:annotation>
			<xsd:documentation>Represents a working team </xsd:documentation>
		</xsd:annotation>
		<xsd:sequence>
			<xsd:element name="Member" type="team:member" minOccurs="0"
				maxOccurs="unbounded" />
		</xsd:sequence>
		<xsd:attribute name="category" type="xsd:string" />
	</xsd:complexType>
	
	<xsd:complexType name="member">
		<xsd:simpleContent>
			<xsd:extension base="xsd:string">
				<xsd:attribute name="role" type="xsd:string" />
			</xsd:extension>
		</xsd:simpleContent>
	</xsd:complexType>

</xsd:schema>

In eclipse, downloading the “m2e conntector for jaxb” plugin, you can automatically generate all the object classes from your XSD schema (in the menu bar menu you can find the JAXB section under File>New>…). Without a binding file, you will have to add the “@XmlRootElement” annotation on the top of your root element class and also delete the namespace in the package-info class. I will tell you more in the next posts…

Categories
Links: