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 d486c012c7aa CAMEL-23772: dataformat component honors global
camel.dataformat.* configuration
d486c012c7aa is described below
commit d486c012c7aaab9a921c7f584219167bac684f7c
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Jun 16 19:04:37 2026 +0200
CAMEL-23772: dataformat component honors global camel.dataformat.*
configuration
The dataformat: component created a fresh, unconfigured DataFormat
instance and bound only the endpoint URI parameters, ignoring the
global camel.dataformat.<name>.* configuration from application.properties.
This fix copies the auto-configured template's option values onto the
new instance before binding endpoint URI parameters (which keep
precedence), aligning the component path with the marshal()/unmarshal()
DSL behaviour fixed in CAMEL-22352.
Closes #24050
---
components/camel-csv/pom.xml | 5 ++
.../component/DataFormatComponentConfigTest.java | 57 ++++++++++++++++++++++
.../csv/component/DataFormatComponentRoute.java | 32 ++++++++++++
.../component/dataformat/DataFormatComponent.java | 56 ++++++++++++++++++++-
.../ROOT/pages/camel-4x-upgrade-guide-4_21.adoc | 9 ++++
5 files changed, 158 insertions(+), 1 deletion(-)
diff --git a/components/camel-csv/pom.xml b/components/camel-csv/pom.xml
index c707dabb9850..cc0b783b922a 100644
--- a/components/camel-csv/pom.xml
+++ b/components/camel-csv/pom.xml
@@ -51,6 +51,11 @@
<artifactId>camel-main</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-dataformat</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-xml</artifactId>
diff --git
a/components/camel-csv/src/test/java/org/apache/camel/dataformat/csv/component/DataFormatComponentConfigTest.java
b/components/camel-csv/src/test/java/org/apache/camel/dataformat/csv/component/DataFormatComponentConfigTest.java
new file mode 100644
index 000000000000..150477e76dd8
--- /dev/null
+++
b/components/camel-csv/src/test/java/org/apache/camel/dataformat/csv/component/DataFormatComponentConfigTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.dataformat.csv.component;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.main.Main;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+/**
+ * Verifies that a {@code dataformat:} component endpoint honors the global
{@code camel.dataformat.csv.*} configuration
+ * (here {@code ignore-surrounding-spaces=true}) the same way the {@code
unmarshal()} DSL does (CAMEL-23772).
+ */
+public class DataFormatComponentConfigTest {
+
+ @Test
+ public void testGlobalConfigAppliedToDataFormatComponent() throws
Exception {
+ Main main = new Main();
+
main.configure().withBasePackageScan("org.apache.camel.dataformat.csv.component");
+ main.start();
+ try {
+ CamelContext camelContext = main.getCamelContext();
+ assertNotNull(camelContext);
+ assertEquals(1, camelContext.getRoutes().size());
+
+ MockEndpoint mock = camelContext.getEndpoint("mock:result",
MockEndpoint.class);
+ mock.expectedMessageCount(1);
+ mock.assertIsSatisfied();
+
+ Object body =
mock.getReceivedExchanges().get(0).getMessage().getBody();
+ assertNotNull(body);
+ // global camel.dataformat.csv.ignore-surrounding-spaces=true must
be applied, so the
+ // surrounding spaces are stripped; without the fix the component
ignores it and the
+ // spaces would be preserved
+ assertEquals("[[One], [Two], [Three]]", body.toString());
+ } finally {
+ main.stop();
+ }
+ }
+}
diff --git
a/components/camel-csv/src/test/java/org/apache/camel/dataformat/csv/component/DataFormatComponentRoute.java
b/components/camel-csv/src/test/java/org/apache/camel/dataformat/csv/component/DataFormatComponentRoute.java
new file mode 100644
index 000000000000..e460236a5216
--- /dev/null
+++
b/components/camel-csv/src/test/java/org/apache/camel/dataformat/csv/component/DataFormatComponentRoute.java
@@ -0,0 +1,32 @@
+/*
+ * 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.dataformat.csv.component;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class DataFormatComponentRoute extends RouteBuilder {
+
+ @Override
+ public void configure() throws Exception {
+ // use the dataformat: component instead of the unmarshal() DSL; it
must honor the global
+ // camel.dataformat.csv.* configuration from application.properties
(CAMEL-23772)
+ from("timer:tick?repeatCount=1")
+ .setBody().constant("One \r\nTwo \r\nThree \r\n")
+ .to("dataformat:csv:unmarshal")
+ .to("mock:result");
+ }
+}
diff --git
a/components/camel-dataformat/src/main/java/org/apache/camel/component/dataformat/DataFormatComponent.java
b/components/camel-dataformat/src/main/java/org/apache/camel/component/dataformat/DataFormatComponent.java
index cc4a11e1c7d4..75da315ab5c2 100644
---
a/components/camel-dataformat/src/main/java/org/apache/camel/component/dataformat/DataFormatComponent.java
+++
b/components/camel-dataformat/src/main/java/org/apache/camel/component/dataformat/DataFormatComponent.java
@@ -16,15 +16,19 @@
*/
package org.apache.camel.component.dataformat;
+import java.util.LinkedHashMap;
import java.util.Map;
+import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
import org.apache.camel.spi.PropertyConfigurer;
import org.apache.camel.spi.annotations.Component;
import org.apache.camel.support.DefaultComponent;
import org.apache.camel.support.PluginHelper;
import org.apache.camel.support.PropertyBindingSupport;
+import org.apache.camel.support.PropertyConfigurerHelper;
import org.apache.camel.util.StringHelper;
/**
@@ -47,6 +51,7 @@ public class DataFormatComponent extends DefaultComponent {
// create new data format as it is configured from the given parameters
String name = StringHelper.before(remaining, ":");
DataFormat df = getCamelContext().createDataFormat(name);
+ boolean created = df != null;
if (df == null) {
// if not, try to lookup existing data format
df = getCamelContext().resolveDataFormat(name);
@@ -58,7 +63,15 @@ public class DataFormatComponent extends DefaultComponent {
// find configurer if any
PropertyConfigurer configurer =
PluginHelper.getConfigurerResolver(getCamelContext())
.resolvePropertyConfigurer(name + "-dataformat",
getCamelContext());
- // bind properties to data format
+
+ // when a brand-new instance was created, first copy any global
camel.dataformat.<name>.*
+ // configuration from the auto-configured data format onto it, so the
dataformat: component
+ // honors global configuration the same way the marshal()/unmarshal()
DSL does (CAMEL-22352)
+ if (created) {
+ copyGlobalConfiguration(name, df, configurer);
+ }
+
+ // bind the endpoint parameters; these take precedence over the global
configuration
PropertyBindingSupport.Builder builder = new
PropertyBindingSupport.Builder();
builder.withConfigurer(configurer);
builder.bind(getCamelContext(), df, parameters);
@@ -69,4 +82,45 @@ public class DataFormatComponent extends DefaultComponent {
setProperties(endpoint, parameters);
return endpoint;
}
+
+ /**
+ * Copies the configuration of an auto-configured data format (e.g. set up
via global
+ * {@code camel.dataformat.<name>.*} properties) onto the newly created
data format instance, so that
+ * {@code dataformat:} endpoints honor global configuration. The endpoint
URI parameters are bound afterwards and
+ * therefore take precedence over the copied values.
+ */
+ private void copyGlobalConfiguration(String name, DataFormat target,
PropertyConfigurer configurer) {
+ CamelContext context = getCamelContext();
+ // only relevant when a generic data format has been auto-configured,
e.g. via camel.dataformat.<name>.*
+ if (!context.getDataFormatNames().contains(name)) {
+ return;
+ }
+ DataFormat template = context.resolveDataFormat(name);
+ if (template == null || template == target) {
+ return;
+ }
+ PropertyConfigurer getter = configurer;
+ if (getter == null) {
+ getter =
PropertyConfigurerHelper.resolvePropertyConfigurer(context, template);
+ }
+ if (getter instanceof ExtendedPropertyConfigurerGetter eg) {
+ Map<String, Object> properties = new LinkedHashMap<>();
+ for (String key : eg.getAllOptions(template).keySet()) {
+ Object value = eg.getOptionValue(template, key, true);
+ if (value != null) {
+ properties.put(key, value);
+ }
+ }
+ if (!properties.isEmpty()) {
+ PropertyBindingSupport.build()
+ .withCamelContext(context)
+ .withTarget(target)
+ .withReference(true)
+ .withIgnoreCase(true)
+ .withConfigurer(configurer)
+ .withProperties(properties)
+ .bind();
+ }
+ }
+ }
}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
index 4c3d8e5d43a1..903886d1cd74 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
@@ -25,6 +25,15 @@ When `fromRouteId` is not available (for example, on
Exchanges created by `Produ
This ensures Prometheus-compatible metric export when Route triggered and
ProducerTemplate Exchanges are mixed.
Dashboards or alerts that assumed the `routeId` label was absent must be
updated to treat `routeId=""` accordingly.
+=== camel-dataformat
+
+The `dataformat:` component now applies the global `camel.dataformat.<name>.*`
configuration (for example from
+`application.properties`) when it creates the data format instance. Previously
a `dataformat:` endpoint such as
+`to("dataformat:beanio:unmarshal")` ignored this global configuration and used
only the options provided on the
+endpoint URI, which could leave the data format incompletely configured. This
aligns the component with the
+`marshal()` / `unmarshal()` DSL, which already honors the global
configuration. Options specified on the endpoint URI
+continue to take precedence over the global configuration.
+
=== camel-core
==== Simple language: internal builder classes reorganized