JiBX is a binding framework which allows you to define a fairly complex mapping between an XML schema and your Java classes. This enables you to create a service that marshalls data between your pre-existing POJOs and documents that conform to an arbitrary XML schema. It's worth noting that you can also use the JiBX Generator tools to generate an XML schema and you can also do code generation from an XML schema to Java code using Xsd2Jibx. JiBX also has excellent performance compared to other binding frameworks; see the java.net bindmark project for more details. For more information on JiBX, try the official JiBX documentation.
JiBX and XFire
In this explanation of using the JiBX bindings with XFire, we'll start with an XML schema and some Java classes, and then describe how to define a mapping between them. Let's say you have some existing Java code which converts temperatures between Farenheit and Celsius, and you want to provide a service which converts weather reports given in one or other scale. You might decide that you want to utilise this pre-existing XML schema. The interesting part of this schema for us is the definition of the WeatherData type:
We also have our existing TemperatureConverter class
We also have an interface for our service and an implementation of it utilises the conversion code:
We also have a Weather class which our service interface uses to accept data and return the results:
Now we need to define the relationship between the Weather class and the WeatherData type defined in the XML schema. In JiBX, this is done using a binding definition; the binding definition for our service is given below. Since there is a close correspondence between our Weather class and the WeatherData XML type, this binding definition is pretty straightforward. JiBX allows far more flexibility and complexity in these definitions. We've set 'usage="optional"' on the temperature properties since the client need only set these values for one of the temperature scales.
The service definition for a JiBX service is like any other, except that you need to specify the use of "org.codehaus.xfire.jibx.JibxServiceFactory" as the service factory. For example, using Spring we would do the following:
Note that the values of the schema property (here "WeatherService.xsd") can be either a filepath or the path to a resource on the classpath. We need to ensure that we have run the JiBX compiler on the class files and binding definition. You can do this on the command line or using the JiBX Ant task, like so:
Here our class files are in the "classes" directory and the "jibx_bindings.xml" file contains the binding definitions. Note that the relevant classes on both the client and server side will need to be "JiBX compiled", so if you have separate compilation stages for your service and for your client, you'll probably need to run this Ant task during each of these. You can now deploy this service like any other, ensuring that the "WeatherService.xsd" schema is available to the service at runtime. The binding definitions file does not need to be deployed with your service or client. The client also has to use the JibxServiceFactory, so for example we could have the following Spring config:
Since the client and the service need to use the same service factory, it's normally useful to refactor the definition of the service factory out into a separate file which is imported by both the service and the client configurations.
In our client code, we would have something along the lines of:
And that's about it.
JiBX and JSR 181 Annotations
We can configure XFire to utilise JSR-181 annotations with JiBX bindings as follows. First, we add some annotations to our service interface and class
We now have to tell XFire to use the Web Annotations service factory with the JiBX type registry. With a Spring config, we can do this as follows:
We then need to configure the service to use this service factory:
We also need to configure the client to use this service factory. One thing to watch out for here is that we now need to configure the client to use the service implementation class as value of the 'serviceInterface' property (you might have to add this class to the compilation of the client code, since the client may not explicitly depend on it):