This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
- Don’t assume. Don’t hide confusion. Surface tradeoffs.
- Minimum code that solves the problem. Limit speculative additions.
- Touch only what you must, clean up only your own mess -- but do suggest additional related fixes.
- Define success criteria. Loop until verified.
This is jackson-databind, the general-purpose data-binding functionality and tree-model for Jackson Data Processor. It builds on the Streaming API (jackson-core) and uses jackson-annotations for configuration. This is the 3.x branch (Jackson 3.0+) which requires JDK 17+ and uses the tools.jackson package namespace (2.x used com.fasterxml.jackson).
Key characteristics:
- ~790 test files with comprehensive test coverage
- Thread-safe mapper instances (as of Jackson 3.0)
- Maven-based build system with Maven wrapper (
./mvnw) - Supports multiple JDK versions (17, 21, 25) with special test profiles
# Full build with tests
./mvnw clean verify
# Build without tests (faster)
./mvnw clean install -DskipTests
# Run tests only
./mvnw test
# Run a specific test class
./mvnw test -Dtest=ClassName
# Run a specific test method
./mvnw test -Dtest=ClassName#methodName
# Generate test report
./create-test-report.sh # runs: mvn surefire-report:report
# Verify Android SDK compatibility
./mvnw animal-sniffer:check
# JDK 21+ test sources: the `java21` profile auto-activates on JDK 21+,
# so no flag is normally needed (`-Pjava21` just forces it on)# Run with ErrorProne static analysis
./mvnw verify -Perrorprone
# Generate code coverage report
./mvnw test jacoco:report
# Report will be in target/site/jacoco/
# Check dependencies
./mvnw dependency:tree-
ObjectMapper (
ObjectMapper.java): The main entry point for all Jackson databind operations- Thread-safe and fully immutable (as of 3.0)
- Uses builder pattern for construction (
JsonMapper.builder()for JSON) - Contains caches for serializers/deserializers
-
Serialization Path (
ser/package):SerializerFactory/BeanSerializerFactory: Creates serializersValueSerializer: Base class for all serializersBeanSerializer: Handles POJO serializationBeanPropertyWriter: Writes individual bean propertiesSerializationContext: Context for serialization process
-
Deserialization Path (
deser/package):DeserializerFactory/BeanDeserializerFactory: Creates deserializersValueDeserializer: Base class for all deserializersBeanDeserializer(indeser/bean/) /BeanDeserializerBuilder: Handles POJO deserializationSettableBeanProperty: Represents a settable bean propertyDeserializationContext: Context for deserialization process
-
Type System (
type/package):JavaType(in rootdatabindpackage): Represents Java types with full generic informationTypeFactory: Creates JavaType instances- Critical for handling generics correctly
-
Introspection (
introspect/package):AnnotatedClass,AnnotatedMethod,AnnotatedField: Represents annotated membersAnnotationIntrospector(in rootdatabindpackage): Processes annotations to configure behavior- Handles reflection and metadata extraction
-
Configuration:
MapperConfig(incfg/): Base configurationSerializationConfig/DeserializationConfig(in rootdatabindpackage): Specific configurationsMapperFeature,SerializationFeature,DeserializationFeature(in rootdatabindpackage): Feature flagsPackageVersion(incfg/): Generated file containing version information
-
Tree Model:
JsonNode(in rootdatabindpackage): Abstract base for all node typesObjectNode,ArrayNode,StringNode, etc. (innode/package): Concrete node types. Note: 2.x'sTextNodeis namedStringNodein 3.x- Alternative to POJO binding for dynamic structures
tools.jackson.databind- Core classes (ObjectMapper, configs, features)tools.jackson.databind.ser- Serialization infrastructuretools.jackson.databind.deser- Deserialization infrastructuretools.jackson.databind.type- Type system and TypeFactorytools.jackson.databind.introspect- Reflection and metadatatools.jackson.databind.node- Tree model (JsonNode hierarchy)tools.jackson.databind.annotation- Databind-specific annotationstools.jackson.databind.json- JSON-specific mapper (JsonMapper)tools.jackson.databind.jsontype- Polymorphic type handlingtools.jackson.databind.jsonFormatVisitors- Schema generation visitorstools.jackson.databind.exc- Exception typestools.jackson.databind.util- Utility classestools.jackson.databind.module- Module systemtools.jackson.databind.ext- External type integrations
- Builder Pattern: ObjectMapper uses immutable builder pattern (3.x change)
- Factory Pattern: SerializerFactory and DeserializerFactory create handlers
- Caching: Serializers/deserializers are cached for performance
- Context Objects: SerializationContext and DeserializationContext carry state
- Visitor Pattern: JsonFormatVisitorWrapper for schema generation
Tests are organized by functional area under src/test/java/tools/jackson/databind/:
deser/- Deserialization testsser/- Serialization testsnode/- Tree model teststype/- Type system testsintrospect/- Introspection testsjsontype/- Polymorphic type handling testsconvert/- Conversion testsformat/- Format-specific testsmixins/- Mixin annotation testsmodule/- Module system testsobjectid/- Object identity testsrecords/- Java Records support testsviews/- JSON Views testsstruct/- Structural type testsseq/- Sequence (streaming read/write) testsmisc/- Miscellaneous testscfg/,contextual/,access/,exc/,ext/,interop/,json/,jsonschema/,util/- Other functional areastofix/- Known failing tests (deferred fixes)testutil/- Test utilities and base classes (@JacksonTestFailureExpectedlives intestutil/failure/)
Use DatabindTestUtil class (in testutil/ package) which extends JacksonTestUtilBase:
- Provides common assertion methods
- Sample JSON documents and constants
- Helper methods for ObjectMapper creation
- JUnit 5 based (migrated from JUnit 4)
Tests for known bugs that have not yet been fixed should be placed in the tofix/ package and annotated with @JacksonTestFailureExpected (in addition to @Test). This annotation inverts the test outcome via JacksonTestFailureExpectedInterceptor:
- If the test throws an exception (the expected behavior for an unfixed bug), the test passes.
- If the test passes without error (meaning the bug was fixed), the test fails with a
JacksonTestShouldFailException— signaling that the annotation (and possibly thetofix/placement) should be removed.
This ensures known-failing tests don't break the build, while automatically detecting when a fix makes them pass so they can be promoted to regular tests.
src/test-jdk21/java/- Tests that require JDK 21+ features- These are only compiled/run when building with JDK 21+
- Prefer text blocks (""" separator) over other mechanisms (like "a2q" or backslash escaping)
- Avoid "test" prefix in methods (legacy code has these)
- JDK Baseline: Jackson 3.x requires JDK 17 minimum
- Android SDK: Jackson 3.0 requires Android SDK 34+
- Package Namespace:
- Jackson 1.x:
org.codehaus.jackson.map - Jackson 2.x:
com.fasterxml.jackson.databind - Jackson 3.x:
tools.jackson.databind(current)
- Jackson 1.x:
- Dependencies:
tools.jackson.core:jackson-core(streaming API)com.fasterxml.jackson.core:jackson-annotations(still 2.x groupId andcom.fasterxml.jackson.annotationpackage)
Active 3.x lines (three roles):
3.x- Development branch (a.k.a. mainline / integration branch): ongoing work toward the next minor (3.3.0-SNAPSHOT). Exactly one.3.2- Latest release branch: the latest released minor (3.2.x), the line users are steered toward. Exactly one per major.3.1,3.0- Maintenance branches: older released minors still getting fixes. Zero or more.
The asymmetry: one development branch, one latest-release branch, and zero-or-more maintenance branches behind it. As releases progress a branch ages down — when 3.3 ships, 3.2 becomes a maintenance branch and 3.3 becomes the latest release branch.
Fixes are merged forward: they land on the oldest affected released line and are merged up one step at a time toward 3.x (e.g. Merge branch '3.1' into 3.2, then Merge branch '3.2' into 3.x).
Long-Term Support (LTS) is an orthogonal designation, not reflected in branch names: a released line marked LTS keeps getting fixes well past the point a normal maintenance branch would be retired. Current LTS lines: 3.1, 2.21, 2.18. A branch's LTS status is independent of its role above — 3.1 kept its LTS status after aging down from latest release branch to maintenance branch.
Legacy 2.x lines:
2.x- Development branch, next minor 2.x version (2.23.0-SNAPSHOT)2.22- Latest release branch of 2.x2.21,2.18- Maintenance branches (both LTS)
- Parent POM:
tools.jackson:jackson-base, version-locked to the project version, which tracks the branch (3.1.6-SNAPSHOTon3.1,3.3.0-SNAPSHOTon3.x, ...) - Generated file:
PackageVersion.java, intotools.jackson.databind.cfg(via maven-replacer-plugin) - Special profiles:
java21- Enables JDK 21+ test sources (src/test-jdk21/java/); auto-activated by<jdk>[21,)</jdk>errorprone- Enables ErrorProne static analysisrelease- Skips tests for release builds
Tests require these JVM arguments (defined in pom.xml):
--add-opens=java.base/java.lang=tools.jackson.databind
--add-opens=java.base/java.util=tools.jackson.databind
- Serializers should extend
ValueSerializer<T>and overrideserialize() - Deserializers should extend
ValueDeserializer<T>and overridedeserialize() - Check if contextual configuration is needed (override
createContextual(), defined directly onValueSerializer/ValueDeserializerin 3.x -- the 2.xContextualSerializer/ContextualDeserializerinterfaces are gone;ContextualKeyDeserializerremains for key deserializers) - Consider caching implications - deserializers are heavily cached
- Handle null values appropriately
- Add feature flag to appropriate enum (
MapperFeature,SerializationFeature,DeserializationFeature) - Update configuration classes to handle the feature
- Add comprehensive tests in appropriate test package
- Consider backward compatibility with 2.x if relevant
- Find or create test that reproduces the issue (in
tofix/package if deferred) - Fix should typically be in factory, serializer, or deserializer layer
- Ensure fix doesn't break existing tests
- Thread Safety: ObjectMapper is fully thread-safe and immutable in 3.x
- Caching: Root-level deserializers are always cached with full generic type info
- Type Handling: Use
TypeFactoryfor creatingJavaTypeinstances with generics - Builder Pattern: Always use builder for ObjectMapper construction in 3.x
- Annotations: Jackson annotations (2.x) are still in the
com.fasterxml.jackson.annotationpackage (published under thecom.fasterxml.jackson.coregroupId)