JAXB2 Basics Runtime
Strategies
If you use JAXB2 Basics Plugins to enhance your schema-derived classes with toString(...), equals(...), hashCode(...) and further utility methods, you will see that generated classes implement some additional interfaces like org.jvnet.jaxb2_commons.lang.ToString, org.jvnet.jaxb2_commons.lang.Equals, org.jvnet.jaxb2_commons.lang.HashCode etc.
These interfaces allow objects to accept and use additional strategy and locator objects. For instance org.jvnet.jaxb2_commons.lang.Equals defines the following method:
public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator, Object that, EqualsStrategy equalsStrategy);
With this approach you can customize how exactly equality (string conversion, hash code calculation etc.) is handled by providing your own strategy.
JAXB2 Basics Runtime package implements default strategies suitable for schema-derived classes. These strategies are somewhat inspired by the Commons Lang builders, but also handle the specifics of JAXB objects (like JAXBElement or DOM nodes). A big difference from Commons Lang implementation is that strategies in JAXB2 Basics are stateless (whereas Commons Lang builders are stateful) which our strategies much more suitable for performance-critical scenarios.
Since schema-derived classes augmented by JAXB2 Basics Plugins implement interfaces and use strategy classes from JAXB2 Basics Runtime, generated code will have compile and runtime dependency on JAXB2 Basics Runtime package. This means that you will need to include JAXB2 Basics Runtime into your compile and runtime classpaths.
If you are using Maven, you'll simply need to add the following dependency:
<dependency> <groupId>org.jvnet.jaxb2_commons</groupId> <artifactId>jaxb2-basics-runtime</artifactId> <version><!-- Current version --></version> </dependency>
If you're not using Maven, include the following JARs:
- jaxb2-basics-runtime-*.jar
| Since 0.5.3 JAXB2 Basics Runtime does not depend on commons-lang. |
| JAXB2 Basics Runtime interfaces were changed between 0.5.2 and 0.5.3. |
Locators
| Since 0.5.3. |
Strategies allow you to customize, how equality, hash code calculation, copying and so on is handled. However, in many cases you also need to consider the location of things you compare (copy, calculate hash code for and so on).
With the version 0.5.3 JAXB2 Basics Runtime introduced the Object Locators API which models the location of objects within your JAXB object structure. These locators are provided to strategies thus allowing strategies to consider location of the data they are working with.
Let's take a look at a couple of examples - based on the equality operation. The simplest usage is as follows:
a.equals(b);
Pure Object.equals(...), no strategies, no locators. Now consider that we want to compare strings case-insensitive. If a and b implement the Equals interface, we can write an own equality strategy for this:
a.equals(null, null, b, new DefaultEqualsStrategy() { public boolean equals(ObjectLocator leftLocator, ObjectLocator rightLocator, Object left, Object right) { if (left instanceof String && right instanceof String) { return ((String) left).equalsIgnoreCase((String) right); } else { return super.equals(leftLocator, rightLocator, left, right); } }; });
Now all of our strings will be compared in a case-insensitive way. Note that we've passed null locators - as long as we don't care about location of the data we work with, we don't care about locators at all.
But now assume we only need to compare "name" properties of our objects case-insensitively and all the rest - normally. In this case we also need to know, where we're comparing, not just what. We'll need something which tells us "you're now in property 'name' of certain object". This "something" is a locator. Here's how our specific strategy would look like:
public class CaseInsensitiveNameStrategy extends DefaultEqualsStrategy { public boolean equals(ObjectLocator leftLocator, ObjectLocator rightLocator, Object left, Object right) { if (leftLocator instanceof PropertyObjectLocator && rightLocator instanceof PropertyObjectLocator && "name".equals(((PropertyObjectLocator) leftLocator) .getPropertyName()) && "name".equals(((PropertyObjectLocator) rightLocator) .getPropertyName()) && left instanceof String && right instanceof String) { return ((String) left).equalsIgnoreCase((String) right); } else { return super.equals(leftLocator, rightLocator, left, right); } } }
Now we'll also need to provide the "starting" locators of the objects we compare:
a.equals(new DefaultRootObjectLocator(a), new DefaultRootObjectLocator(b), b, new CaseInsensitiveNameStrategy());
Methods generated by the JAXB2 Basics plugins use the "starting" locators to produce "child" locators for the properties being processed:
public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator, Object object, EqualsStrategy strategy) { if (!(object instanceof MyType)) { return false; } if (this == object) { return true; } final MyType that = ((MyType) object); { String lhsName; lhsName = this.getName(); String rhsName; rhsName = that.getName(); if (!strategy.equals(LocatorUtils.property(thisLocator, "name", lhsName), LocatorUtils.property(thatLocator, "name", rhsName), lhsName, rhsName)) { return false; } } return true; }
If starting locators (thisLocator and thatLocator in the fragment above) are null, then LocatorUtils.property(...) also return null - location information is simply ignored.
Javadocs
Javadoc for JAXB2 Basics Runtime can be found here:
http://static.highsource.org/jaxb2-basics/jaxb2-basics-runtime/apidocs/index.html