This is an automated email from the ASF dual-hosted git repository.

Croway pushed a commit to branch camel-spring-boot-4.22.x
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git


The following commit(s) were added to refs/heads/camel-spring-boot-4.22.x by 
this push:
     new 9affdbc23dc [backport camel-spring-boot-4.22.x] CAMEL-25338: Document 
Jackson 2 / Jackson 3 usage and migration (#2019)
9affdbc23dc is described below

commit 9affdbc23dcc2b86f4b91cd4bfe731fd84bb4f54
Author: Federico Mariani <[email protected]>
AuthorDate: Tue Oct 6 09:45:14 2026 +0200

    [backport camel-spring-boot-4.22.x] CAMEL-25338: Document Jackson 2 / 
Jackson 3 usage and migration (#2019)
    
    * CAMEL-25338: Document Jackson 2 / Jackson 3 usage and migration
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    (cherry picked from commit c166dd1f6dabf8d1ea2de79cc443f6989ec18dfd)
    
    * CAMEL-25338: Clarify when camel.dataformat.jackson.* is ignored and when 
it fails
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    (cherry picked from commit e5d5a00cfd16056949075badd4f16f566e99d83e)
    
    ---------
    
    Co-authored-by: Claude Opus 5.5 <[email protected]>
---
 docs/spring-boot/modules/ROOT/nav.adoc           |   1 +
 docs/spring-boot/modules/ROOT/pages/jackson.adoc | 256 +++++++++++++++++++++++
 2 files changed, 257 insertions(+)

diff --git a/docs/spring-boot/modules/ROOT/nav.adoc 
b/docs/spring-boot/modules/ROOT/nav.adoc
index c230d2d6821..0bdff90fb05 100644
--- a/docs/spring-boot/modules/ROOT/nav.adoc
+++ b/docs/spring-boot/modules/ROOT/nav.adoc
@@ -2,6 +2,7 @@
 * xref:spring-boot.adoc[Camel Context starter]
 * xref:list.adoc[List of starters]
 * xref:starter-configuration.adoc[Starter Configuration]
+* xref:jackson.adoc[Jackson 2 and Jackson 3]
 * Starters
 // starters: START
 ** xref:starters/a2a.adoc[A2A]
diff --git a/docs/spring-boot/modules/ROOT/pages/jackson.adoc 
b/docs/spring-boot/modules/ROOT/pages/jackson.adoc
new file mode 100644
index 00000000000..21bbf09dc12
--- /dev/null
+++ b/docs/spring-boot/modules/ROOT/pages/jackson.adoc
@@ -0,0 +1,256 @@
+= 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:
+
+[options="header"]
+|===
+| Jackson 2 (`com.fasterxml.jackson`) | Jackson 3 (`tools.jackson`)
+| xref:starters/jackson.adoc[`camel-jackson-starter`] | 
xref:starters/jackson3.adoc[`camel-jackson3-starter`]
+| xref:starters/jacksonxml.adoc[`camel-jacksonxml-starter`] | 
xref:starters/jackson3xml.adoc[`camel-jackson3xml-starter`]
+| xref:starters/jackson-avro.adoc[`camel-jackson-avro-starter`] | 
xref:starters/jackson3-avro.adoc[`camel-jackson3-avro-starter`]
+| xref:starters/jackson-protobuf.adoc[`camel-jackson-protobuf-starter`] | 
xref:starters/jackson3-protobuf.adoc[`camel-jackson3-protobuf-starter`]
+|===
+
+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-starter` or `camel-jackson3-starter`, never both. 
With both on the classpath the
+  application fails to start with a `BeanDefinitionOverrideException` for 
`configureJacksonDataFormatFactory`.
+  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-starter` and `camel-dhis2-starter`. If you combine 
them with `camel-jackson3-starter`, the
+  order of the dependencies decides, without any warning, which data format 
`marshal().json()`, REST DSL binding and
+  the JSON transformers use. When the Jackson 2 data format wins, the 
`camel.dataformat.jackson.*` properties are
+  ignored: the `camel-jackson3-starter` only applies them to Jackson 3 data 
format instances.
++
+Check with:
++
+[source,bash]
+----
+mvn dependency:tree 
-Dincludes=org.apache.camel:camel-jackson,org.apache.camel:camel-jackson3
+----
++
+In that case, either declare `camel-jackson3-starter` before those starters, 
or reference the data format explicitly:
+`marshal("jackson")` with a Jackson 3 `JacksonDataFormat` bean, or an instance 
passed to `marshal()`. Configure that
+bean in Java, not with `camel.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. While `camel-jackson` 
comes first on the classpath, its Jackson 2
+configurer is used, and the application fails to start with a 
`PropertyBindingException`. Do not exclude
+`camel-jackson` from those starters: they need it.
+* Kamelet schema resolution (`camel-kamelet`) only supports the Jackson 2 
modules. Applications that rely on it must
+  stay on `camel-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:
++
+[source,java]
+----
+@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 your
+  `spring.jackson.*` properties to `spring.jackson2.*`. Properties under 
`spring.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:
+
+* 
https://github.com/FasterXML/jackson/blob/main/jackson3/MIGRATING_TO_JACKSON_3.md[Jackson
 3 Migration Guide]
+* https://github.com/FasterXML/jackson-future-ideas/wiki/JSTEP-2[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,Rules>> first.
+* Find the Jackson 2 code in your application:
++
+[source,bash]
+----
+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-jackson
+----
++
+`com.fasterxml.jackson.annotation` imports (`@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-databind` becomes
+  `tools.jackson.core:jackson-databind`, and Jackson 2 modules become the 
`tools.jackson.*` modules of the same name.
+  Remove `jackson-datatype-jsr310`, `jackson-datatype-jdk8` and 
`jackson-module-parameter-names`: Jackson 3 includes
+  them. Keep `com.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 
https://docs.openrewrite.org/recipes/java/jackson/upgradejackson_2_3[OpenRewrite
 recipe] performs most of the
+mechanical changes: packages, Maven coordinates, renamed types and methods, 
and exception types.
+
+[source,bash]
+----
+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:
+
+[options="header"]
+|===
+| Spring Boot 3 / Jackson 2 | Spring Boot 4 / Jackson 3
+| `Jackson2ObjectMapperBuilderCustomizer` | `JsonMapperBuilderCustomizer`
+| `@JsonComponent`, `JsonObjectSerializer`, `JsonObjectDeserializer` | 
`@JacksonComponent`, `ObjectValueSerializer`, `ObjectValueDeserializer`
+| `ObjectMapper` bean | `JsonMapper` bean
+|===
+
+=== Migrate the Camel configuration
+
+* *Routes.* `marshal().json()`, `json(JsonLibrary.Jackson)`, 
`marshal("jackson")`, REST DSL binding and the
+  `application-json` transformers keep working unchanged. Only Java code that 
creates the data format changes its
+  import: `org.apache.camel.component.jackson.JacksonDataFormat` becomes
+  `org.apache.camel.component.jackson3.JacksonDataFormat`. The same applies to 
`ListJacksonDataFormat`, to the XML,
+  Avro and Protobuf data formats, and to class names referenced in YAML or XML 
routes.
+* *Custom mapper.* The `objectMapper` option and the 
`camel.dataformat.jackson.object-mapper` property take a
+  Jackson 3 `tools.jackson.databind.ObjectMapper`, for example a `JsonMapper`.
+* *Modules.* `camel.dataformat.jackson.module-class-names` and `module-refs` 
must reference Jackson 3 modules
+  (`tools.jackson.databind.JacksonModule`).
+* *Features.* In `enable-features` and `disable-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:
++
+[source,properties]
+----
+# 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_TIMESTAMPS
+----
++
+Feature 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=true` so routes use the
+  `JsonMapper` that Spring Boot creates: routes and Spring MVC controllers 
then produce the same JSON, and
+  `spring.jackson.*` applies to both. Without it, Camel uses its own mapper 
and `spring.jackson.*` has no effect on
+  routes. Two things to know:
+** Camel does not apply its own `camel.dataformat.jackson.*` customizations, 
such as features, modules, `timezone` or
+   `naming-strategy`, to a discovered mapper. Configure them with 
`spring.jackson.*` or a `JsonMapperBuilderCustomizer`
+   instead.
+** Discovery only works when exactly one Jackson 3 `ObjectMapper` bean exists. 
Otherwise Camel silently creates its own
+   default mapper.
+* *Error handling.* Jackson 3 exceptions are unchecked and are not 
``IOException``s. Replace
+  `onException(IOException.class)` and 
`onException(JsonProcessingException.class)` clauses that handle JSON errors
+  with `onException(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:
+
+[options="header"]
+|===
+| Change | Effect
+| Properties are sorted alphabetically | Output order changes, usually the 
first visible difference
+| `java.util.Date` is written as an ISO-8601 string | `0` becomes 
`"1970-01-01T00:00:00.000Z"`
+| `java.time` and `Optional` are supported without modules | Serialization 
that failed before now works
+| Enums use `toString()` when it is overridden | Enum values change, both when 
writing and when reading
+| Unknown properties are ignored | Payloads with extra fields no longer fail
+| `null` for a primitive fails | `MismatchedInputException` instead of `0`
+| Collections with only a getter and `final` fields are no longer populated | 
Data is silently missing after unmarshalling
+| Properties without a view are excluded when a `@JsonView` is active | Fields 
disappear from the output
+| `com.fasterxml.jackson.databind.annotation` annotations are ignored | 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 set
+  `spring.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 
`DataFormatCustomizer` bean. The
+  `camel.dataformat.jackson.*` properties are still applied on top of it:
++
+[source,java]
+----
+@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 `JsonMapper` bean 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,Before you start>>.
+
+=== Verify
+
+. Check that only the Jackson 3 Camel modules are present:
++
+[source,bash]
+----
+mvn dependency:tree 
-Dincludes=org.apache.camel:camel-jackson,org.apache.camel:camel-jackson3
+----
++
+`camel-jackson` must not appear, unless a starter that requires it brings it; 
in that case see <<_rules,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 `onException`
+  clauses 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:
+
+[source,bash]
+----
+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`.

Reply via email to