CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-fasterxml-jackson-core--jackson-annotations

Core annotations used for value types, used by Jackson data binding package.

Pending
Overview
Eval results
Files

object-identity.mddocs/

Object Identity and References

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

Capabilities

JsonIdentityInfo

Configure object identity for handling circular references and duplicate objects.

/**
 * Configure object identity for reference handling
 * @param property Identity property name in JSON
 * @param generator ObjectIdGenerator implementation class
 * @param resolver ObjectIdResolver implementation class  
 * @param scope Identity scope class (default: Object.class for global scope)
 */
@JsonIdentityInfo(String property = "@id",
                  Class<? extends ObjectIdGenerator<?>> generator,
                  Class<? extends ObjectIdResolver> resolver = SimpleObjectIdResolver.class,
                  Class<?> scope = Object.class)
public @interface JsonIdentityInfo;

Usage Examples:

@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "id"
)
public class Department {
    private Long id;
    private String name;
    private List<Employee> employees;
}

@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "employeeId"
)
public class Employee {
    private Long employeeId;
    private String name;
    private Department department;
}

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

JsonIdentityReference

Configure whether to always serialize objects as identity references.

/**
 * Configure whether to always serialize as identity reference
 * @param alwaysAsId Always use ID instead of full object (default: false)
 */
@JsonIdentityReference(boolean alwaysAsId = false)
public @interface JsonIdentityReference;

Usage Examples:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Category {
    private Long id;
    private String name;
    
    @JsonIdentityReference(alwaysAsId = true)
    private Category parentCategory;  // Always serialized as just the ID
    
    private List<Category> subcategories;  // Full objects on first reference
}

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

JsonManagedReference and JsonBackReference

Handle bidirectional relationships without infinite recursion.

/**
 * Mark forward reference in bidirectional relationship
 * @param value Reference name to match with @JsonBackReference
 */
@JsonManagedReference(String value = "defaultReference")
public @interface JsonManagedReference;

/**
 * Mark back reference in bidirectional relationship  
 * @param value Reference name matching @JsonManagedReference
 */
@JsonBackReference(String value = "defaultReference")
public @interface JsonBackReference;

Usage Examples:

public class Parent {
    private String name;
    
    @JsonManagedReference("parent-children")
    private List<Child> children;
}

public class Child {
    private String name;
    
    @JsonBackReference("parent-children")
    private Parent parent;
}

// Serialization: {"name": "ParentName", "children": [{"name": "Child1"}, {"name": "Child2"}]}
// Parent reference in children is omitted to prevent cycles

// Multiple reference types in same class:
public class Order {
    @JsonManagedReference("order-items")
    private List<OrderItem> items;
    
    @JsonManagedReference("order-payments")
    private List<Payment> payments;
}

public class OrderItem {
    @JsonBackReference("order-items")
    private Order order;
}

public class Payment {
    @JsonBackReference("order-payments")
    private Order order;
}

Object Identity System Components

ObjectIdGenerator

Base class for generating object identifiers.

/**
 * Base class for object ID generators
 */
public abstract class ObjectIdGenerator<T> {
    
    /** Get the scope class for this generator */
    public abstract Class<?> getScope();
    
    /** Check if this generator can be used for another generator */
    public abstract boolean canUseFor(ObjectIdGenerator<?> gen);
    
    /** Create generator for specific scope */
    public abstract ObjectIdGenerator<T> forScope(Class<?> scope);
    
    /** Create new generator instance for serialization context */
    public abstract ObjectIdGenerator<T> newForSerialization(Object context);
    
    /** Generate ID for given object */
    public abstract T generateId(Object forPojo);
    
    /** Create IdKey for the given key */
    public abstract IdKey key(Object key);
    
    /**
     * Key class for object identity mapping
     */
    public static final class IdKey {
        public final Class<?> type;
        public final Class<?> scope;
        public final Object key;
        
        public IdKey(Class<?> type, Class<?> scope, Object key);
    }
}

ObjectIdGenerators

Standard ObjectIdGenerator implementations.

/**
 * Container for standard ObjectIdGenerator implementations
 */
public class ObjectIdGenerators {
    
    /**
     * Generator using integer sequence
     */
    public static class IntSequenceGenerator extends ObjectIdGenerator<Integer> {
        protected int _nextValue = 1;
        
        public Integer generateId(Object forPojo) {
            return _nextValue++;
        }
    }
    
    /**
     * Generator using UUID values
     */
    public static class UUIDGenerator extends ObjectIdGenerator<UUID> {
        public UUID generateId(Object forPojo) {
            return UUID.randomUUID();
        }
    }
    
    /**
     * Generator using property value as ID
     */
    public static abstract class PropertyGenerator extends ObjectIdGenerator<Object> {
        // Uses existing property value as object ID
    }
    
    /**
     * Generator using string values
     */
    public static class StringIdGenerator extends ObjectIdGenerator<String> {
        // Implementation for string-based IDs
    }
    
    /**
     * No-op generator (no identity handling)
     */
    public static abstract class None extends ObjectIdGenerator<Object> {
        // Placeholder for no identity generation
    }
}

ObjectIdResolver

Interface for resolving object IDs to instances.

/**
 * Interface for resolving object IDs to object instances
 */
public interface ObjectIdResolver {
    
    /** Bind object ID to object instance */
    void bindItem(ObjectIdGenerator.IdKey id, Object pojo);
    
    /** Resolve ID to object instance */
    Object resolveId(ObjectIdGenerator.IdKey id);
    
    /** Create new resolver for deserialization context */
    ObjectIdResolver newForDeserialization(Object context);
    
    /** Check if this resolver can be used for another resolver type */
    boolean canUseFor(ObjectIdResolver resolverType);
}

SimpleObjectIdResolver

Default HashMap-based ObjectIdResolver implementation.

/**
 * Default ObjectIdResolver using HashMap for storage
 */
public class SimpleObjectIdResolver implements ObjectIdResolver {
    
    protected Map<ObjectIdGenerator.IdKey, Object> _items;
    
    public SimpleObjectIdResolver();
    
    public void bindItem(ObjectIdGenerator.IdKey id, Object ob) {
        if (_items == null) {
            _items = new HashMap<>();
        }
        _items.put(id, ob);
    }
    
    public Object resolveId(ObjectIdGenerator.IdKey id) {
        return (_items == null) ? null : _items.get(id);
    }
    
    public ObjectIdResolver newForDeserialization(Object context) {
        return new SimpleObjectIdResolver();
    }
    
    public boolean canUseFor(ObjectIdResolver resolverType) {
        return resolverType.getClass() == getClass();
    }
}

Advanced Identity Patterns

Scoped Identity

@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "id",
    scope = Department.class  // Identity scoped to Department class
)
public class Employee {
    private Long id;
    private String name;
    private Department department;
}

@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "id",
    scope = Project.class  // Different identity scope
)
public class Task {
    private Long id;  // Can have same ID as Employee because different scope
    private String description;
}

Custom ID Generation

@JsonIdentityInfo(
    generator = ObjectIdGenerators.UUIDGenerator.class,
    property = "@uuid"
)
public class DistributedEntity {
    private String name;
    private String data;
    
    // UUID automatically generated and used for identity
}

@JsonIdentityInfo(
    generator = ObjectIdGenerators.IntSequenceGenerator.class,
    property = "@seqId"
)
public class SequentialEntity {
    private String content;
    
    // Sequential integer IDs: @seqId: 1, 2, 3, etc.
}

Complex Circular References

public class Node {
    private String name;
    
    @JsonManagedReference("node-children")
    private List<Node> children;
    
    @JsonBackReference("node-children")
    private Node parent;
    
    @JsonIdentityInfo(
        generator = ObjectIdGenerators.PropertyGenerator.class,
        property = "name"
    )
    @JsonIdentityReference(alwaysAsId = true)
    private List<Node> references;  // Cross-references to other nodes
}

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

Multi-level Relationships

public class Company {
    private String name;
    
    @JsonManagedReference("company-departments")
    private List<Department> departments;
}

public class Department {
    private String name;
    
    @JsonBackReference("company-departments")
    private Company company;
    
    @JsonManagedReference("department-employees")
    private List<Employee> employees;
}

public class Employee {
    private String name;
    
    @JsonBackReference("department-employees")
    private Department department;
    
    @JsonIdentityReference(alwaysAsId = true)
    private Employee manager;  // Reference to another employee
}

Identity with Inheritance

@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "id"
)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Manager.class, name = "manager"),
    @JsonSubTypes.Type(value = Developer.class, name = "developer")
})
public abstract class Employee {
    protected Long id;
    protected String name;
}

public class Manager extends Employee {
    @JsonIdentityReference(alwaysAsId = true)
    private List<Employee> team;
}

public class Developer extends Employee {
    @JsonIdentityReference(alwaysAsId = true)
    private Manager manager;
}

Install with Tessl CLI

npx tessl i tessl/maven-com-fasterxml-jackson-core--jackson-annotations

docs

configuration.md

formatting.md

inclusion-exclusion.md

index.md

object-creation.md

object-identity.md

object-structure.md

polymorphic-types.md

property-control.md

tile.json