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

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 47c2b010a2d9 CAMEL-22857: REST binding keeps rejecting unknown 
properties on Jackson 3 (#29559)
47c2b010a2d9 is described below

commit 47c2b010a2d9c709322b5bfa950315337956bde8
Author: James Netherton <[email protected]>
AuthorDate: Tue Nov 10 13:28:37 2026 +0000

    CAMEL-22857: REST binding keeps rejecting unknown properties on Jackson 3 
(#29559)
    
    Jackson 3 turns FAIL_ON_UNKNOWN_PROPERTIES off by default, so with
    camel-jackson3 the REST DSL binding accepted a request body with properties
    its type does not have. Request bodies come from external callers, so the
    binding enables the feature again when it reads them: 
RestBindingAdviceFactory
    for json.in and the camel-jackson3xml factory for xml.in. It is not added 
when
    enableFeatures/disableFeatures already names it, or when the data format has
    a mapper of the user's own. Responses and the REST producer keep the 
Jackson 3
    default. The upgrade guide describes the behaviour and the opt-out.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 ...nXMLRestBindingJacksonXmlDataFormatFactory.java |  21 ++++
 ...nXMLRestBindingFailOnUnknownPropertiesTest.java | 108 +++++++++++++++++++++
 .../RestJettyPostJsonPojoOwnObjectMapperTest.java  |  65 +++++++++++++
 ...ostJsonPojoUnknownPropertyOtherFeatureTest.java |  30 ++++++
 .../RestJettyPostJsonPojoUnknownPropertyTest.java  |  88 +++++++++++++++++
 .../rest/RestUndertowHttpPojoTypeTest.java         |   4 +-
 .../processor/RestBindingAdviceFactory.java        |  30 ++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |  14 ++-
 8 files changed, 352 insertions(+), 8 deletions(-)

diff --git 
a/components/camel-jackson3xml/src/main/java/org/apache/camel/component/jackson3xml/JacksonXMLRestBindingJacksonXmlDataFormatFactory.java
 
b/components/camel-jackson3xml/src/main/java/org/apache/camel/component/jackson3xml/JacksonXMLRestBindingJacksonXmlDataFormatFactory.java
index 66723538c4b0..2830239ccb47 100644
--- 
a/components/camel-jackson3xml/src/main/java/org/apache/camel/component/jackson3xml/JacksonXMLRestBindingJacksonXmlDataFormatFactory.java
+++ 
b/components/camel-jackson3xml/src/main/java/org/apache/camel/component/jackson3xml/JacksonXMLRestBindingJacksonXmlDataFormatFactory.java
@@ -34,6 +34,8 @@ import org.apache.camel.support.PropertyBindingSupport;
 @JdkService(RestBindingJacksonXmlDataFormatFactory.FACTORY)
 public class JacksonXMLRestBindingJacksonXmlDataFormatFactory implements 
RestBindingJacksonXmlDataFormatFactory {
 
+    private static final String FAIL_ON_UNKNOWN_PROPERTIES = 
"FAIL_ON_UNKNOWN_PROPERTIES";
+
     @Override
     public void setupJacksonXml(
             CamelContext camelContext, RestConfiguration config,
@@ -63,6 +65,7 @@ public class JacksonXMLRestBindingJacksonXmlDataFormatFactory 
implements RestBin
 
         setAdditionalConfiguration(config, "xml.in.", builder);
         builder.bind();
+        failOnUnknownProperties(xml);
 
         //
         // OUT
@@ -83,6 +86,24 @@ public class 
JacksonXMLRestBindingJacksonXmlDataFormatFactory implements RestBin
         outBuilder.bind();
     }
 
+    /**
+     * Jackson 3 accepts unknown properties by default, where Jackson 2 
rejects them. REST binding keeps rejecting them
+     * in request bodies, as they come from external callers, unless the 
feature or a mapper of your own is configured.
+     */
+    private static void failOnUnknownProperties(DataFormat dataFormat) {
+        if (dataFormat instanceof JacksonXMLDataFormat xml
+                && xml.getXmlMapper() == null
+                && !namesFailOnUnknownProperties(xml.getEnableFeatures())
+                && !namesFailOnUnknownProperties(xml.getDisableFeatures())) {
+            xml.setEnableFeatures(xml.getEnableFeatures() != null
+                    ? xml.getEnableFeatures() + "," + 
FAIL_ON_UNKNOWN_PROPERTIES : FAIL_ON_UNKNOWN_PROPERTIES);
+        }
+    }
+
+    private static boolean namesFailOnUnknownProperties(String features) {
+        return features != null && 
features.contains(FAIL_ON_UNKNOWN_PROPERTIES);
+    }
+
     private static String getOutTypeName(String outType, Class<?> 
outTypeClass, String typeName) {
         String outTypeName = null;
         if (outTypeClass != null) {
diff --git 
a/components/camel-jackson3xml/src/test/java/org/apache/camel/component/jackson3xml/JacksonXMLRestBindingFailOnUnknownPropertiesTest.java
 
b/components/camel-jackson3xml/src/test/java/org/apache/camel/component/jackson3xml/JacksonXMLRestBindingFailOnUnknownPropertiesTest.java
new file mode 100644
index 000000000000..8915c4172335
--- /dev/null
+++ 
b/components/camel-jackson3xml/src/test/java/org/apache/camel/component/jackson3xml/JacksonXMLRestBindingFailOnUnknownPropertiesTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jackson3xml;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.RestConfiguration;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import tools.jackson.databind.exc.UnrecognizedPropertyException;
+import tools.jackson.dataformat.xml.XmlMapper;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * REST binding rejects unknown properties with Jackson 3 too, whose default 
is to accept them.
+ */
+public class JacksonXMLRestBindingFailOnUnknownPropertiesTest {
+
+    private static final String UNKNOWN = 
"<TestPojo><name>Camel</name><donotexists>foo</donotexists></TestPojo>";
+
+    private CamelContext context;
+
+    @BeforeEach
+    public void createContext() {
+        context = new DefaultCamelContext();
+        context.start();
+    }
+
+    @AfterEach
+    public void stopContext() {
+        context.stop();
+    }
+
+    @Test
+    public void testUnknownPropertyIsRejected() throws Exception {
+        JacksonXMLDataFormat xml = setup(Map.of());
+
+        assertEquals("FAIL_ON_UNKNOWN_PROPERTIES", xml.getEnableFeatures());
+        assertThrows(UnrecognizedPropertyException.class, () -> unmarshal(xml, 
UNKNOWN));
+    }
+
+    @Test
+    public void testOtherFeaturesKeepTheRejection() throws Exception {
+        JacksonXMLDataFormat xml = setup(Map.of("xml.in.enableFeatures", 
"ACCEPT_SINGLE_VALUE_AS_ARRAY"));
+
+        
assertEquals("ACCEPT_SINGLE_VALUE_AS_ARRAY,FAIL_ON_UNKNOWN_PROPERTIES", 
xml.getEnableFeatures());
+        assertThrows(UnrecognizedPropertyException.class, () -> unmarshal(xml, 
UNKNOWN));
+    }
+
+    @Test
+    public void testDisablingTheFeatureAcceptsUnknownProperties() throws 
Exception {
+        JacksonXMLDataFormat xml = setup(Map.of("xml.in.disableFeatures", 
"FAIL_ON_UNKNOWN_PROPERTIES"));
+
+        TestPojo pojo = (TestPojo) unmarshal(xml, UNKNOWN);
+        assertEquals("Camel", pojo.getName());
+    }
+
+    @Test
+    public void testOwnMapperKeepsItsSettings() throws Exception {
+        JacksonXMLDataFormat xml = setup(Map.of("xml.in.xmlMapper", new 
XmlMapper()));
+
+        assertNull(xml.getEnableFeatures());
+        TestPojo pojo = (TestPojo) unmarshal(xml, UNKNOWN);
+        assertEquals("Camel", pojo.getName());
+    }
+
+    private JacksonXMLDataFormat setup(Map<String, Object> properties) throws 
Exception {
+        RestConfiguration config = new RestConfiguration();
+        config.setDataFormatProperties(properties);
+
+        JacksonXMLDataFormat xml = new JacksonXMLDataFormat();
+        JacksonXMLDataFormat outXml = new JacksonXMLDataFormat();
+        new JacksonXMLRestBindingJacksonXmlDataFormatFactory()
+                .setupJacksonXml(context, config, null, TestPojo.class, null, 
null, xml, outXml);
+        xml.setCamelContext(context);
+        xml.start();
+        return xml;
+    }
+
+    private static Object unmarshal(JacksonXMLDataFormat xml, String body) 
throws Exception {
+        Exchange exchange = new DefaultExchange(xml.getCamelContext());
+        return xml.unmarshal(exchange, new 
ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)));
+    }
+}
diff --git 
a/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/rest/RestJettyPostJsonPojoOwnObjectMapperTest.java
 
b/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/rest/RestJettyPostJsonPojoOwnObjectMapperTest.java
new file mode 100644
index 000000000000..4ca1b5c8eda9
--- /dev/null
+++ 
b/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/rest/RestJettyPostJsonPojoOwnObjectMapperTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jetty.rest;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.jetty.BaseJettyTest;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.junit.jupiter.api.Test;
+import tools.jackson.databind.json.JsonMapper;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * REST binding keeps the settings of a mapper of your own, here one that 
accepts unknown properties.
+ */
+public class RestJettyPostJsonPojoOwnObjectMapperTest extends BaseJettyTest {
+
+    @BindToRegistry("myMapper")
+    public JsonMapper myMapper() {
+        return JsonMapper.builder().build();
+    }
+
+    @Test
+    public void testUnknownPropertyIsAccepted() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:input");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(UserPojo.class);
+
+        String body = "{\"id\": 123, \"name\": \"Donald Duck\", 
\"donotexists\": \"foo\"}";
+        template.sendBody("http://localhost:"; + getPort() + "/users/new", 
body);
+
+        MockEndpoint.assertIsSatisfied(context);
+        UserPojo user = 
mock.getReceivedExchanges().get(0).getIn().getBody(UserPojo.class);
+        assertEquals("Donald Duck", user.getName());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                
restConfiguration().component("jetty").host("localhost").port(getPort()).bindingMode(RestBindingMode.json)
+                        .dataFormatProperty("json.in.objectMapper", 
"#myMapper");
+
+                
rest("/users/").post("new").type(UserPojo.class).to("mock:input");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/rest/RestJettyPostJsonPojoUnknownPropertyOtherFeatureTest.java
 
b/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/rest/RestJettyPostJsonPojoUnknownPropertyOtherFeatureTest.java
new file mode 100644
index 000000000000..e4ba411615ab
--- /dev/null
+++ 
b/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/rest/RestJettyPostJsonPojoUnknownPropertyOtherFeatureTest.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jetty.rest;
+
+import org.apache.camel.model.rest.RestConfigurationDefinition;
+
+/**
+ * Enabling other features keeps the rejection of unknown properties.
+ */
+public class RestJettyPostJsonPojoUnknownPropertyOtherFeatureTest extends 
RestJettyPostJsonPojoUnknownPropertyTest {
+
+    @Override
+    protected void configureDataFormat(RestConfigurationDefinition rest) {
+        rest.dataFormatProperty("json.in.enableFeatures", 
"ACCEPT_SINGLE_VALUE_AS_ARRAY");
+    }
+}
diff --git 
a/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/rest/RestJettyPostJsonPojoUnknownPropertyTest.java
 
b/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/rest/RestJettyPostJsonPojoUnknownPropertyTest.java
new file mode 100644
index 000000000000..c5aa6fab12f1
--- /dev/null
+++ 
b/components/camel-jetty/src/test/java/org/apache/camel/component/jetty/rest/RestJettyPostJsonPojoUnknownPropertyTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.jetty.rest;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.jetty.BaseJettyTest;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.http.base.HttpOperationFailedException;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestConfigurationDefinition;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.camel.test.junit6.TestSupport.assertIsInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * REST binding rejects unknown properties with Jackson 3 too, whose default 
is to accept them.
+ */
+public class RestJettyPostJsonPojoUnknownPropertyTest extends BaseJettyTest {
+
+    @Test
+    public void testUnknownPropertyIsRejected() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:input");
+        mock.expectedMessageCount(0);
+
+        String body = "{\"id\": 123, \"name\": \"Donald Duck\", 
\"donotexists\": \"foo\"}";
+        Exception ex = assertThrows(CamelExecutionException.class,
+                () -> template.sendBody("http://localhost:"; + getPort() + 
"/users/new", body));
+
+        HttpOperationFailedException cause = 
assertIsInstanceOf(HttpOperationFailedException.class, ex.getCause());
+        assertEquals(400, cause.getStatusCode());
+        assertTrue(cause.getResponseBody().contains("donotexists"), 
cause.getResponseBody());
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Test
+    public void testKnownPropertiesAreAccepted() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:input");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(UserPojo.class);
+
+        template.sendBody("http://localhost:"; + getPort() + "/users/new", 
"{\"id\": 123, \"name\": \"Donald Duck\"}");
+
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                // answer the binding failure with its message
+                onException(Exception.class)
+                        .handled(true)
+                        .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400))
+                        .setBody().simple("${exception.message}");
+
+                configureDataFormat(
+                        
restConfiguration().component("jetty").host("localhost").port(getPort())
+                                .bindingMode(RestBindingMode.json));
+
+                
rest("/users/").post("new").type(UserPojo.class).to("mock:input");
+            }
+        };
+    }
+
+    protected void configureDataFormat(RestConfigurationDefinition rest) {
+        // the defaults of REST binding
+    }
+}
diff --git 
a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpPojoTypeTest.java
 
b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpPojoTypeTest.java
index b9a164e051ae..b67ea806c101 100644
--- 
a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpPojoTypeTest.java
+++ 
b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpPojoTypeTest.java
@@ -255,9 +255,7 @@ public class RestUndertowHttpPojoTypeTest extends 
BaseUndertowTest {
 
                 // configure to use undertow on localhost with the given port
                 
restConfiguration().component("undertow").host("localhost").port(getPort())
-                        .bindingMode(RestBindingMode.json)
-                        // Jackson 3 ignores unknown properties by default
-                        .dataFormatProperty("json.in.enableFeatures", 
"FAIL_ON_UNKNOWN_PROPERTIES");
+                        .bindingMode(RestBindingMode.json);
 
                 // use the rest DSL to define the rest services
                 rest()
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdviceFactory.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdviceFactory.java
index cd6d58c6fe21..6425372c3b3e 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdviceFactory.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdviceFactory.java
@@ -37,6 +37,10 @@ import org.apache.camel.support.ResolverHelper;
  */
 public class RestBindingAdviceFactory {
 
+    // matched by name: camel-support cannot depend on camel-jackson3, and 
JSON has no binding factory SPI
+    private static final String JACKSON3_PACKAGE = 
"org.apache.camel.component.jackson3.";
+    private static final String FAIL_ON_UNKNOWN_PROPERTIES = 
"FAIL_ON_UNKNOWN_PROPERTIES";
+
     /**
      * Builds the {@link RestBindingAdvice} from the given configuration
      *
@@ -169,6 +173,7 @@ public class RestBindingAdviceFactory {
                     useList);
         }
         setAdditionalConfiguration(camelContext, config, json, "json.in.");
+        failOnUnknownProperties(camelContext, json);
 
         if (outJson != null) {
             Class<?> outClazz = null;
@@ -252,6 +257,31 @@ public class RestBindingAdviceFactory {
         }
     }
 
+    /**
+     * Jackson 3 accepts unknown properties by default, where Jackson 2 
rejects them. REST binding keeps rejecting them
+     * in request bodies, as they come from external callers, unless the 
feature or a mapper of your own is configured.
+     */
+    private static void failOnUnknownProperties(CamelContext camelContext, 
DataFormat dataFormat) throws Exception {
+        if (!dataFormat.getClass().getName().startsWith(JACKSON3_PACKAGE)) {
+            return;
+        }
+        BeanIntrospection beanIntrospection = 
PluginHelper.getBeanIntrospection(camelContext);
+        if (beanIntrospection.getOrElseProperty(dataFormat, "objectMapper", 
null, false) != null) {
+            return;
+        }
+        Object enable = beanIntrospection.getOrElseProperty(dataFormat, 
"enableFeatures", null, false);
+        Object disable = beanIntrospection.getOrElseProperty(dataFormat, 
"disableFeatures", null, false);
+        if (namesFailOnUnknownProperties(enable) || 
namesFailOnUnknownProperties(disable)) {
+            return;
+        }
+        String features = enable != null ? enable + "," + 
FAIL_ON_UNKNOWN_PROPERTIES : FAIL_ON_UNKNOWN_PROPERTIES;
+        beanIntrospection.setProperty(camelContext, dataFormat, 
"enableFeatures", features);
+    }
+
+    private static boolean namesFailOnUnknownProperties(Object features) {
+        return features != null && 
features.toString().contains(FAIL_ON_UNKNOWN_PROPERTIES);
+    }
+
     private static boolean isKeyKnownPrefix(String key) {
         return key.startsWith("json.in.") || key.startsWith("json.out.") || 
key.startsWith("xml.in.")
                 || key.startsWith("xml.out.");
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index f96092f0c261..b74611bbcb8a 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -7588,7 +7588,7 @@ which differ from Jackson 2. Most visibly:
 |===
 | Feature | Jackson 2 | Jackson 3 | Effect of the Jackson 3 default
 
-| `FAIL_ON_UNKNOWN_PROPERTIES` | on | off | Unknown properties are ignored. 
See the warning below.
+| `FAIL_ON_UNKNOWN_PROPERTIES` | on | off | Unknown properties are ignored, 
except by REST binding (see below).
 | `SORT_PROPERTIES_ALPHABETICALLY` | off | on | Properties are written in 
alphabetical order.
 | `WRITE_DATES_AS_TIMESTAMPS` | on | off | Dates are written as ISO-8601 text, 
not as numbers.
 | `WRITE_DURATIONS_AS_TIMESTAMPS` | on | off | Durations are written as 
ISO-8601 text.
@@ -7605,12 +7605,16 @@ Set a feature back with the `enableFeatures` and 
`disableFeatures` options of th
 [source,java]
 ----
 restConfiguration().bindingMode(RestBindingMode.json)
-    .dataFormatProperty("json.in.enableFeatures", 
"FAIL_ON_UNKNOWN_PROPERTIES");
+    .dataFormatProperty("json.out.enableFeatures", 
"WRITE_DATES_AS_TIMESTAMPS");
 ----
 
-WARNING: With `FAIL_ON_UNKNOWN_PROPERTIES` off, a route using REST binding no 
longer rejects a JSON body that does not
-match its type. The body is accepted, the request gets no `400` response, and 
the route receives a POJO with empty fields.
-Enable the feature as shown above if your routes rely on that validation.
+NOTE: The REST DSL binding of a service enables `FAIL_ON_UNKNOWN_PROPERTIES` 
on its Jackson 3 data formats (`json`, and
+`jacksonXml` from `camel-jackson3xml`), so a request body with properties that 
its type does not have is still rejected,
+as with Jackson 2. To accept such bodies, set `json.in.disableFeatures` (or 
`xml.in.disableFeatures`) to
+`FAIL_ON_UNKNOWN_PROPERTIES`. A feature you enable with `enableFeatures` is 
added to it. A data format with a mapper of
+your own keeps the settings of that mapper: the `objectMapper` option or a 
mapper found with `autoDiscoverObjectMapper`
+for JSON, the `xmlMapper` option for XML. The REST producer, which reads the 
responses of the services it calls, uses
+the Jackson 3 default.
 
 *Limits.* Jackson 3 reads and writes with other limits: nesting up to 500 
levels (it was 1000), for reading and writing, and
 strings up to 100 million characters (it was 20 million). They apply to every 
component on Jackson 3, including those whose

Reply via email to