0
# Object Location Tracking
1
2
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.
3
4
## Capabilities
5
6
### Core Interfaces
7
8
#### ObjectLocator
9
10
Main interface that denotes a location in an object structure, extending both ValidationEventLocator and Reportable for comprehensive location tracking and reporting.
11
12
```java { .api }
13
interface ObjectLocator extends ValidationEventLocator, Reportable {
14
ObjectLocator getParentLocator();
15
ObjectLocator[] getPath();
16
String getPathAsString();
17
PropertyObjectLocator property(String propertyName, Object propertyValue);
18
ItemObjectLocator item(int itemIndex, Object itemValue);
19
}
20
```
21
22
#### Specialized Locator Interfaces
23
24
```java { .api }
25
interface RootObjectLocator extends ObjectLocator {
26
// Marker interface for root object locators
27
}
28
29
interface PropertyObjectLocator extends ObjectLocator {
30
String getPropertyName();
31
Object getObject();
32
}
33
34
interface ItemObjectLocator extends ObjectLocator {
35
int getIndex();
36
Object getObject();
37
}
38
```
39
40
### Abstract Base Implementation
41
42
```java { .api }
43
abstract class AbstractObjectLocator implements ObjectLocator {
44
protected AbstractObjectLocator(ObjectLocator parentLocator, Object object);
45
46
// ObjectLocator methods
47
public ObjectLocator getParentLocator();
48
public ObjectLocator[] getPath();
49
public String getPathAsString();
50
public Object getObject();
51
public ItemObjectLocator item(int index, Object value);
52
public PropertyObjectLocator property(String name, Object value);
53
54
// ValidationEventLocator methods (return default values)
55
public int getColumnNumber();
56
public int getLineNumber();
57
public int getOffset();
58
public URL getURL();
59
public Node getNode();
60
61
// Reportable methods
62
public String getMessageCode();
63
public String getMessage();
64
public String getMessage(ResourceBundle bundle);
65
66
// Abstract methods for subclasses
67
protected abstract String getStepAsString();
68
protected abstract String getDefaultMessage();
69
}
70
```
71
72
### Concrete Implementations
73
74
```java { .api }
75
final class DefaultRootObjectLocator extends AbstractObjectLocator implements RootObjectLocator {
76
public DefaultRootObjectLocator(Object rootObject);
77
public Object[] getMessageParameters();
78
}
79
80
final class DefaultPropertyObjectLocator extends AbstractObjectLocator implements PropertyObjectLocator {
81
protected DefaultPropertyObjectLocator(ObjectLocator parentLocator, String propertyName, Object propertyValue);
82
public String getPropertyName();
83
public Object[] getMessageParameters();
84
}
85
86
final class DefaultItemObjectLocator extends AbstractObjectLocator implements ItemObjectLocator {
87
protected DefaultItemObjectLocator(ObjectLocator parentLocator, int itemIndex, Object itemValue);
88
public int getIndex();
89
public Object[] getMessageParameters();
90
}
91
```
92
93
### Utility Classes
94
95
```java { .api }
96
final class LocatorUtils {
97
// SAX Locator formatting
98
static String getLocation(Locator locator);
99
100
// Null-safe property locator creation
101
static PropertyObjectLocator property(ObjectLocator parent, String name, Object value);
102
static PropertyObjectLocator property(ObjectLocator parent, String name, boolean value);
103
static PropertyObjectLocator property(ObjectLocator parent, String name, byte value);
104
static PropertyObjectLocator property(ObjectLocator parent, String name, char value);
105
static PropertyObjectLocator property(ObjectLocator parent, String name, double value);
106
static PropertyObjectLocator property(ObjectLocator parent, String name, float value);
107
static PropertyObjectLocator property(ObjectLocator parent, String name, int value);
108
static PropertyObjectLocator property(ObjectLocator parent, String name, long value);
109
static PropertyObjectLocator property(ObjectLocator parent, String name, short value);
110
111
// Null-safe item locator creation
112
static ItemObjectLocator item(ObjectLocator parent, int index, Object value);
113
static ItemObjectLocator item(ObjectLocator parent, int index, boolean value);
114
static ItemObjectLocator item(ObjectLocator parent, int index, byte value);
115
static ItemObjectLocator item(ObjectLocator parent, int index, char value);
116
static ItemObjectLocator item(ObjectLocator parent, int index, double value);
117
static ItemObjectLocator item(ObjectLocator parent, int index, float value);
118
static ItemObjectLocator item(ObjectLocator parent, int index, int value);
119
static ItemObjectLocator item(ObjectLocator parent, int index, long value);
120
static ItemObjectLocator item(ObjectLocator parent, int index, short value);
121
}
122
```
123
124
## Usage Examples
125
126
### Basic Object Path Tracking
127
128
```java
129
import org.jvnet.jaxb2_commons.locator.*;
130
import org.jvnet.jaxb2_commons.locator.util.LocatorUtils;
131
132
// Create root locator for a customer object
133
Customer customer = new Customer();
134
customer.setName("John Doe");
135
customer.setAddress(new Address());
136
customer.getAddress().setStreet("123 Main St");
137
138
DefaultRootObjectLocator rootLocator = new DefaultRootObjectLocator(customer);
139
140
// Navigate to properties
141
PropertyObjectLocator nameLocator = rootLocator.property("name", customer.getName());
142
PropertyObjectLocator addressLocator = rootLocator.property("address", customer.getAddress());
143
PropertyObjectLocator streetLocator = addressLocator.property("street", customer.getAddress().getStreet());
144
145
// Get path information
146
System.out.println(streetLocator.getPathAsString());
147
// Output: <customer>.address.street
148
149
ObjectLocator[] path = streetLocator.getPath();
150
// Returns array: [rootLocator, addressLocator, streetLocator]
151
```
152
153
### Using LocatorUtils for Null-Safe Operations
154
155
```java
156
import org.jvnet.jaxb2_commons.locator.util.LocatorUtils;
157
158
// Null-safe property creation (handles null parent gracefully)
159
ObjectLocator parentLocator = null; // or any ObjectLocator
160
PropertyObjectLocator safeLocator = LocatorUtils.property(parentLocator, "name", "John");
161
// Returns locator even if parent is null
162
163
// Primitive type handling with auto-boxing
164
PropertyObjectLocator intLocator = LocatorUtils.property(parentLocator, "age", 25);
165
PropertyObjectLocator booleanLocator = LocatorUtils.property(parentLocator, "active", true);
166
167
// Array/collection item tracking
168
List<String> items = Arrays.asList("first", "second", "third");
169
ObjectLocator listLocator = new DefaultRootObjectLocator(items);
170
for (int i = 0; i < items.size(); i++) {
171
ItemObjectLocator itemLocator = LocatorUtils.item(listLocator, i, items.get(i));
172
System.out.println(itemLocator.getPathAsString());
173
// Output: <list>[0], <list>[1], <list>[2]
174
}
175
```
176
177
### Integration with Strategic Patterns
178
179
```java
180
public class Order implements Equals2 {
181
private String orderId;
182
private List<OrderItem> items;
183
184
@Override
185
public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator,
186
Object object, EqualsStrategy2 strategy) {
187
if (!(object instanceof Order)) {
188
return false;
189
}
190
Order that = (Order) object;
191
192
// Using LocatorUtils for property navigation
193
boolean orderIdEquals = strategy.equals(
194
LocatorUtils.property(thisLocator, "orderId", this.orderId),
195
LocatorUtils.property(thatLocator, "orderId", that.orderId),
196
this.orderId, that.orderId,
197
(this.orderId != null), (that.orderId != null)
198
);
199
200
boolean itemsEquals = strategy.equals(
201
LocatorUtils.property(thisLocator, "items", this.items),
202
LocatorUtils.property(thatLocator, "items", that.items),
203
this.items, that.items,
204
(this.items != null), (that.items != null)
205
);
206
207
return orderIdEquals && itemsEquals;
208
}
209
}
210
```
211
212
### Error Reporting with Locators
213
214
```java
215
// Custom validation using locators for precise error reporting
216
public class CustomerValidator {
217
public void validate(Customer customer) {
218
DefaultRootObjectLocator rootLocator = new DefaultRootObjectLocator(customer);
219
220
if (customer.getName() == null || customer.getName().trim().isEmpty()) {
221
PropertyObjectLocator nameLocator = LocatorUtils.property(rootLocator, "name", customer.getName());
222
throw new ValidationException("Name is required at: " + nameLocator.getPathAsString());
223
}
224
225
if (customer.getAddresses() != null) {
226
PropertyObjectLocator addressesLocator = LocatorUtils.property(rootLocator, "addresses", customer.getAddresses());
227
for (int i = 0; i < customer.getAddresses().size(); i++) {
228
Address address = customer.getAddresses().get(i);
229
ItemObjectLocator addressLocator = LocatorUtils.item(addressesLocator, i, address);
230
231
if (address.getZipCode() == null) {
232
PropertyObjectLocator zipLocator = LocatorUtils.property(addressLocator, "zipCode", address.getZipCode());
233
throw new ValidationException("Zip code is required at: " + zipLocator.getPathAsString());
234
// Error message: "Zip code is required at: <customer>.addresses[2].zipCode"
235
}
236
}
237
}
238
}
239
}
240
```
241
242
### JAXB Validation Integration
243
244
```java
245
// Implementing Reportable for internationalized error messages
246
public class CustomValidationError extends AbstractObjectLocator implements Reportable {
247
private final String messageCode;
248
private final Object[] parameters;
249
250
public CustomValidationError(ObjectLocator parent, String property, Object value,
251
String messageCode, Object... parameters) {
252
super(parent, value);
253
this.messageCode = messageCode;
254
this.parameters = parameters;
255
}
256
257
@Override
258
public String getMessageCode() {
259
return messageCode;
260
}
261
262
@Override
263
public Object[] getMessageParameters() {
264
return parameters;
265
}
266
267
@Override
268
protected String getStepAsString() {
269
return getPropertyName();
270
}
271
272
@Override
273
protected String getDefaultMessage() {
274
return "Validation error at " + getPathAsString();
275
}
276
}
277
278
// Usage in JAXB validation event handler
279
public class ValidationEventHandler implements javax.xml.bind.ValidationEventHandler {
280
@Override
281
public boolean handleEvent(ValidationEvent event) {
282
ValidationEventLocator locator = event.getLocator();
283
284
// Convert JAXB locator to our ObjectLocator if needed
285
if (locator instanceof ObjectLocator) {
286
ObjectLocator objectLocator = (ObjectLocator) locator;
287
System.err.println("Validation error at: " + objectLocator.getPathAsString());
288
System.err.println("Message: " + objectLocator.getMessage());
289
}
290
291
return true; // Continue validation
292
}
293
}
294
```
295
296
## Object Path Tracking Architecture
297
298
The locator system works as a hierarchical path tracking mechanism:
299
300
1. **Root Level**: `DefaultRootObjectLocator` represents the starting point of navigation
301
2. **Property Navigation**: `DefaultPropertyObjectLocator` tracks object property access
302
3. **Collection Navigation**: `DefaultItemObjectLocator` tracks array/list element access
303
4. **Path Building**: Each locator maintains parent reference enabling full path reconstruction
304
5. **String Representation**: Paths are formatted as `<root>.property[index].subProperty[subIndex]...`
305
306
This architecture provides complete traceability through complex object hierarchies, making it invaluable for debugging JAXB binding issues, validation errors, and strategic operation failures.