or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdjaxb-lifecycle.mdjaxb-model.mdobject-locators.mdstrategic-patterns.mdutilities.md

jaxb-lifecycle.mddocs/

0

# JAXB Lifecycle Integration

1

2

Callback interfaces for integrating with JAXB marshalling and unmarshalling lifecycle events, enabling custom processing during XML binding operations. These interfaces allow JAXB-generated classes to execute custom logic at specific points in the marshalling/unmarshalling process.

3

4

## Capabilities

5

6

### Marshalling Callbacks

7

8

Interfaces for executing custom logic before and after marshalling operations.

9

10

```java { .api }

11

interface BeforeMarshallCallback {

12

void beforeMarshall(Marshaller marshaller);

13

}

14

15

interface AfterMarshallCallback {

16

void afterMarshall(Marshaller marshaller);

17

}

18

```

19

20

### Unmarshalling Callbacks

21

22

Interfaces for executing custom logic before and after unmarshalling operations.

23

24

```java { .api }

25

interface BeforeUnmarshallCallback {

26

void beforeUnmarshal(Unmarshaller unmarshaller, Object parent);

27

}

28

29

interface AfterUnmarshallCallback {

30

void afterUnmarshal(Unmarshaller unmarshaller, Object parent);

31

}

32

```

33

34

### Context Awareness

35

36

Interface for classes that need to be aware of their JAXB context path.

37

38

```java { .api }

39

interface ContextPathAware {

40

String getContextPath();

41

}

42

```

43

44

### XML Adapters

45

46

Custom adapters for common data transformations during marshalling/unmarshalling.

47

48

```java { .api }

49

class CommaDelimitedStringAdapter extends XmlAdapter<String, List<String>> {

50

public String marshal(List<String> value) throws Exception;

51

public List<String> unmarshal(String text) throws Exception;

52

}

53

```

54

55

## Usage Examples

56

57

### Basic Lifecycle Callbacks

58

59

```java

60

import org.jvnet.jaxb2_commons.xml.bind.*;

61

import javax.xml.bind.Marshaller;

62

import javax.xml.bind.Unmarshaller;

63

64

@XmlRootElement

65

public class Customer implements BeforeMarshallCallback, AfterMarshallCallback,

66

BeforeUnmarshallCallback, AfterUnmarshallCallback {

67

68

private String name;

69

private String email;

70

private Date lastModified;

71

72

@Override

73

public void beforeMarshall(Marshaller marshaller) {

74

System.out.println("About to marshal Customer: " + name);

75

// Update last modified timestamp before marshalling

76

this.lastModified = new Date();

77

}

78

79

@Override

80

public void afterMarshall(Marshaller marshaller) {

81

System.out.println("Successfully marshalled Customer: " + name);

82

// Perform cleanup or logging after marshalling

83

}

84

85

@Override

86

public void beforeUnmarshal(Unmarshaller unmarshaller, Object parent) {

87

System.out.println("About to unmarshal Customer with parent: " + parent);

88

// Initialize default values or prepare for unmarshalling

89

}

90

91

@Override

92

public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {

93

System.out.println("Successfully unmarshalled Customer: " + name);

94

// Perform post-processing, validation, or setup

95

if (this.email != null) {

96

this.email = this.email.toLowerCase().trim();

97

}

98

}

99

100

// Standard getters and setters

101

public String getName() { return name; }

102

public void setName(String name) { this.name = name; }

103

public String getEmail() { return email; }

104

public void setEmail(String email) { this.email = email; }

105

public Date getLastModified() { return lastModified; }

106

public void setLastModified(Date lastModified) { this.lastModified = lastModified; }

107

}

108

```

109

110

### Context Path Awareness

111

112

```java

113

import org.jvnet.jaxb2_commons.xml.bind.ContextPathAware;

114

import javax.xml.bind.JAXBContext;

115

116

@XmlRootElement

117

public class ConfigurableEntity implements ContextPathAware {

118

private String contextPath;

119

120

@Override

121

public String getContextPath() {

122

if (contextPath == null) {

123

// Determine context path based on package or configuration

124

contextPath = this.getClass().getPackage().getName();

125

}

126

return contextPath;

127

}

128

129

public void setContextPath(String contextPath) {

130

this.contextPath = contextPath;

131

}

132

133

// Use context path for dynamic behavior

134

public JAXBContext createContext() throws JAXBException {

135

return JAXBContext.newInstance(getContextPath());

136

}

137

}

138

```

139

140

### Advanced Lifecycle Integration

141

142

```java

143

import org.jvnet.jaxb2_commons.xml.bind.*;

144

import javax.xml.bind.Marshaller;

145

import javax.xml.bind.Unmarshaller;

146

import java.util.concurrent.atomic.AtomicLong;

147

148

@XmlRootElement

149

public class AuditableEntity implements BeforeMarshallCallback, AfterUnmarshallCallback {

150

151

private static final AtomicLong VERSION_COUNTER = new AtomicLong(0);

152

153

private String id;

154

private Long version;

155

private Date createdDate;

156

private Date modifiedDate;

157

private transient boolean isNew = true;

158

159

@Override

160

public void beforeMarshall(Marshaller marshaller) {

161

// Update modification timestamp and version before marshalling

162

this.modifiedDate = new Date();

163

if (this.version == null) {

164

this.version = VERSION_COUNTER.incrementAndGet();

165

}

166

167

// Set marshaller properties based on entity state

168

try {

169

if (isNew) {

170

marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

171

}

172

} catch (Exception e) {

173

// Handle marshaller property setting errors

174

System.err.println("Could not set marshaller properties: " + e.getMessage());

175

}

176

}

177

178

@Override

179

public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {

180

// Mark entity as existing (not new) after unmarshalling

181

this.isNew = false;

182

183

// Set creation date if not present

184

if (this.createdDate == null) {

185

this.createdDate = new Date();

186

}

187

188

// Perform parent relationship setup

189

if (parent instanceof EntityContainer) {

190

EntityContainer container = (EntityContainer) parent;

191

container.addEntity(this);

192

}

193

194

// Validate unmarshalled data

195

validateEntity();

196

}

197

198

private void validateEntity() {

199

if (id == null || id.trim().isEmpty()) {

200

throw new IllegalStateException("Entity ID cannot be null or empty");

201

}

202

if (version == null || version < 0) {

203

throw new IllegalStateException("Entity version must be non-negative");

204

}

205

}

206

207

// Getters and setters

208

public String getId() { return id; }

209

public void setId(String id) { this.id = id; }

210

public Long getVersion() { return version; }

211

public void setVersion(Long version) { this.version = version; }

212

public Date getCreatedDate() { return createdDate; }

213

public void setCreatedDate(Date createdDate) { this.createdDate = createdDate; }

214

public Date getModifiedDate() { return modifiedDate; }

215

public void setModifiedDate(Date modifiedDate) { this.modifiedDate = modifiedDate; }

216

public boolean isNew() { return isNew; }

217

}

218

```

219

220

### XML Adapter Usage

221

222

```java

223

import org.jvnet.jaxb2_commons.xml.bind.annotation.adapters.CommaDelimitedStringAdapter;

224

import javax.xml.bind.annotation.XmlRootElement;

225

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

226

import java.util.List;

227

import java.util.Arrays;

228

229

@XmlRootElement

230

public class ProductInfo {

231

232

@XmlJavaTypeAdapter(CommaDelimitedStringAdapter.class)

233

private List<String> tags;

234

235

@XmlJavaTypeAdapter(CommaDelimitedStringAdapter.class)

236

private List<String> categories;

237

238

// Constructor

239

public ProductInfo() {

240

this.tags = new ArrayList<>();

241

this.categories = new ArrayList<>();

242

}

243

244

// Getters and setters

245

public List<String> getTags() { return tags; }

246

public void setTags(List<String> tags) { this.tags = tags; }

247

public List<String> getCategories() { return categories; }

248

public void setCategories(List<String> categories) { this.categories = categories; }

249

}

250

251

// Usage example:

252

ProductInfo product = new ProductInfo();

253

product.setTags(Arrays.asList("electronics", "mobile", "smartphone"));

254

product.setCategories(Arrays.asList("phones", "accessories"));

255

256

// When marshalled, produces XML like:

257

// <productInfo>

258

// <tags>electronics,mobile,smartphone</tags>

259

// <categories>phones,accessories</categories>

260

// </productInfo>

261

262

// When unmarshalled, converts comma-delimited strings back to List<String>

263

```

264

265

### Custom XML Adapter

266

267

```java

268

import javax.xml.bind.annotation.adapters.XmlAdapter;

269

import java.time.LocalDateTime;

270

import java.time.format.DateTimeFormatter;

271

272

public class LocalDateTimeAdapter extends XmlAdapter<String, LocalDateTime> {

273

274

private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

275

276

@Override

277

public LocalDateTime unmarshal(String value) throws Exception {

278

if (value == null || value.trim().isEmpty()) {

279

return null;

280

}

281

return LocalDateTime.parse(value, FORMATTER);

282

}

283

284

@Override

285

public String marshal(LocalDateTime value) throws Exception {

286

if (value == null) {

287

return null;

288

}

289

return value.format(FORMATTER);

290

}

291

}

292

293

// Usage in entity class

294

@XmlRootElement

295

public class Event implements AfterUnmarshallCallback {

296

297

@XmlJavaTypeAdapter(LocalDateTimeAdapter.class)

298

private LocalDateTime eventDateTime;

299

300

@Override

301

public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {

302

// Validate that event date is not in the past

303

if (eventDateTime != null && eventDateTime.isBefore(LocalDateTime.now())) {

304

System.out.println("Warning: Event date is in the past: " + eventDateTime);

305

}

306

}

307

308

public LocalDateTime getEventDateTime() { return eventDateTime; }

309

public void setEventDateTime(LocalDateTime eventDateTime) { this.eventDateTime = eventDateTime; }

310

}

311

```

312

313

### Callback Chain with Parent-Child Relationships

314

315

```java

316

@XmlRootElement

317

public class OrderContainer implements AfterUnmarshallCallback {

318

319

@XmlElement(name = "order")

320

private List<Order> orders = new ArrayList<>();

321

322

@Override

323

public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {

324

// Set up parent-child relationships after unmarshalling

325

for (Order order : orders) {

326

order.setContainer(this);

327

}

328

System.out.println("Unmarshalled " + orders.size() + " orders");

329

}

330

331

public List<Order> getOrders() { return orders; }

332

public void setOrders(List<Order> orders) { this.orders = orders; }

333

}

334

335

@XmlType

336

public class Order implements BeforeMarshallCallback, AfterUnmarshallCallback {

337

338

private String orderId;

339

private transient OrderContainer container;

340

341

@Override

342

public void beforeMarshall(Marshaller marshaller) {

343

System.out.println("Marshalling order: " + orderId);

344

}

345

346

@Override

347

public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {

348

System.out.println("Unmarshalled order: " + orderId + " with parent: " + parent.getClass().getSimpleName());

349

// Parent relationship will be set by OrderContainer's afterUnmarshal

350

}

351

352

public String getOrderId() { return orderId; }

353

public void setOrderId(String orderId) { this.orderId = orderId; }

354

public OrderContainer getContainer() { return container; }

355

public void setContainer(OrderContainer container) { this.container = container; }

356

}

357

```

358

359

## Integration with JAXB Runtime

360

361

The lifecycle callbacks integrate seamlessly with JAXB's standard marshalling and unmarshalling process:

362

363

1. **Marshalling Flow**: `beforeMarshall()` → JAXB marshalling → `afterMarshall()`

364

2. **Unmarshalling Flow**: `beforeUnmarshal()` → JAXB unmarshalling → `afterUnmarshal()`

365

3. **Adapter Flow**: `marshal()` during marshalling, `unmarshal()` during unmarshalling

366

4. **Context Awareness**: Available throughout the lifecycle for context-sensitive operations

367

368

These callbacks provide hooks for custom validation, data transformation, relationship setup, auditing, and other cross-cutting concerns that need to execute during XML binding operations.