CtrlK
BlogDocsLog inGet started
Tessl Logo

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

General data-binding functionality for Jackson: works on core streaming API

Pending
Overview
Eval results
Files

advanced-features.mddocs/

Advanced Features

Jackson Databind provides sophisticated features for complex use cases including polymorphic type handling, object identity management, custom type handling, injectable values, and advanced property processing. These features enable handling of complex object graphs, type hierarchies, and specialized serialization/deserialization scenarios.

Polymorphic Type Handling

Jackson supports polymorphic type handling through type information inclusion and resolution.

TypeSerializer and TypeDeserializer

public abstract class TypeSerializer {
    // Type serialization methods for different JSON structures
    public abstract void writeTypePrefixForScalar(Object value, JsonGenerator g) throws IOException;
    public abstract void writeTypeSuffixForScalar(Object value, JsonGenerator g) throws IOException;
    public abstract void writeTypePrefixForObject(Object value, JsonGenerator g) throws IOException;
    public abstract void writeTypeSuffixForObject(Object value, JsonGenerator g) throws IOException;
    public abstract void writeTypePrefixForArray(Object value, JsonGenerator g) throws IOException;
    public abstract void writeTypeSuffixForArray(Object value, JsonGenerator g) throws IOException;
    
    // Custom type serialization
    public abstract void writeCustomTypePrefixForScalar(Object value, JsonGenerator g, String typeId) throws IOException;
    public abstract void writeCustomTypeSuffixForScalar(Object value, JsonGenerator g, String typeId) throws IOException;
    public abstract void writeCustomTypePrefixForObject(Object value, JsonGenerator g, String typeId) throws IOException;
    public abstract void writeCustomTypeSuffixForObject(Object value, JsonGenerator g, String typeId) throws IOException;
    public abstract void writeCustomTypePrefixForArray(Object value, JsonGenerator g, String typeId) throws IOException;
    public abstract void writeCustomTypeSuffixForArray(Object value, JsonGenerator g, String typeId) throws IOException;
    
    // Type property handling
    public abstract JsonTypeInfo.As getTypeInclusion();
    public abstract String getPropertyName();
    public abstract TypeIdResolver getTypeIdResolver();
    
    // Utility methods
    public Class<?> getDefaultImpl();
}

public abstract class TypeDeserializer {
    // Type deserialization methods
    public abstract Object deserializeTypedFromScalar(JsonParser jp, DeserializationContext ctxt) throws IOException;
    public abstract Object deserializeTypedFromObject(JsonParser jp, DeserializationContext ctxt) throws IOException;
    public abstract Object deserializeTypedFromArray(JsonParser jp, DeserializationContext ctxt) throws IOException;
    public abstract Object deserializeTypedFromAny(JsonParser jp, DeserializationContext ctxt) throws IOException;
    
    // Type information access
    public abstract JsonTypeInfo.As getTypeInclusion();
    public abstract String getPropertyName();
    public abstract TypeIdResolver getTypeIdResolver();
    
    // Default implementation handling
    public Class<?> getDefaultImpl();
    public abstract Object getTypeId();
}

TypeIdResolver

public interface TypeIdResolver {
    // Initialization
    void init(JavaType baseType);
    
    // Type ID resolution
    String idFromValue(Object value);
    String idFromValueAndType(Object value, Class<?> suggestedType);
    String idFromBaseType();
    
    // Type from ID
    JavaType typeFromId(DatabindContext context, String id) throws IOException;
    
    // Description for error messages
    String getDescForKnownTypeIds();
    
    // Mechanism information
    JsonTypeInfo.Id getMechanism();
}

TypeResolverBuilder

public interface TypeResolverBuilder<T extends TypeResolverBuilder<T>> {
    // Configuration methods
    T inclusion(JsonTypeInfo.As includeAs);
    T typeProperty(String propName);
    T typeIdVisibility(boolean isVisible);
    T defaultImpl(Class<?> defaultImpl);
    
    // Serializer/deserializer building
    TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection<NamedType> subtypes);
    TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection<NamedType> subtypes);
}

PolymorphicTypeValidator

public abstract class PolymorphicTypeValidator implements Serializable {
    // Validation methods
    public abstract Validity validateBaseType(MapperConfig<?> config, JavaType baseType);
    public abstract Validity validateSubClassName(MapperConfig<?> config, JavaType baseType, String subClassName) throws JsonMappingException;
    public abstract Validity validateSubType(MapperConfig<?> config, JavaType baseType, JavaType subType) throws JsonMappingException;
    
    // No-op validator
    public static final PolymorphicTypeValidator NONE;
    
    // Validity enum
    public enum Validity {
        ALLOWED,
        DENIED,
        INDETERMINATE;
    }
}

public class BasicPolymorphicTypeValidator extends PolymorphicTypeValidator {
    // Builder pattern for configuration
    public static Builder builder();
    
    public static class Builder {
        // Allow specific types
        public Builder allowIfSubType(Class<?> subType);
        public Builder allowIfSubType(String subTypePattern);
        public Builder allowIfSubTypeIsArray();
        
        // Allow base types  
        public Builder allowIfBaseType(Class<?> baseType);
        public Builder allowIfBaseType(String baseTypePattern);
        
        // Deny specific types
        public Builder denyForExactBaseType(Class<?> baseType);
        
        // Build validator
        public PolymorphicTypeValidator build();
    }
}

Object Identity Management

ObjectIdGenerator

public abstract class ObjectIdGenerator<T> implements Serializable {
    // Scope and compatibility
    public abstract Class<?> getScope();
    public abstract boolean canUseFor(ObjectIdGenerator<?> gen);
    public abstract ObjectIdGenerator<T> forScope(Class<?> scope);
    public abstract ObjectIdGenerator<T> newForSerialization(Object context);
    
    // ID generation and keys
    public abstract IdKey key(Object key);
    public abstract T generateId(Object forPojo);
    
    // Generator type information
    public boolean maySerializeAsObject();
    public boolean isValidReferencePropertyName(String name, Object parser);
}

// Standard generators
public class ObjectIdGenerators {
    public static class IntSequenceGenerator extends ObjectIdGenerator<Integer> {
        public IntSequenceGenerator();
        public IntSequenceGenerator(Class<?> scope, int initialValue);
        
        public Class<?> getScope();
        public boolean canUseFor(ObjectIdGenerator<?> gen);
        public ObjectIdGenerator<Integer> forScope(Class<?> scope);
        public ObjectIdGenerator<Integer> newForSerialization(Object context);
        public IdKey key(Object key);
        public Integer generateId(Object forPojo);
    }
    
    public static class PropertyGenerator extends ObjectIdGenerator<Object> {
        public PropertyGenerator(Class<?> scope);
        
        public Class<?> getScope();
        public boolean canUseFor(ObjectIdGenerator<?> gen);
        public ObjectIdGenerator<Object> forScope(Class<?> scope);  
        public ObjectIdGenerator<Object> newForSerialization(Object context);
        public IdKey key(Object key);
        public Object generateId(Object forPojo);
    }
    
    public static class StringIdGenerator extends ObjectIdGenerator<String> {
        // Similar methods for String-based IDs
    }
    
    public static class UUIDGenerator extends ObjectIdGenerator<UUID> {
        // Similar methods for UUID-based IDs
    }
}

ObjectIdResolver

public interface ObjectIdResolver {
    // Object resolution during deserialization
    void bindItem(IdKey id, Object ob);
    Object resolveId(IdKey id);
    boolean canUseFor(ObjectIdResolver resolverType);
    ObjectIdResolver newForDeserialization(Object context);
}

// Standard resolver
public class SimpleObjectIdResolver implements ObjectIdResolver {
    public void bindItem(IdKey id, Object ob);
    public Object resolveId(IdKey id);
    public boolean canUseFor(ObjectIdResolver resolverType);
    public ObjectIdResolver newForDeserialization(Object context);
}

ObjectIdReader and ObjectIdWriter

public class ObjectIdReader implements Serializable {
    // ID property information
    public final JavaType idType;
    public final PropertyName propertyName;
    public final ObjectIdGenerator<?> generator;
    public final ObjectIdResolver resolver;
    public final JsonDeserializer<Object> deserializer;
    public final SettableBeanProperty idProperty;
    
    // Construction
    public ObjectIdReader(JavaType t, PropertyName propName, ObjectIdGenerator<?> gen, JsonDeserializer<?> deser, SettableBeanProperty idProp, ObjectIdResolver resolver);
    
    // Factory methods  
    public static ObjectIdReader construct(JavaType idType, PropertyName propName, ObjectIdGenerator<?> generator, JsonDeserializer<?> deser, SettableBeanProperty idProp, ObjectIdResolver resolver);
    
    // Modification methods
    public ObjectIdReader withAlwaysAsId();
    public ObjectIdReader withResolver(ObjectIdResolver resolver);
    public ObjectIdReader withDeserializer(JsonDeserializer<?> deser);
}

public class ObjectIdWriter implements Serializable {
    // ID generation information
    public final JavaType idType;
    public final PropertyName propertyName;
    public final ObjectIdGenerator<?> generator;
    public final JsonSerializer<Object> serializer;
    public final boolean alwaysAsId;
    
    // Construction
    public ObjectIdWriter(JavaType t, PropertyName propName, ObjectIdGenerator<?> gen, JsonSerializer<?> ser, boolean alwaysAsId);
    
    // Factory methods
    public static ObjectIdWriter construct(JavaType idType, PropertyName propName, ObjectIdGenerator<?> generator, boolean alwaysAsId);
    
    // Modification methods
    public ObjectIdWriter withSerializer(JsonSerializer<?> ser);
    public ObjectIdWriter withAlwaysAsId(boolean state);
}

Injectable Values

InjectableValues

public abstract class InjectableValues {
    // Value injection
    public abstract Object findInjectableValue(Object valueId, DeserializationContext ctxt, BeanProperty forProperty, Object beanInstance) throws JsonMappingException;
    
    // Standard implementation
    public static class Std extends InjectableValues implements Serializable {
        // Construction
        public Std();
        public Std(Map<String, Object> values);
        
        // Value management
        public Std addValue(String key, Object value);
        public Std addValue(Class<?> key, Object value);
        
        // Injection implementation
        public Object findInjectableValue(Object valueId, DeserializationContext ctxt, BeanProperty forProperty, Object beanInstance);
    }
}

Custom Property Handling

PropertyNamingStrategy

public abstract class PropertyNamingStrategy implements Serializable {
    // Property name transformation methods
    public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName);
    public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName);
    public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName);
    public String nameForConstructorParameter(MapperConfig<?> config, AnnotatedParameter ctorParam, String defaultName);
}

public class PropertyNamingStrategies {
    // Standard strategies
    public static final PropertyNamingStrategy LOWER_CAMEL_CASE;
    public static final PropertyNamingStrategy UPPER_CAMEL_CASE;
    public static final PropertyNamingStrategy SNAKE_CASE;
    public static final PropertyNamingStrategy UPPER_SNAKE_CASE;
    public static final PropertyNamingStrategy LOWER_CASE;
    public static final PropertyNamingStrategy KEBAB_CASE;
    public static final PropertyNamingStrategy LOWER_DOT_CASE;
    
    // Base implementation for custom strategies
    public abstract static class NamingBase extends PropertyNamingStrategy {
        public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName);
        public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName);
        public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName);
        public String nameForConstructorParameter(MapperConfig<?> config, AnnotatedParameter ctorParam, String defaultName);
        
        // Abstract method for name transformation
        public abstract String translate(String propertyName);
    }
    
    // Specific strategy implementations
    public static class SnakeCaseStrategy extends NamingBase {
        public String translate(String input);
    }
    
    public static class UpperCamelCaseStrategy extends NamingBase {
        public String translate(String input);
    }
    
    public static class LowerCaseStrategy extends NamingBase {
        public String translate(String input);
    }
    
    public static class KebabCaseStrategy extends NamingBase {  
        public String translate(String input);
    }
    
    public static class LowerDotCaseStrategy extends NamingBase {
        public String translate(String input);
    }
}

AccessorNamingStrategy

public abstract class AccessorNamingStrategy {
    // Accessor method name analysis
    public abstract String findNameForIsGetter(AnnotatedMethod am, String name);
    public abstract String findNameForRegularGetter(AnnotatedMethod am, String name);
    public abstract String findNameForMutator(AnnotatedMethod am, String name);
    
    // Provider interface for strategy factories
    public static abstract class Provider implements Serializable {
        public abstract AccessorNamingStrategy forPOJO(MapperConfig<?> config, AnnotatedClass targetClass);
        public abstract AccessorNamingStrategy forBuilder(MapperConfig<?> config, AnnotatedClass builderClass, BeanDescription valueTypeDesc);
        public abstract AccessorNamingStrategy forRecord(MapperConfig<?> config, AnnotatedClass recordClass);
    }
}

public class DefaultAccessorNamingStrategy extends AccessorNamingStrategy {
    // Standard JavaBeans naming convention implementation
    public String findNameForIsGetter(AnnotatedMethod am, String name);
    public String findNameForRegularGetter(AnnotatedMethod am, String name);
    public String findNameForMutator(AnnotatedMethod am, String name);
    
    // Provider implementation
    public static class Provider extends AccessorNamingStrategy.Provider {
        public AccessorNamingStrategy forPOJO(MapperConfig<?> config, AnnotatedClass targetClass);
        public AccessorNamingStrategy forBuilder(MapperConfig<?> config, AnnotatedClass builderClass, BeanDescription valueTypeDesc);
        public AccessorNamingStrategy forRecord(MapperConfig<?> config, AnnotatedClass recordClass);
    }
}

Handler Instantiation

HandlerInstantiator

public abstract class HandlerInstantiator {
    // Deserializer instantiation
    public abstract JsonDeserializer<?> deserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> deserClass);
    public abstract KeyDeserializer keyDeserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> keyDeserClass);
    
    // Serializer instantiation  
    public abstract JsonSerializer<?> serializerInstance(SerializationConfig config, Annotated annotated, Class<?> serClass);
    
    // Type handling
    public abstract TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> config, Annotated annotated, Class<?> builderClass);
    public abstract TypeIdResolver typeIdResolverInstance(MapperConfig<?> config, Annotated annotated, Class<?> resolverClass);
    
    // Value instantiation
    public ValueInstantiator valueInstantiatorInstance(MapperConfig<?> config, Annotated annotated, Class<?> instClass);
    
    // Object ID generation
    public ObjectIdGenerator<?> objectIdGeneratorInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass);
    public ObjectIdResolver resolverIdGeneratorInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass);
    
    // Converter instantiation
    public Converter<?, ?> converterInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass);
    
    // Filter instantiation  
    public VirtualBeanPropertyWriter virtualPropertyWriterInstance(MapperConfig<?> config, Class<?> implClass);
}

Advanced Type Processing

TypeModifier

public abstract class TypeModifier {
    // Type modification during construction
    public abstract JavaType modifyType(JavaType type, Type jdkType, TypeBindings context, TypeFactory typeFactory);
}

MixIn Support

MixIn annotations allow adding Jackson annotations to classes without modifying them.

// Example MixIn interface
public interface PersonMixIn {
    @JsonProperty("full_name")
    String getName();
    
    @JsonIgnore
    String getPassword();
    
    @JsonFormat(pattern = "yyyy-MM-dd")
    Date getBirthDate();
}

// Usage
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(Person.class, PersonMixIn.class);

// Now Person class will use annotations from PersonMixIn

Usage Examples

Polymorphic Type Handling

// Base class with type information
@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "type"
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "dog"),
    @JsonSubTypes.Type(value = Cat.class, name = "cat"),
    @JsonSubTypes.Type(value = Bird.class, name = "bird")
})
public abstract class Animal {
    protected String name;
    protected int age;
    
    // getters/setters
}

@JsonTypeName("dog")
public class Dog extends Animal {
    private String breed;
    private boolean goodBoy = true;
    
    // getters/setters
}

@JsonTypeName("cat")  
public class Cat extends Animal {
    private int livesRemaining = 9;
    private boolean indoor;
    
    // getters/setters
}

// Usage with polymorphic type validator
PolymorphicTypeValidator validator = BasicPolymorphicTypeValidator.builder()
    .allowIfSubType("com.example.model.animals")
    .allowIfBaseType(Animal.class)
    .build();

ObjectMapper mapper = new ObjectMapper();
mapper.activateDefaultTyping(validator, ObjectMapper.DefaultTyping.NON_FINAL);

// Serialization includes type information
List<Animal> animals = Arrays.asList(
    new Dog("Rex", 5, "Golden Retriever"),
    new Cat("Whiskers", 3, true)
);

String json = mapper.writeValueAsString(animals);
// [{"type":"dog","name":"Rex","age":5,"breed":"Golden Retriever","goodBoy":true},
//  {"type":"cat","name":"Whiskers","age":3,"livesRemaining":9,"indoor":true}]

// Deserialization creates correct subtype instances
List<Animal> parsed = mapper.readValue(json, new TypeReference<List<Animal>>() {});
System.out.println(parsed.get(0).getClass()); // Dog
System.out.println(parsed.get(1).getClass()); // Cat

Object Identity Management

// Using object identity to handle circular references
@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "id"
)
public class Department {
    private Long id;
    private String name;
    private List<Employee> employees = new ArrayList<>();
    
    // getters/setters
}

@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "employeeId"
)
public class Employee {
    private Long employeeId;
    private String name;
    private Department department;
    private Employee manager;
    private List<Employee> subordinates = new ArrayList<>();
    
    // getters/setters
}

// Usage
Department engineering = new Department();
engineering.setId(1L);
engineering.setName("Engineering");

Employee alice = new Employee();
alice.setEmployeeId(100L);
alice.setName("Alice");
alice.setDepartment(engineering);

Employee bob = new Employee();
bob.setEmployeeId(200L);
bob.setName("Bob");
bob.setDepartment(engineering);
bob.setManager(alice);

alice.getSubordinates().add(bob);
engineering.getEmployees().addAll(Arrays.asList(alice, bob));

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(engineering);

// JSON uses object IDs to represent relationships:
// {"id":1,"name":"Engineering","employees":[100,200]}
// with separate definitions for employees using their IDs

Department parsed = mapper.readValue(json, Department.class);
// Object references are properly restored

Injectable Values

// Service class to be injected
public class AuditService {
    public void logAccess(String user, String operation) {
        System.out.println("User " + user + " performed " + operation);
    }
}

// POJO that uses injectable values
public class AuditableEntity {
    private String data;
    
    @JacksonInject("auditService")
    private AuditService auditService;
    
    @JacksonInject("currentUser")  
    private String currentUser;
    
    @JsonCreator
    public AuditableEntity(@JsonProperty("data") String data) {
        this.data = data;
    }
    
    @JsonSetter("data")
    public void setData(String data) {
        if (auditService != null && currentUser != null) {
            auditService.logAccess(currentUser, "data update");
        }
        this.data = data;
    }
    
    // getters/setters
}

// Usage
ObjectMapper mapper = new ObjectMapper();

// Set up injectable values
InjectableValues.Std injectableValues = new InjectableValues.Std();
injectableValues.addValue("auditService", new AuditService());
injectableValues.addValue("currentUser", "john.doe");

mapper.setInjectableValues(injectableValues);

// During deserialization, services are injected
String json = "{\"data\":\"sensitive information\"}";
AuditableEntity entity = mapper.readValue(json, AuditableEntity.class);
// AuditService and currentUser are injected automatically

entity.setData("updated information"); // Triggers audit logging

Custom Property Naming Strategy

// Custom naming strategy for API compatibility
public class LegacyApiNamingStrategy extends PropertyNamingStrategies.NamingBase {
    
    // Map of property name translations
    private static final Map<String, String> PROPERTY_MAPPINGS = Map.of(
        "firstName", "first_name",
        "lastName", "last_name", 
        "emailAddress", "email_addr",
        "phoneNumber", "phone_num",
        "createdAt", "create_time",
        "updatedAt", "update_time"
    );
    
    @Override
    public String translate(String propertyName) {
        // Check for explicit mapping first
        String mapped = PROPERTY_MAPPINGS.get(propertyName);
        if (mapped != null) {
            return mapped;
        }
        
        // Apply snake_case transformation with special rules
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < propertyName.length(); i++) {
            char c = propertyName.charAt(i);
            if (Character.isUpperCase(c)) {
                if (i > 0) {
                    result.append('_');
                }
                result.append(Character.toLowerCase(c));
            } else {
                result.append(c);
            }
        }
        
        return result.toString();
    }
}

// Usage  
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new LegacyApiNamingStrategy());

public class User {
    private String firstName;    // -> "first_name"
    private String lastName;     // -> "last_name"
    private String emailAddress; // -> "email_addr"
    private Date createdAt;      // -> "create_time"
    
    // getters/setters
}

Advanced MixIn Usage

// Original third-party class (cannot modify)
public class ExternalLibraryClass {
    private String internalId;
    private Date timestamp;
    private Map<String, Object> properties;
    
    // Only has getters, no setters
    public String getInternalId() { return internalId; }
    public Date getTimestamp() { return timestamp; }
    public Map<String, Object> getProperties() { return properties; }
}

// MixIn to add Jackson annotations
public abstract class ExternalLibraryMixIn {
    // Rename properties
    @JsonProperty("id")
    public abstract String getInternalId();
    
    // Custom date format
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    public abstract Date getTimestamp();
    
    // Unwrap properties map
    @JsonAnyGetter
    public abstract Map<String, Object> getProperties();
    
    // Add constructor for deserialization
    @JsonCreator
    public ExternalLibraryMixIn(
        @JsonProperty("id") String internalId,
        @JsonProperty("timestamp") Date timestamp,
        @JsonAnySetter Map<String, Object> properties) {}
}

// Custom deserializer to handle constructor limitation
public class ExternalLibraryDeserializer extends StdDeserializer<ExternalLibraryClass> {
    
    public ExternalLibraryDeserializer() {
        super(ExternalLibraryClass.class);
    }
    
    @Override
    public ExternalLibraryClass deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node = p.getCodec().readTree(p);
        
        // Use reflection or factory methods to create instance
        ExternalLibraryClass obj = createInstance();
        
        // Set fields using reflection
        setField(obj, "internalId", node.get("id").asText());
        setField(obj, "timestamp", parseDate(node.get("timestamp").asText()));
        
        // Handle additional properties
        Map<String, Object> props = new HashMap<>();
        Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
        while (fields.hasNext()) {
            Map.Entry<String, JsonNode> field = fields.next();
            if (!"id".equals(field.getKey()) && !"timestamp".equals(field.getKey())) {
                props.put(field.getKey(), ctxt.readTreeAsValue(field.getValue(), Object.class));
            }
        }
        setField(obj, "properties", props);
        
        return obj;
    }
    
    // Helper methods for reflection
    private ExternalLibraryClass createInstance() { /* implementation */ }
    private void setField(Object obj, String fieldName, Object value) { /* implementation */ }
    private Date parseDate(String dateStr) { /* implementation */ }
}

// Usage
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(ExternalLibraryClass.class, ExternalLibraryMixIn.class);

SimpleModule module = new SimpleModule();
module.addDeserializer(ExternalLibraryClass.class, new ExternalLibraryDeserializer());
mapper.registerModule(module);

// Now ExternalLibraryClass can be serialized/deserialized with custom behavior

Custom Handler Instantiator

// Dependency injection integration
public class SpringHandlerInstantiator extends HandlerInstantiator {
    private final ApplicationContext applicationContext;
    
    public SpringHandlerInstantiator(ApplicationContext context) {
        this.applicationContext = context;
    }
    
    @Override
    public JsonDeserializer<?> deserializerInstance(DeserializationConfig config, Annotated annotated, Class<?> deserClass) {
        // Try to get from Spring context first
        try {
            return applicationContext.getBean(deserClass);
        } catch (NoSuchBeanDefinitionException e) {
            // Fall back to default instantiation
            return (JsonDeserializer<?>) ClassUtil.createInstance(deserClass, config.canOverrideAccessModifiers());
        }
    }
    
    @Override
    public JsonSerializer<?> serializerInstance(SerializationConfig config, Annotated annotated, Class<?> serClass) {
        try {
            return applicationContext.getBean(serClass);
        } catch (NoSuchBeanDefinitionException e) {
            return (JsonSerializer<?>) ClassUtil.createInstance(serClass, config.canOverrideAccessModifiers());
        }
    }
    
    @Override
    public ValueInstantiator valueInstantiatorInstance(MapperConfig<?> config, Annotated annotated, Class<?> instClass) {
        try {
            return applicationContext.getBean(instClass);
        } catch (NoSuchBeanDefinitionException e) {
            return (ValueInstantiator) ClassUtil.createInstance(instClass, config.canOverrideAccessModifiers());
        }
    }
    
    // Implement other methods similarly
}

// Usage in Spring configuration
@Configuration
public class JacksonConfig {
    
    @Bean
    @Primary
    public ObjectMapper objectMapper(ApplicationContext context) {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setHandlerInstantiator(new SpringHandlerInstantiator(context));
        return mapper;
    }
}

// Now serializers/deserializers can be Spring beans with dependency injection
@Component
public class AuditingSerializer extends JsonSerializer<AuditableEntity> {
    
    @Autowired
    private AuditService auditService;
    
    @Override
    public void serialize(AuditableEntity value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        auditService.logSerialization(value);
        // Perform serialization
    }
}

Types

// Subtype resolver interface  
public abstract class SubtypeResolver {
    public abstract Collection<NamedType> collectAndResolveSubtypesByClass(MapperConfig<?> config, AnnotatedMember property, JavaType baseType);
    public abstract Collection<NamedType> collectAndResolveSubtypesByTypeId(MapperConfig<?> config, AnnotatedMember property, JavaType baseType);
    public NamedType findTypeByName(Collection<NamedType> subtypes, String typeName);
}

// Standard subtype resolver
public class StdSubtypeResolver extends SubtypeResolver {
    public Collection<NamedType> collectAndResolveSubtypesByClass(MapperConfig<?> config, AnnotatedMember property, JavaType baseType);
    public Collection<NamedType> collectAndResolveSubtypesByTypeId(MapperConfig<?> config, AnnotatedMember property, JavaType baseType);
    public void registerSubtypes(NamedType... types);
    public void registerSubtypes(Class<?>... classes);
    public void registerSubtypes(Collection<Class<?>> subtypes);
}

// Type resolver builder implementation
public class StdTypeResolverBuilder implements TypeResolverBuilder<StdTypeResolverBuilder> {
    public StdTypeResolverBuilder inclusion(JsonTypeInfo.As includeAs);
    public StdTypeResolverBuilder typeProperty(String propName);
    public StdTypeResolverBuilder typeIdVisibility(boolean isVisible);
    public StdTypeResolverBuilder defaultImpl(Class<?> defaultImpl);
    public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection<NamedType> subtypes);
    public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection<NamedType> subtypes);
}

// Default type ID resolver
public abstract class TypeIdResolverBase implements TypeIdResolver {
    protected final JavaType _baseType;
    protected final TypeFactory _typeFactory;
    
    protected TypeIdResolverBase();
    protected TypeIdResolverBase(JavaType baseType, TypeFactory typeFactory);
    
    public void init(JavaType bt);
    public String idFromBaseType();
    public String getDescForKnownTypeIds();
    
    // Abstract methods for subclasses
    public abstract JsonTypeInfo.Id getMechanism();
}

// Specific type ID resolver implementations
public class MinimalClassNameIdResolver extends TypeIdResolverBase {
    public JsonTypeInfo.Id getMechanism();
    public String idFromValue(Object value);
    public String idFromValueAndType(Object value, Class<?> suggestedType);
    public JavaType typeFromId(DatabindContext context, String id);
}

public class ClassNameIdResolver extends TypeIdResolverBase {
    // Similar methods but uses full class names
}

// Object ID key class
public final class IdKey implements Serializable {
    public IdKey(Class<?> scope, Class<?> type, Object key);
    
    public Class<?> getScope();
    public Class<?> getType();  
    public Object getKey();
    
    public boolean equals(Object o);
    public int hashCode();
    public String toString();
}

// Writeable object ID for serialization
public final class WritableObjectId {
    public WritableObjectId(ObjectIdGenerator<?> generator);
    public WritableObjectId(ObjectIdGenerator<?> generator, Object id);
    
    public Class<?> getScope();
    public Object generateId(Object forPojo);
    public void writeAsId(JsonGenerator gen, SerializerProvider provider, ObjectIdWriter w) throws IOException;
    public void writeAsField(JsonGenerator gen, SerializerProvider provider, ObjectIdWriter w) throws IOException;
}

// Readable object ID for deserialization  
public class ReadableObjectId {
    public ReadableObjectId(Object id);
    public ReadableObjectId bindItem(Object ob, Object id);
    
    public Object getKey();
    public Object getValue();
    public Class<?> getScope();
    public boolean hasReferringProperties();
    public Iterator<ObjectIdReferenceProperty> referringProperties();
}

<function_calls> <invoke name="TodoWrite"> <parameter name="todos">[{"content": "Create entry-point document (index.md) with overview and key API snippets", "status": "completed", "activeForm": "Creating entry-point document"}, {"content": "Create object-mapping.md sub-document covering ObjectMapper, ObjectReader, ObjectWriter", "status": "completed", "activeForm": "Creating object-mapping.md"}, {"content": "Create json-tree-model.md sub-document covering JsonNode hierarchy and tree manipulation", "status": "completed", "activeForm": "Creating json-tree-model.md"}, {"content": "Create type-system.md sub-document covering JavaType and type handling", "status": "completed", "activeForm": "Creating type-system.md"}, {"content": "Create serialization.md sub-document covering JsonSerializer and serialization framework", "status": "completed", "activeForm": "Creating serialization.md"}, {"content": "Create deserialization.md sub-document covering JsonDeserializer and deserialization framework", "status": "completed", "activeForm": "Creating deserialization.md"}, {"content": "Create configuration.md sub-document covering features, settings, and configuration", "status": "completed", "activeForm": "Creating configuration.md"}, {"content": "Create annotations.md sub-document covering Jackson databind annotations", "status": "completed", "activeForm": "Creating annotations.md"}, {"content": "Create modules.md sub-document covering Module system and extensibility", "status": "completed", "activeForm": "Creating modules.md"}, {"content": "Create advanced-features.md sub-document covering polymorphism, custom handlers, etc.", "status": "completed", "activeForm": "Creating advanced-features.md"}]

Install with Tessl CLI

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

docs

advanced-features.md

annotations.md

configuration.md

deserialization.md

index.md

json-tree-model.md

modules.md

object-mapping.md

serialization.md

type-system.md

tile.json