This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Jackson modules-base is a multi-module Maven project containing 11 foundational Jackson 3 extension modules that build directly on jackson-databind. Each module is independent (no inter-module dependencies).
Modules: afterburner, blackbird, mrbean, guice, guice7, jaxb, jakarta-xmlbind, osgi, android-record, no-ctor-deser, spi-subtypes
(paranamer is not part of 3.x — it only appears commented out in the root pom.xml.)
There are also three test-only, never-published modules: afterburner-tests and blackbird-tests have no module-info.java, so their test POJOs live in the unnamed module, as in most applications (see each module's README.md). For Afterburner this covers the bytecode-generation paths it disables for beans in named JPMS modules; Blackbird's in-tree tests run inside Blackbird's own named module, and blackbird-tests also holds the tests that need the packaged jar or other JDKs; blackbird-jpms-tests is a foreign named module that requires blackbird and runs on the module path.
Blackbird builds only on JDK 25+: blackbird, blackbird-tests and blackbird-jpms-tests are in the root pom's blackbird-jdk25 profile (activated on JDK 25+). On an older JDK the full build silently leaves them out, and -pl blackbird fails with "Could not find the selected project in the reactor"; use a JDK 25 (JAVA_HOME=... ./mvnw ...) for Blackbird work.
Maven coordinates: groupId tools.jackson.module, parent tools.jackson:jackson-base; depends on tools.jackson.core:jackson-databind.
# Full build (all modules)
./mvnw -B -q -ff -ntp verify
# Build a single module
./mvnw -B -q -ff -ntp verify -pl afterburner
# Run tests only (all modules)
./mvnw -B -ff -ntp test
# Run tests for a single module
./mvnw -B -ff -ntp test -pl mrbean
# Blackbird modules need JDK 25+ (not in the reactor on older JDKs)
JAVA_HOME=/path/to/jdk25 ./mvnw -B -ff -ntp test -pl blackbird
# Run a single test class
./mvnw -B -ff -ntp test -pl afterburner -Dtest=TestSimpleSerialize
# Run a single test method
./mvnw -B -ff -ntp test -pl afterburner -Dtest=BasicDeserializeTest#testIntMethodJava 17 is the minimum (javac.src.version 17); CI (main.yml) tests against 17, 21, 24, 25; Blackbird builds only in the 25 job, which also runs its runtime tests on 17 and 21 through -Dblackbird.test.oldJdks. The databind-push rebuild (dep_build_v3.yml) builds all other modules on 17 and 21 and only the Blackbird modules on 25, with the same old-JDK tests; keep the old-JDK wiring of the two workflows in sync. osgi and afterburner-tests add --add-opens java.base/java.lang=ALL-UNNAMED to their test argLine.
Every module follows the same pattern:
- A
*Moduleclass (e.g.,AfterburnerModule,BlackbirdModule) extends Jackson'stools.jackson.databind.JacksonModule, registered on a mapper builder (e.g.,JsonMapper.builder().addModule(...)) - Package:
tools.jackson.module.<name>(hyphens dropped or turned into sub-packages:androidrecord,noctordeser,spisubtypes,jakarta.xmlbind) PackageVersion.javais generated fromPackageVersion.java.inby the replacer Maven plugin — do not edit manually- JPMS module descriptors are real sources:
<module>/src/main/java/module-info.java(andsrc/test/java/module-info.javafor tests). Moditect is no longer used; the straysrc/moditect/dir in android-record is a leftover - SPI registration:
src/main/resources/META-INF/services/tools.jackson.databind.JacksonModule(all modules except guice, guice7, osgi)
- Performance (bytecode generation): afterburner (Byte Buddy-based), blackbird (generated per-bean codecs through the JDK ClassFile API; a multi-release jar that builds on JDK 25+ and is active only on 25+; on Java 17-24 module discovery skips it and explicit
addModulethrowsIllegalStateException, seeblackbird/README.md) — both disable themselves automatically in GraalVM native images viaNativeImageUtil.isInNativeImage()check insetupModule - DI integration: guice (javax.inject), guice7 (jakarta.inject) — note: guice's
ObjectMapperModuleimplements Guice'scom.google.inject.Module, not Jackson'sJacksonModule - Type materialization: mrbean (generates implementations for interfaces/abstract classes, Byte Buddy-based)
- Annotation support: jaxb (javax.xml.bind), jakarta-xmlbind (jakarta.xml.bind)
- Other: osgi (OSGi service injection), android-record (Android desugared records), no-ctor-deser (no default constructor), spi-subtypes (SPI-based subtype registration)
Unlike 2.x, nothing is shaded: afterburner and mrbean depend on net.bytebuddy:byte-buddy (version managed in the root pom as version.bytebuddy) as a regular dependency. ASM appears only as a test dependency.
- Framework: JUnit 5 (Jupiter)
- Base test classes: Each module has its own (e.g.,
AfterburnerTestBase,BlackbirdTestBase,BaseJaxbTest,BaseTest) providing mapper construction helpers and shared test types - Test location:
<module>/src/test/java/tools/jackson/module/<name>/ - Tests use static imports from
org.junit.jupiter.api.Assertions - Mapper construction in tests: Use
mapperBuilder()(returnsJsonMapper.Builderwith module pre-registered) ornewObjectMapper()factory methods from the test base class;newVanillaJSONMapper()gives a baseline mapper without the module - Test helpers:
q("str")wraps in double-quotes,a2q("{'a':1}")converts single to double quotes; assertion helpersverifyException(),assertToken() - SPI test:
ModuleSPIMetadataTestverifies discovery viaServiceLoader.load(JacksonModule.class); present in afterburner, android-record, blackbird, jakarta-xmlbind, mrbean, no-ctor-deser, spi-subtypes (not yet in jaxb, which is registered)
- Main branches:
3.x(Jackson 3 development, default branch) and2.x(head of the 2.x line); there is nomaster - Development branches: per-minor-version branches (e.g.,
3.0,3.1,3.2;2.21,2.22); fixes merge forward (e.g.,2.21→2.22→2.x→3.1→3.2→3.x) - Current version (this branch,
3.x): 3.3.0-SNAPSHOT - Releases use maven-release-plugin; snapshots deploy to Sonatype Central Portal