or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdformatting.mdinclusion-exclusion.mdindex.mdobject-creation.mdobject-identity.mdobject-structure.mdpolymorphic-types.mdproperty-control.md

object-identity.mddocs/

0

# Object Identity and References

1

2

Handle circular references and object identity with configurable ID generation and reference management.

3

4

## Capabilities

5

6

### JsonIdentityInfo

7

8

Configure object identity for handling circular references and duplicate objects.

9

10

```java { .api }

11

/**

12

* Configure object identity for reference handling

13

* @param property Identity property name in JSON

14

* @param generator ObjectIdGenerator implementation class

15

* @param resolver ObjectIdResolver implementation class

16

* @param scope Identity scope class (default: Object.class for global scope)

17

*/

18

@JsonIdentityInfo(String property = "@id",

19

Class<? extends ObjectIdGenerator<?>> generator,

20

Class<? extends ObjectIdResolver> resolver = SimpleObjectIdResolver.class,

21

Class<?> scope = Object.class)

22

public @interface JsonIdentityInfo;

23

```

24

25

**Usage Examples:**

26

27

```java

28

@JsonIdentityInfo(

29

generator = ObjectIdGenerators.PropertyGenerator.class,

30

property = "id"

31

)

32

public class Department {

33

private Long id;

34

private String name;

35

private List<Employee> employees;

36

}

37

38

@JsonIdentityInfo(

39

generator = ObjectIdGenerators.PropertyGenerator.class,

40

property = "employeeId"

41

)

42

public class Employee {

43

private Long employeeId;

44

private String name;

45

private Department department;

46

}

47

48

// First occurrence: {"id": 1, "name": "Engineering", "employees": [{"employeeId": 100, "name": "John", "department": 1}]}

49

// Subsequent references: {"id": 1} or {"employeeId": 100}

50

```

51

52

### JsonIdentityReference

53

54

Configure whether to always serialize objects as identity references.

55

56

```java { .api }

57

/**

58

* Configure whether to always serialize as identity reference

59

* @param alwaysAsId Always use ID instead of full object (default: false)

60

*/

61

@JsonIdentityReference(boolean alwaysAsId = false)

62

public @interface JsonIdentityReference;

63

```

64

65

**Usage Examples:**

66

67

```java

68

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")

69

public class Category {

70

private Long id;

71

private String name;

72

73

@JsonIdentityReference(alwaysAsId = true)

74

private Category parentCategory; // Always serialized as just the ID

75

76

private List<Category> subcategories; // Full objects on first reference

77

}

78

79

// Result: {"id": 1, "name": "Electronics", "parentCategory": 5, "subcategories": [{"id": 2, "name": "Phones", "parentCategory": 1}]}

80

```

81

82

### JsonManagedReference and JsonBackReference

83

84

Handle bidirectional relationships without infinite recursion.

85

86

```java { .api }

87

/**

88

* Mark forward reference in bidirectional relationship

89

* @param value Reference name to match with @JsonBackReference

90

*/

91

@JsonManagedReference(String value = "defaultReference")

92

public @interface JsonManagedReference;

93

94

/**

95

* Mark back reference in bidirectional relationship

96

* @param value Reference name matching @JsonManagedReference

97

*/

98

@JsonBackReference(String value = "defaultReference")

99

public @interface JsonBackReference;

100

```

101

102

**Usage Examples:**

103

104

```java

105

public class Parent {

106

private String name;

107

108

@JsonManagedReference("parent-children")

109

private List<Child> children;

110

}

111

112

public class Child {

113

private String name;

114

115

@JsonBackReference("parent-children")

116

private Parent parent;

117

}

118

119

// Serialization: {"name": "ParentName", "children": [{"name": "Child1"}, {"name": "Child2"}]}

120

// Parent reference in children is omitted to prevent cycles

121

122

// Multiple reference types in same class:

123

public class Order {

124

@JsonManagedReference("order-items")

125

private List<OrderItem> items;

126

127

@JsonManagedReference("order-payments")

128

private List<Payment> payments;

129

}

130

131

public class OrderItem {

132

@JsonBackReference("order-items")

133

private Order order;

134

}

135

136

public class Payment {

137

@JsonBackReference("order-payments")

138

private Order order;

139

}

140

```

141

142

## Object Identity System Components

143

144

### ObjectIdGenerator

145

146

Base class for generating object identifiers.

147

148

```java { .api }

149

/**

150

* Base class for object ID generators

151

*/

152

public abstract class ObjectIdGenerator<T> {

153

154

/** Get the scope class for this generator */

155

public abstract Class<?> getScope();

156

157

/** Check if this generator can be used for another generator */

158

public abstract boolean canUseFor(ObjectIdGenerator<?> gen);

159

160

/** Create generator for specific scope */

161

public abstract ObjectIdGenerator<T> forScope(Class<?> scope);

162

163

/** Create new generator instance for serialization context */

164

public abstract ObjectIdGenerator<T> newForSerialization(Object context);

165

166

/** Generate ID for given object */

167

public abstract T generateId(Object forPojo);

168

169

/** Create IdKey for the given key */

170

public abstract IdKey key(Object key);

171

172

/**

173

* Key class for object identity mapping

174

*/

175

public static final class IdKey {

176

public final Class<?> type;

177

public final Class<?> scope;

178

public final Object key;

179

180

public IdKey(Class<?> type, Class<?> scope, Object key);

181

}

182

}

183

```

184

185

### ObjectIdGenerators

186

187

Standard ObjectIdGenerator implementations.

188

189

```java { .api }

190

/**

191

* Container for standard ObjectIdGenerator implementations

192

*/

193

public class ObjectIdGenerators {

194

195

/**

196

* Generator using integer sequence

197

*/

198

public static class IntSequenceGenerator extends ObjectIdGenerator<Integer> {

199

protected int _nextValue = 1;

200

201

public Integer generateId(Object forPojo) {

202

return _nextValue++;

203

}

204

}

205

206

/**

207

* Generator using UUID values

208

*/

209

public static class UUIDGenerator extends ObjectIdGenerator<UUID> {

210

public UUID generateId(Object forPojo) {

211

return UUID.randomUUID();

212

}

213

}

214

215

/**

216

* Generator using property value as ID

217

*/

218

public static abstract class PropertyGenerator extends ObjectIdGenerator<Object> {

219

// Uses existing property value as object ID

220

}

221

222

/**

223

* Generator using string values

224

*/

225

public static class StringIdGenerator extends ObjectIdGenerator<String> {

226

// Implementation for string-based IDs

227

}

228

229

/**

230

* No-op generator (no identity handling)

231

*/

232

public static abstract class None extends ObjectIdGenerator<Object> {

233

// Placeholder for no identity generation

234

}

235

}

236

```

237

238

### ObjectIdResolver

239

240

Interface for resolving object IDs to instances.

241

242

```java { .api }

243

/**

244

* Interface for resolving object IDs to object instances

245

*/

246

public interface ObjectIdResolver {

247

248

/** Bind object ID to object instance */

249

void bindItem(ObjectIdGenerator.IdKey id, Object pojo);

250

251

/** Resolve ID to object instance */

252

Object resolveId(ObjectIdGenerator.IdKey id);

253

254

/** Create new resolver for deserialization context */

255

ObjectIdResolver newForDeserialization(Object context);

256

257

/** Check if this resolver can be used for another resolver type */

258

boolean canUseFor(ObjectIdResolver resolverType);

259

}

260

```

261

262

### SimpleObjectIdResolver

263

264

Default HashMap-based ObjectIdResolver implementation.

265

266

```java { .api }

267

/**

268

* Default ObjectIdResolver using HashMap for storage

269

*/

270

public class SimpleObjectIdResolver implements ObjectIdResolver {

271

272

protected Map<ObjectIdGenerator.IdKey, Object> _items;

273

274

public SimpleObjectIdResolver();

275

276

public void bindItem(ObjectIdGenerator.IdKey id, Object ob) {

277

if (_items == null) {

278

_items = new HashMap<>();

279

}

280

_items.put(id, ob);

281

}

282

283

public Object resolveId(ObjectIdGenerator.IdKey id) {

284

return (_items == null) ? null : _items.get(id);

285

}

286

287

public ObjectIdResolver newForDeserialization(Object context) {

288

return new SimpleObjectIdResolver();

289

}

290

291

public boolean canUseFor(ObjectIdResolver resolverType) {

292

return resolverType.getClass() == getClass();

293

}

294

}

295

```

296

297

## Advanced Identity Patterns

298

299

### Scoped Identity

300

301

```java

302

@JsonIdentityInfo(

303

generator = ObjectIdGenerators.PropertyGenerator.class,

304

property = "id",

305

scope = Department.class // Identity scoped to Department class

306

)

307

public class Employee {

308

private Long id;

309

private String name;

310

private Department department;

311

}

312

313

@JsonIdentityInfo(

314

generator = ObjectIdGenerators.PropertyGenerator.class,

315

property = "id",

316

scope = Project.class // Different identity scope

317

)

318

public class Task {

319

private Long id; // Can have same ID as Employee because different scope

320

private String description;

321

}

322

```

323

324

### Custom ID Generation

325

326

```java

327

@JsonIdentityInfo(

328

generator = ObjectIdGenerators.UUIDGenerator.class,

329

property = "@uuid"

330

)

331

public class DistributedEntity {

332

private String name;

333

private String data;

334

335

// UUID automatically generated and used for identity

336

}

337

338

@JsonIdentityInfo(

339

generator = ObjectIdGenerators.IntSequenceGenerator.class,

340

property = "@seqId"

341

)

342

public class SequentialEntity {

343

private String content;

344

345

// Sequential integer IDs: @seqId: 1, 2, 3, etc.

346

}

347

```

348

349

### Complex Circular References

350

351

```java

352

public class Node {

353

private String name;

354

355

@JsonManagedReference("node-children")

356

private List<Node> children;

357

358

@JsonBackReference("node-children")

359

private Node parent;

360

361

@JsonIdentityInfo(

362

generator = ObjectIdGenerators.PropertyGenerator.class,

363

property = "name"

364

)

365

@JsonIdentityReference(alwaysAsId = true)

366

private List<Node> references; // Cross-references to other nodes

367

}

368

369

// Handles both parent-child relationships and arbitrary cross-references

370

```

371

372

### Multi-level Relationships

373

374

```java

375

public class Company {

376

private String name;

377

378

@JsonManagedReference("company-departments")

379

private List<Department> departments;

380

}

381

382

public class Department {

383

private String name;

384

385

@JsonBackReference("company-departments")

386

private Company company;

387

388

@JsonManagedReference("department-employees")

389

private List<Employee> employees;

390

}

391

392

public class Employee {

393

private String name;

394

395

@JsonBackReference("department-employees")

396

private Department department;

397

398

@JsonIdentityReference(alwaysAsId = true)

399

private Employee manager; // Reference to another employee

400

}

401

```

402

403

### Identity with Inheritance

404

405

```java

406

@JsonIdentityInfo(

407

generator = ObjectIdGenerators.PropertyGenerator.class,

408

property = "id"

409

)

410

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")

411

@JsonSubTypes({

412

@JsonSubTypes.Type(value = Manager.class, name = "manager"),

413

@JsonSubTypes.Type(value = Developer.class, name = "developer")

414

})

415

public abstract class Employee {

416

protected Long id;

417

protected String name;

418

}

419

420

public class Manager extends Employee {

421

@JsonIdentityReference(alwaysAsId = true)

422

private List<Employee> team;

423

}

424

425

public class Developer extends Employee {

426

@JsonIdentityReference(alwaysAsId = true)

427

private Manager manager;

428

}

429

```