Welcome to the Joint-Venture Blog from Fabio Cortesi and Stefan Jäger.
Generics are very useful. But sometimes, they don’t fullfil all required needs. Today, I had a small problem. Over the parameter of a method, a Class definition was passed. In the method, I had to cast an object of type Object into a concrete type (the concrete type was T, defined by Generics). The easiest way is to put the cast between a try and catch block. This will work, no question. But in my piece of code, a try and catch block wasn’t very nice. For this reason, I tried to check, if the object o is of the type clazz. Unfortunately, instanceof doesn’t work with dynamic defined classes. But there is a simple solution: just use the method isAssignableFrom.
private void test(Class<?> clazz) { // the Object o is from somewhere... if (o instanceof clazz) { // does not working } if (o.getClass().isAssignableFrom(clazz)) { // is working } }
I just found a really good Quick Reference sheet about the Design Patterns from the GoF (Gang of Four). Have a look at this blog.
Today I stumbled upon a nice solution, to use the Collections.EMPTY_LIST with Generics. Just use the method emptyList with Generics instead of the constant value.
For example:
Collections.<string> emtpyList();
We use JiBX in our current project and had the problem, that JiBX won’t trim whitespaces automatically. For example, a XML tag like <test> asdf </test> get’s stored as “ asdf “ instead of “asdf”.
To solve this problem, we created an user-defined formatter for Strings.
package ch.stefanjaeger.formatter; public class StringFormatter { public static String trimString(String untrimmed) { return untrimmed.trim(); } }
Now just update the binding file of JiBX and JiBX will trim whitespaces:
<format deserializer="ch.stefanjaeger.formatter.StringFormatter.trimString" type="java.lang.String" />
Are you a real men (or women)? Because if you are one, Eclipse offers you the possiblity to “don’t click”
Try to use the simple shortcut CTRL + 3. What happens? Eclipse opens the Quick access window:
Now, type what you want, for example “new xml file”, and Eclipse searches for the command, which consists of these words:
Also very interesting is the access to the Preferences window. Try to search for “classpath variables” or “build path”, you get direct access to these settings. Also interesting is “Generate Getters”. If you don’t know a specific shortcut, just use CTRL + 3 from now on!
This is the last hint this week. While working with JiBX, I had the situation, that there were some null values in the Java class.
JiBXTestApplication Exception in thread "main" org.jibx.runtime.JiBXException: null value for element "{http://stefanjaeger.ch/CustomerSchema}city" from object of type ch.stefanjaeger.jibx.Customer at org.jibx.runtime.impl.MarshallingContext.element(MarshallingContext.java:713) at ch.admin.bit.edec.common.declaration.Versandvorgang.JiBX_binding_marshal_1_0(Unknown Source) at ch.admin.bit.edec.common.declaration.Deklaration.JiBX_binding_marshal_1_0(Unknown Source) at ch.admin.bit.edec.common.declaration.JiBX_bindingDeklaration_access.marshal() at ch.admin.bit.edec.common.declaration.Deklaration.marshal(Unknown Source) at org.jibx.runtime.impl.MarshallingContext.marshalRoot(MarshallingContext.java:1041) at org.jibx.runtime.impl.MarshallingContext.marshalDocument(MarshallingContext.java:1111) at ch.admin.bit.test.jibx.JiBXTestApplication.main(Unknown Source)
Per default, JiBX doesn’t allow null values. If there is a null value, it throws an JiBXException while marshalling.
To allow null values, you have to define explicit the attribute usage="optional" on a value or structure element in the binding file. If JiBX finds a null pointer on a member, JiBX does not fill an empty value to the xml element, JiBX will skip the element.
To define a constant value in an output mapping, just use the attribute constant:
<value constant="hello world" name="theAttribute" />The XML attribute theAttribute get now always the value hello world.
I like to validate the binding XML file against a schema, to prevent typos and other mistakes. In the folder docs of the JiBX zip archive, there is the XML schema binding.xsd. Just use it like following:
<binding xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nonamespaceschemalocation="binding.xsd">
JiBX offers the possibility to create separate input and output bindings. Just use the attribute direction in the root element of the binding file. To create a XML binding just for the marshalling objects, use <binding direction="output">. To create an XML binding just for unmarhshalling XML files, use <binding direction="input">.
With this possibility, you can define for example an input binding, which doesn’t map every element of a XML file. But in the output binding you can define some constants, which get’s mapped, if objects gets marshaled to XML files.
JiBX is one of the fastest XML object mapping frameworks out there (check out this performance test). Furthermore, it is very flexible in binding XML structures to objects. In this blog post I will describe, how a basic JiBX project can be set up with Maven2. The focus of this entry is on getting in touch with JiBX (and a little bit with Maven).
To use JiBX in our project, we just have to add the dependency to our pom.xml. JiBX is fast, but to get it’s high performance, it uses byte code enhancement. For this reason, the byte code need’s to be edited by JiBX after the compilation phase. This is done with a Maven JiBX plugin, which is executed in the build phase “process-classes”.
Besides, I also wanted a JAR file, which contains all dependencies and has a defined main class (to which I will come to later). The creation of the JAR file is done with the Maven Assembly.
Check out the pom.xml for this test run.
After setting up the pom.xml, we can begin to develop a mapping example with Eclipse. JiBX has two main parts on which we have to focus, binding and the runtime part.
In the binding part, JiBX enhances the byte code (based on a binding definition) to enable the mapping between Java objects and a XML files. In the runtim part, the JiBX runtime components are used to perform the marshal (objects to XML) or unmarshal (XML to objects) tasks.
As you have seen in the pom.xml, the JiBX binding files should be located in src/main/jibx. The names of the JiBX files should end with -binding.xml.
Our goal is to map an XML file, based on following schema CustomerSchema.xsd:
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://stefanjaeger.ch/CustomerSchema" xmlns:sja="http://stefanjaeger.ch/CustomerSchema" elementFormDefault="qualified"> <element name="customer"> <complexType> <sequence> <element ref="sja:person" maxOccurs="1" /> <element ref="sja:city" maxOccurs="1" /> </sequence> </complexType> </element> <element name="person"> <complexType> <sequence> <element ref="sja:first-name" maxOccurs="1" /> <element ref="sja:last-name" maxOccurs="1" /> </sequence> </complexType> </element> <element name="first-name" type="string" /> <element name="last-name" type="string" /> <element name="city" type="string" /> </schema>
Our XML Customer1.xml file looks like:
<?xml version="1.0" encoding="UTF-8"?> <customer xmlns="http://stefanjaeger.ch/CustomerSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://stefanjaeger.ch/CustomerSchema CustomerSchema.xsd"> <person> <first-name>Stefan</first-name> <last-name>Jaeger</last-name> </person> <city>Davos Dorf</city> </customer>
We want to map the XML in the two objects Customer and Person (to simplify these lines of code, the getter, setter and toString methods are not described).
public class Customer { private Person person; private String city; } public class Person { private String firstName; private String lastName; }
To map the XML file to these classes, we create following binding definition. Because we use a XML schema, we have to define the namespace. Also the fully qualified name of the mapped class Customer need’s to be used. Because the class Person is in relation with the Customer class, JiBX recognizes automatically the fully qualified name of Person.
<?xml version="1.0" encoding="UTF-8"?> <binding> <mapping name="customer" class="ch.stefanjaeger.jibx.Customer"> <namespace uri="http://stefanjaeger.ch/CustomerSchema" default="elements"/> <structure name="person" field="person"> <value name="first-name" field="firstName" /> <value name="last-name" field="lastName" /> </structure> <value name="city" field="city" /> </mapping> </binding>
Now, we have a XML file, some Java classes and a binding between them. What we now need is an application, which does the unmarshalling of the XML file.
public class JiBXDemoApplication { public static void main(String[] args) throws Exception { IBindingFactory bfact = BindingDirectory.getFactory(Customer.class); IUnmarshallingContext uctx = bfact.createUnmarshallingContext(); Customer customer = (Customer) uctx.unmarshalDocument( new FileInputStream("Customer1.xml"), null); System.out.println(customer.toString()); } }
We are finished now. Just build the project with the command mvn package and let’s see, how the test run is working. Remember to place the XML schema and the XML file to the same location as the JAR file (after mvn package, it should be located in /target/).
The command
java -jar jibx_playground-1.0-SNAPSHOT-jar-with-dependencies.jar
results in
ch.stefanjaeger.jibx.Customer@12d03f9 [person=ch.stefanjaeger.jibx.Person@15dfd77 [firstName=Stefan,lastName=Jaeger] ,city=Davos Dorf]
I have to admit, that I did the same example with ANT. It tooks me a little bit longer… From today on, I’m a Maven fan
Download here the source code of this example. You only have to run mvn package to build the project.
Older Posts »