Object locator system for tracking navigation paths through object hierarchies. Essential for debugging, error reporting, and providing context during strategic operations. The locator system enables precise error reporting and supports JAXB validation integration.
Main interface that denotes a location in an object structure, extending both ValidationEventLocator and Reportable for comprehensive location tracking and reporting.
interface ObjectLocator extends ValidationEventLocator, Reportable {
ObjectLocator getParentLocator();
ObjectLocator[] getPath();
String getPathAsString();
PropertyObjectLocator property(String propertyName, Object propertyValue);
ItemObjectLocator item(int itemIndex, Object itemValue);
}interface RootObjectLocator extends ObjectLocator {
// Marker interface for root object locators
}
interface PropertyObjectLocator extends ObjectLocator {
String getPropertyName();
Object getObject();
}
interface ItemObjectLocator extends ObjectLocator {
int getIndex();
Object getObject();
}abstract class AbstractObjectLocator implements ObjectLocator {
protected AbstractObjectLocator(ObjectLocator parentLocator, Object object);
// ObjectLocator methods
public ObjectLocator getParentLocator();
public ObjectLocator[] getPath();
public String getPathAsString();
public Object getObject();
public ItemObjectLocator item(int index, Object value);
public PropertyObjectLocator property(String name, Object value);
// ValidationEventLocator methods (return default values)
public int getColumnNumber();
public int getLineNumber();
public int getOffset();
public URL getURL();
public Node getNode();
// Reportable methods
public String getMessageCode();
public String getMessage();
public String getMessage(ResourceBundle bundle);
// Abstract methods for subclasses
protected abstract String getStepAsString();
protected abstract String getDefaultMessage();
}final class DefaultRootObjectLocator extends AbstractObjectLocator implements RootObjectLocator {
public DefaultRootObjectLocator(Object rootObject);
public Object[] getMessageParameters();
}
final class DefaultPropertyObjectLocator extends AbstractObjectLocator implements PropertyObjectLocator {
protected DefaultPropertyObjectLocator(ObjectLocator parentLocator, String propertyName, Object propertyValue);
public String getPropertyName();
public Object[] getMessageParameters();
}
final class DefaultItemObjectLocator extends AbstractObjectLocator implements ItemObjectLocator {
protected DefaultItemObjectLocator(ObjectLocator parentLocator, int itemIndex, Object itemValue);
public int getIndex();
public Object[] getMessageParameters();
}final class LocatorUtils {
// SAX Locator formatting
static String getLocation(Locator locator);
// Null-safe property locator creation
static PropertyObjectLocator property(ObjectLocator parent, String name, Object value);
static PropertyObjectLocator property(ObjectLocator parent, String name, boolean value);
static PropertyObjectLocator property(ObjectLocator parent, String name, byte value);
static PropertyObjectLocator property(ObjectLocator parent, String name, char value);
static PropertyObjectLocator property(ObjectLocator parent, String name, double value);
static PropertyObjectLocator property(ObjectLocator parent, String name, float value);
static PropertyObjectLocator property(ObjectLocator parent, String name, int value);
static PropertyObjectLocator property(ObjectLocator parent, String name, long value);
static PropertyObjectLocator property(ObjectLocator parent, String name, short value);
// Null-safe item locator creation
static ItemObjectLocator item(ObjectLocator parent, int index, Object value);
static ItemObjectLocator item(ObjectLocator parent, int index, boolean value);
static ItemObjectLocator item(ObjectLocator parent, int index, byte value);
static ItemObjectLocator item(ObjectLocator parent, int index, char value);
static ItemObjectLocator item(ObjectLocator parent, int index, double value);
static ItemObjectLocator item(ObjectLocator parent, int index, float value);
static ItemObjectLocator item(ObjectLocator parent, int index, int value);
static ItemObjectLocator item(ObjectLocator parent, int index, long value);
static ItemObjectLocator item(ObjectLocator parent, int index, short value);
}import org.jvnet.jaxb2_commons.locator.*;
import org.jvnet.jaxb2_commons.locator.util.LocatorUtils;
// Create root locator for a customer object
Customer customer = new Customer();
customer.setName("John Doe");
customer.setAddress(new Address());
customer.getAddress().setStreet("123 Main St");
DefaultRootObjectLocator rootLocator = new DefaultRootObjectLocator(customer);
// Navigate to properties
PropertyObjectLocator nameLocator = rootLocator.property("name", customer.getName());
PropertyObjectLocator addressLocator = rootLocator.property("address", customer.getAddress());
PropertyObjectLocator streetLocator = addressLocator.property("street", customer.getAddress().getStreet());
// Get path information
System.out.println(streetLocator.getPathAsString());
// Output: <customer>.address.street
ObjectLocator[] path = streetLocator.getPath();
// Returns array: [rootLocator, addressLocator, streetLocator]import org.jvnet.jaxb2_commons.locator.util.LocatorUtils;
// Null-safe property creation (handles null parent gracefully)
ObjectLocator parentLocator = null; // or any ObjectLocator
PropertyObjectLocator safeLocator = LocatorUtils.property(parentLocator, "name", "John");
// Returns locator even if parent is null
// Primitive type handling with auto-boxing
PropertyObjectLocator intLocator = LocatorUtils.property(parentLocator, "age", 25);
PropertyObjectLocator booleanLocator = LocatorUtils.property(parentLocator, "active", true);
// Array/collection item tracking
List<String> items = Arrays.asList("first", "second", "third");
ObjectLocator listLocator = new DefaultRootObjectLocator(items);
for (int i = 0; i < items.size(); i++) {
ItemObjectLocator itemLocator = LocatorUtils.item(listLocator, i, items.get(i));
System.out.println(itemLocator.getPathAsString());
// Output: <list>[0], <list>[1], <list>[2]
}public class Order implements Equals2 {
private String orderId;
private List<OrderItem> items;
@Override
public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator,
Object object, EqualsStrategy2 strategy) {
if (!(object instanceof Order)) {
return false;
}
Order that = (Order) object;
// Using LocatorUtils for property navigation
boolean orderIdEquals = strategy.equals(
LocatorUtils.property(thisLocator, "orderId", this.orderId),
LocatorUtils.property(thatLocator, "orderId", that.orderId),
this.orderId, that.orderId,
(this.orderId != null), (that.orderId != null)
);
boolean itemsEquals = strategy.equals(
LocatorUtils.property(thisLocator, "items", this.items),
LocatorUtils.property(thatLocator, "items", that.items),
this.items, that.items,
(this.items != null), (that.items != null)
);
return orderIdEquals && itemsEquals;
}
}// Custom validation using locators for precise error reporting
public class CustomerValidator {
public void validate(Customer customer) {
DefaultRootObjectLocator rootLocator = new DefaultRootObjectLocator(customer);
if (customer.getName() == null || customer.getName().trim().isEmpty()) {
PropertyObjectLocator nameLocator = LocatorUtils.property(rootLocator, "name", customer.getName());
throw new ValidationException("Name is required at: " + nameLocator.getPathAsString());
}
if (customer.getAddresses() != null) {
PropertyObjectLocator addressesLocator = LocatorUtils.property(rootLocator, "addresses", customer.getAddresses());
for (int i = 0; i < customer.getAddresses().size(); i++) {
Address address = customer.getAddresses().get(i);
ItemObjectLocator addressLocator = LocatorUtils.item(addressesLocator, i, address);
if (address.getZipCode() == null) {
PropertyObjectLocator zipLocator = LocatorUtils.property(addressLocator, "zipCode", address.getZipCode());
throw new ValidationException("Zip code is required at: " + zipLocator.getPathAsString());
// Error message: "Zip code is required at: <customer>.addresses[2].zipCode"
}
}
}
}
}// Implementing Reportable for internationalized error messages
public class CustomValidationError extends AbstractObjectLocator implements Reportable {
private final String messageCode;
private final Object[] parameters;
public CustomValidationError(ObjectLocator parent, String property, Object value,
String messageCode, Object... parameters) {
super(parent, value);
this.messageCode = messageCode;
this.parameters = parameters;
}
@Override
public String getMessageCode() {
return messageCode;
}
@Override
public Object[] getMessageParameters() {
return parameters;
}
@Override
protected String getStepAsString() {
return getPropertyName();
}
@Override
protected String getDefaultMessage() {
return "Validation error at " + getPathAsString();
}
}
// Usage in JAXB validation event handler
public class ValidationEventHandler implements javax.xml.bind.ValidationEventHandler {
@Override
public boolean handleEvent(ValidationEvent event) {
ValidationEventLocator locator = event.getLocator();
// Convert JAXB locator to our ObjectLocator if needed
if (locator instanceof ObjectLocator) {
ObjectLocator objectLocator = (ObjectLocator) locator;
System.err.println("Validation error at: " + objectLocator.getPathAsString());
System.err.println("Message: " + objectLocator.getMessage());
}
return true; // Continue validation
}
}The locator system works as a hierarchical path tracking mechanism:
DefaultRootObjectLocator represents the starting point of navigationDefaultPropertyObjectLocator tracks object property accessDefaultItemObjectLocator tracks array/list element access<root>.property[index].subProperty[subIndex]...This architecture provides complete traceability through complex object hierarchies, making it invaluable for debugging JAXB binding issues, validation errors, and strategic operation failures.