Jackson 2 and Jackson 3
Since version 4.19, Camel Spring Boot is based on Spring Boot 4, which uses Jackson 3 (tools.jackson) by default. Camel supports both Jackson lines:
Jackson 2 (com.fasterxml.jackson) | Jackson 3 (tools.jackson) |
|---|---|
Both lines register the same data format names (jackson, jacksonXml, avroJackson, protobufJackson), the same data type transformers (application-json, …) and the same configuration prefix (camel.dataformat.jackson.), so routes and properties do not need to change when switching. As a consequence, *only one line can be used in an application.
Many Camel components (for example Kafka, Salesforce, OpenAPI, Micrometer) use Jackson 2 internally, so the Jackson 2 libraries are often on the classpath next to Spring Boot’s Jackson 3. This is expected and supported: the two lines use different Java packages. Only the Camel Jackson modules listed above must not be mixed.
Rules
-
Use either
camel-jackson-starterorcamel-jackson3-starter, never both. With both on the classpath the application fails to start with aBeanDefinitionOverrideExceptionforconfigureJacksonDataFormatFactory. The same applies to the XML, Avro and Protobuf variants. -
Some starters bring
camel-jackson(Jackson 2) transitively:camel-mongodb-starter,camel-mongodb-gridfs-starter,camel-jq-starter,camel-neo4j-starter,camel-aws-bedrock-starter,camel-google-vertexai-starterandcamel-dhis2-starter. If you combine them withcamel-jackson3-starter, the order of the dependencies decides, without any warning, which data formatmarshal().json(), REST DSL binding and the JSON transformers use. When the Jackson 2 data format wins, thecamel.dataformat.jackson.*properties are ignored: thecamel-jackson3-starteronly applies them to Jackson 3 data format instances.Check with:
mvn dependency:tree -Dincludes=org.apache.camel:camel-jackson,org.apache.camel:camel-jackson3In that case, either declare
camel-jackson3-starterbefore those starters, or reference the data format explicitly:marshal("jackson")with a Jackson 3JacksonDataFormatbean, or an instance passed tomarshal(). Configure that bean in Java, not withcamel.dataformat.jackson.*properties. The starter does apply those properties to this Jackson 3 instance, but Camel binds them through the property configurer named after the data format (jackson-dataformat), which both modules provide. Whilecamel-jacksoncomes first on the classpath, its Jackson 2 configurer is used, and the application fails to start with aPropertyBindingException. Do not excludecamel-jacksonfrom those starters: they need it. -
Kamelet schema resolution (
camel-kamelet) only supports the Jackson 2 modules. Applications that rely on it must stay oncamel-jackson-starter.
Upgrading from Camel Spring Boot 4.18
Upgrade first with the Jackson line you already use (camel-jackson-starter), and move to Jackson 3 as a separate step.
Staying on Jackson 2
Spring Boot 4 no longer creates a Jackson 2 ObjectMapper. If you relied on camel.dataformat.jackson.auto-discover-object-mapper=true to reuse Spring’s mapper (and spring.jackson.* properties), Camel now silently uses its own default mapper instead. Either:
-
declare your own Jackson 2 mapper, which Camel discovers:
@Bean com.fasterxml.jackson.databind.ObjectMapper camelObjectMapper() { return new com.fasterxml.jackson.databind.ObjectMapper(); // configure as needed } -
or add
org.springframework.boot:spring-boot-jackson2(deprecated in Spring Boot 4) and rename yourspring.jackson.properties tospring.jackson2.. Properties underspring.jackson.*only configure Spring Boot’s Jackson 3 mapper.
Custom mappers given to components that use Jackson 2 internally (for example the objectMapper option of camel-salesforce or camel-servicenow) must be Jackson 2 ObjectMapper instances.
Moving to Jackson 3
The Camel Jackson 3 data formats use Jackson’s default configuration and do not override it, so every Jackson 3 change applies to your routes: package names, annotations, default settings, date/time handling and exceptions. The Jackson project documents these changes:
-
JSTEP-2: Jackson 3 default settings, behavior changes (complete list of default changes)
The steps below cover what is specific to Camel and Camel Spring Boot.
Before you start
-
Check that the application can move:
-
Kamelets that resolve data type schemas require the Jackson 2 modules. Stay on
camel-jackson-starter. -
If the application uses one of the starters that bring
camel-jackson, read the Rules first.
-
-
Find the Jackson 2 code in your application:
grep -rlE 'com\.fasterxml\.jackson\.(core|databind|datatype|dataformat|module)' src/ mvn dependency:tree -Dincludes=com.fasterxml.jackson.core,com.fasterxml.jackson.datatype,org.apache.camel:camel-jacksoncom.fasterxml.jackson.annotationimports (@JsonProperty,@JsonIgnore,@JsonFormat, …) are shared by Jackson 2 and Jackson 3 and do not need to change. -
Add tests that capture the JSON your routes and REST endpoints produce and accept today: marshal a representative object and compare it with a stored file, and unmarshal stored payloads. Run them before and after the migration. Most Jackson 3 changes do not raise errors; they produce different JSON.
Update the dependencies
-
Replace each Camel Jackson 2 starter with its Jackson 3 counterpart, as listed in the table at the top of this page.
-
Replace the direct Jackson 2 dependencies of your own code:
com.fasterxml.jackson.core:jackson-databindbecomestools.jackson.core:jackson-databind, and Jackson 2 modules become thetools.jackson.*modules of the same name. Removejackson-datatype-jsr310,jackson-datatype-jdk8andjackson-module-parameter-names: Jackson 3 includes them. Keepcom.fasterxml.jackson.core:jackson-annotations, which Jackson 3 uses too. -
Do not remove or exclude the Jackson 2 libraries that Camel components bring transitively. They are still needed.
Migrate the Java code
The OpenRewrite recipe performs most of the mechanical changes: packages, Maven coordinates, renamed types and methods, and exception types.
mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-jackson:RELEASE \
-Drewrite.activeRecipes=org.openrewrite.java.jackson.UpgradeJackson_2_3 Review the result against the Jackson 3 Migration Guide. Pay attention to the databind annotations (@JsonSerialize, @JsonDeserialize, @JsonNaming, …): they moved to tools.jackson.databind.annotation, and Jackson 3 silently ignores the old com.fasterxml.jackson.databind.annotation ones.
Spring Boot customizations of the Jackson mapper change as well:
| Spring Boot 3 / Jackson 2 | Spring Boot 4 / Jackson 3 |
|---|---|
|
|
|
|
|
|
Migrate the Camel configuration
-
Routes.
marshal().json(),json(JsonLibrary.Jackson),marshal("jackson"), REST DSL binding and theapplication-jsontransformers keep working unchanged. Only Java code that creates the data format changes its import:org.apache.camel.component.jackson.JacksonDataFormatbecomesorg.apache.camel.component.jackson3.JacksonDataFormat. The same applies toListJacksonDataFormat, to the XML, Avro and Protobuf data formats, and to class names referenced in YAML or XML routes. -
Custom mapper. The
objectMapperoption and thecamel.dataformat.jackson.object-mapperproperty take a Jackson 3tools.jackson.databind.ObjectMapper, for example aJsonMapper. -
Modules.
camel.dataformat.jackson.module-class-namesandmodule-refsmust reference Jackson 3 modules (tools.jackson.databind.JacksonModule). -
Features. In
enable-featuresanddisable-features, use plain feature names, or the Jackson 3 class name as the prefix. Some features moved to another class in Jackson 3, and the old prefix fails at startup:# works on both Jackson 2 and Jackson 3 camel.dataformat.jackson.enable-features=WRITE_DATES_AS_TIMESTAMPS # fails at startup on Jackson 3: the feature moved to DateTimeFeature # camel.dataformat.jackson.enable-features=SerializationFeature.WRITE_DATES_AS_TIMESTAMPSFeature names that were removed in Jackson 3 also fail at startup, with
IllegalArgumentException: Enable feature: … cannot be converted to an accepted enum. -
Reusing the Spring Boot mapper. Set
camel.dataformat.jackson.auto-discover-object-mapper=trueso routes use theJsonMapperthat Spring Boot creates: routes and Spring MVC controllers then produce the same JSON, andspring.jackson.applies to both. Without it, Camel uses its own mapper andspring.jackson.has no effect on routes. Two things to know:-
Camel does not apply its own
camel.dataformat.jackson.customizations, such as features, modules,timezoneornaming-strategy, to a discovered mapper. Configure them withspring.jackson.or aJsonMapperBuilderCustomizerinstead. -
Discovery only works when exactly one Jackson 3
ObjectMapperbean exists. Otherwise Camel silently creates its own default mapper.
-
-
Error handling. Jackson 3 exceptions are unchecked and are not
IOExceptions. ReplaceonException(IOException.class)andonException(JsonProcessingException.class)clauses that handle JSON errors withonException(tools.jackson.core.JacksonException.class).
Review the payload changes
Because Camel’s Jackson 3 data formats use Jackson’s defaults, the JSON your routes produce and accept changes. The most visible changes are:
| Change | Effect |
|---|---|
Properties are sorted alphabetically | Output order changes, usually the first visible difference |
|
|
| Serialization that failed before now works |
Enums use | Enum values change, both when writing and when reading |
Unknown properties are ignored | Payloads with extra fields no longer fail |
|
|
Collections with only a getter and | Data is silently missing after unmarshalling |
Properties without a view are excluded when a | Fields disappear from the output |
| Custom serializers silently stop applying |
See JSTEP-2 for the complete list.
Payloads written by a Jackson 2 data format are not always readable by a Jackson 3 data format with default settings, and the other way round (for example enums with a custom toString()). If other services still read or write Jackson 2 payloads, upgrade producers and consumers together, or keep the previous format with one of these options:
-
Reuse the Spring Boot mapper (
auto-discover-object-mapper=true) and setspring.jackson.use-jackson2-defaults=true. This also changes the JSON of your Spring MVC controllers. -
Or give only Camel a mapper with Jackson 2 defaults, using a
DataFormatCustomizerbean. Thecamel.dataformat.jackson.*properties are still applied on top of it:@Bean DataFormatCustomizer camelJackson2Defaults() { return DataFormatCustomizer.forType(org.apache.camel.component.jackson3.JacksonDataFormat.class, df -> df.setObjectMapper(JsonMapper.builderWithJackson2Defaults().build())); }Do not declare the mapper as a
JsonMapperbean for this purpose: it replaces the mapper that Spring Boot creates, so your Spring MVC controllers would use it as well.
Neither option restores every Jackson 2 default. @JsonView default inclusion, property names derived from getters such as getXName(), and Jackson 2 databind annotations still behave differently. Fix those in your model classes and cover them with the tests from Before you start.
Verify
-
Check that only the Jackson 3 Camel modules are present:
mvn dependency:tree -Dincludes=org.apache.camel:camel-jackson,org.apache.camel:camel-jackson3camel-jacksonmust not appear, unless a starter that requires it brings it; in that case see Rules. -
Run the payload tests. Investigate every difference, even when the JSON is equivalent: other systems may depend on the exact format.
-
Start the application and exercise the routes that parse invalid input, to confirm that the new
onExceptionclauses are triggered.
Jackson versions
The camel-spring-boot-bom does not manage Jackson, so the Jackson 2 and Jackson 3 versions come from the Spring Boot BOM (spring-boot-dependencies). They can differ from the versions Camel is built and tested with (the jackson2-version and jackson3-version properties of the Camel parent POM). Check the resolved versions with:
mvn dependency:list | grep -E 'jackson-(databind|annotations)' If you override them, override both lines together and use matching release trains (for example Jackson 2.22.x with Jackson 3.2.x), because both lines share com.fasterxml.jackson.core:jackson-annotations.