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 2328bb522ec7 CAMEL-24696: camel-core-model - inheritErrorHandler is a
String so property placeholders resolve at route startup
2328bb522ec7 is described below
commit 2328bb522ec792c2c6336b58a708bf5d71ca6e9f
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Sep 15 09:07:15 2026 +0200
CAMEL-24696: camel-core-model - inheritErrorHandler is a String so property
placeholders resolve at route startup
CircuitBreakerDefinition.inheritErrorHandler and
FailoverLoadBalancerDefinition.inheritErrorHandler were the last two model
attributes still converted with Boolean.valueOf while deserializing, so a
property placeholder was never resolved and inheritErrorHandler: "{{flag}}"
silently evaluated to false - while camel validate accepted it since
CAMEL-24697 exposed the attribute in the YAML schema.
Both attributes are now String with @Metadata(javaType =
"java.lang.Boolean")
like every other scalar attribute; ProcessorReifier and LoadBalanceReifier
parse the value with the CamelContext at route startup. camel-jta and
camel-kamelet follow, the fluent DSL keeps its boolean signatures and gains
a
CircuitBreakerDefinition.inheritErrorHandler(String) overload, and the
generated parsers/writers/XSDs are regenerated. Documented in the 4.23
upgrade guide.
The failover(..., inheritErrorHandler=false, ...) runtime regression found
while analysing this is tracked separately as CAMEL-24749.
Closes #26449
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
.../apache/camel/catalog/schemas/camel-spring.xsd | 4 +-
.../apache/camel/catalog/schemas/camel-xml-io.xsd | 4 +-
.../org/apache/camel/jta/JtaTransactionPolicy.java | 2 +-
.../apache/camel/component/kamelet/Kamelet.java | 4 +-
...silienceInheritErrorHandlerPlaceholderTest.java | 64 ++++++++++++++++++++++
.../camel/model/CircuitBreakerDefinition.java | 22 +++++++-
.../apache/camel/model/LoadBalanceDefinition.java | 4 +-
.../apache/camel/model/ProcessorDefinition.java | 6 +-
.../FailoverLoadBalancerDefinition.java | 6 +-
.../apache/camel/reifier/LoadBalanceReifier.java | 2 +-
.../org/apache/camel/reifier/ProcessorReifier.java | 2 +-
.../apache/camel/java/out/JavaDslModelWriter.java | 4 +-
.../java/org/apache/camel/xml/in/ModelParser.java | 4 +-
.../java/org/apache/camel/xml/out/ModelWriter.java | 4 +-
.../org/apache/camel/yaml/out/YamlModelWriter.java | 4 +-
.../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 34 ++++++++++++
.../dsl/yaml/deserializers/ModelDeserializers.java | 4 +-
.../camel/dsl/yaml/validator/YamlValidator.java | 7 ++-
.../validator/YamlValidatorSchemaGroupsTest.java | 6 ++
.../inherit-error-handler-placeholder.yaml | 35 ++++++++++++
.../camel/dsl/yaml/CircuitBreakerTest.groovy | 22 ++++++++
.../apache/camel/dsl/yaml/LoadBalanceTest.groovy | 30 ++++++++++
22 files changed, 241 insertions(+), 33 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index 5ee9404250ed..fb02523a244b 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -4539,7 +4539,7 @@ Refers to a circuit breaker configuration to use for
configuring the circuit bre
</xs:documentation>
</xs:annotation>
</xs:attribute>
- <xs:attribute name="inheritErrorHandler" type="xs:boolean">
+ <xs:attribute name="inheritErrorHandler" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="en">
<![CDATA[
@@ -6949,7 +6949,7 @@ value: -1
</xs:documentation>
</xs:annotation>
</xs:attribute>
- <xs:attribute name="inheritErrorHandler" type="xs:boolean">
+ <xs:attribute name="inheritErrorHandler" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="en">
<![CDATA[
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd
index dbbcbd1ba490..79d25dfcdd81 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-xml-io.xsd
@@ -3649,7 +3649,7 @@ Refers to a circuit breaker configuration to use for
configuring the circuit bre
</xs:documentation>
</xs:annotation>
</xs:attribute>
- <xs:attribute name="inheritErrorHandler" type="xs:boolean">
+ <xs:attribute name="inheritErrorHandler" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="en">
<![CDATA[
@@ -6071,7 +6071,7 @@ value: -1
</xs:documentation>
</xs:annotation>
</xs:attribute>
- <xs:attribute name="inheritErrorHandler" type="xs:boolean">
+ <xs:attribute name="inheritErrorHandler" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="en">
<![CDATA[
diff --git
a/components/camel-jta/src/main/java/org/apache/camel/jta/JtaTransactionPolicy.java
b/components/camel-jta/src/main/java/org/apache/camel/jta/JtaTransactionPolicy.java
index 0b9e4c67dfe7..c8b3bf64abf6 100644
---
a/components/camel-jta/src/main/java/org/apache/camel/jta/JtaTransactionPolicy.java
+++
b/components/camel-jta/src/main/java/org/apache/camel/jta/JtaTransactionPolicy.java
@@ -63,7 +63,7 @@ public abstract class JtaTransactionPolicy implements
TransactedPolicy {
// (otherwise the default error handler would be used two times
// because we inherit it on our own but only in case of a
// non-transactional error handler)
- ((ProcessorDefinition<?>) definition).setInheritErrorHandler(false);
+ ((ProcessorDefinition<?>) definition).setInheritErrorHandler("false");
}
public abstract void run(Runnable runnable) throws Throwable;
diff --git
a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java
b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java
index d3b3cda8c7ed..9a5acda98d16 100644
---
a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java
+++
b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java
@@ -214,8 +214,8 @@ public final class Kamelet {
// (if ppid is null then it is a source kamelet)
if (ppid != null) {
ProcessorDefinition<?> pro = mcc.getProcessorDefinition(ppid);
- wrap = pro == null ||
ProcessorDefinitionHelper.shouldWrapInErrorHandler(def.getCamelContext(), pro,
null,
- pro.getInheritErrorHandler());
+ wrap = pro == null ||
ProcessorDefinitionHelper.shouldWrapInErrorHandler(mcc, pro, null,
+ CamelContextHelper.parseBoolean(mcc,
pro.getInheritErrorHandler()));
}
if (wrap && parent != null && parent.isKamelet() == null) {
// do not wrap if the parent is also a kamelet
diff --git
a/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceInheritErrorHandlerPlaceholderTest.java
b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceInheritErrorHandlerPlaceholderTest.java
new file mode 100644
index 000000000000..3b8c9ca0a9f7
--- /dev/null
+++
b/components/camel-resilience4j/src/test/java/org/apache/camel/component/resilience4j/ResilienceInheritErrorHandlerPlaceholderTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.resilience4j;
+
+import java.util.Properties;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+/**
+ * The inheritErrorHandler option is a property placeholder that is resolved
when the route starts (CAMEL-24696).
+ */
+public class ResilienceInheritErrorHandlerPlaceholderTest extends
CamelTestSupport {
+
+ @Override
+ protected Properties useOverridePropertiesWithPropertiesComponent() {
+ Properties prop = new Properties();
+ prop.setProperty("myInherit", "true");
+ return prop;
+ }
+
+ @Test
+ public void testResiliencePlaceholder() throws Exception {
+ // inheritErrorHandler resolved to true so Camel error handler does
the 3 redeliveries before the dead letter
+ getMockEndpoint("mock:a").expectedMessageCount(3 + 1);
+ getMockEndpoint("mock:dead").expectedMessageCount(1);
+ getMockEndpoint("mock:result").expectedMessageCount(0);
+
+ template.sendBody("direct:start", "Hello World");
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+
errorHandler(deadLetterChannel("mock:dead").maximumRedeliveries(3).redeliveryDelay(0));
+
+ from("direct:start").to("log:start")
+
.circuitBreaker().inheritErrorHandler("{{myInherit}}").to("mock:a")
+ .throwException(new
IllegalArgumentException("Forced")).end().to("log:result").to("mock:result");
+ }
+ };
+ }
+
+}
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java
index 320be9797bd5..4dc14c555953 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/CircuitBreakerDefinition.java
@@ -47,7 +47,7 @@ public class CircuitBreakerDefinition extends
OutputDefinition<CircuitBreakerDef
@XmlAttribute
@Metadata(label = "advanced", javaType = "java.lang.Boolean", defaultValue
= "false",
description = "Whether to inherit Camel error handling during
circuit breaker. By default, Camel error handler is turned off.")
- private Boolean inheritErrorHandler;
+ private String inheritErrorHandler;
@XmlElement
@Metadata(label = "advanced",
description = "Configures the circuit breaker to use
Resilience4j with the given configuration.")
@@ -149,12 +149,12 @@ public class CircuitBreakerDefinition extends
OutputDefinition<CircuitBreakerDef
}
@Override
- public Boolean getInheritErrorHandler() {
+ public String getInheritErrorHandler() {
return inheritErrorHandler;
}
@Override
- public void setInheritErrorHandler(Boolean inheritErrorHandler) {
+ public void setInheritErrorHandler(String inheritErrorHandler) {
this.inheritErrorHandler = inheritErrorHandler;
}
@@ -225,6 +225,22 @@ public class CircuitBreakerDefinition extends
OutputDefinition<CircuitBreakerDef
* By default, Camel error handler is turned off.
*/
public CircuitBreakerDefinition inheritErrorHandler(boolean
inheritErrorHandler) {
+ return inheritErrorHandler(Boolean.toString(inheritErrorHandler));
+ }
+
+ /**
+ * To turn on or off Camel error handling during circuit breaker.
+ *
+ * If this is enabled then Camel error handler will first trigger if there
is an error in the circuit breaker, which
+ * allows to let Camel handle redeliveries. If all attempts is failed,
then after the circuit breaker is finished,
+ * then Camel error handler can handle the error as well such as the dead
letter channel.
+ *
+ * By default, Camel error handler is turned off.
+ *
+ * @param inheritErrorHandler whether to inherit the error handler, can
also be a property placeholder that is
+ * resolved when the route starts
+ */
+ public CircuitBreakerDefinition inheritErrorHandler(String
inheritErrorHandler) {
this.inheritErrorHandler = inheritErrorHandler;
return this;
}
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/LoadBalanceDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/LoadBalanceDefinition.java
index 50cba0714f2b..46bdb0e852d9 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/LoadBalanceDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/LoadBalanceDefinition.java
@@ -159,7 +159,7 @@ public class LoadBalanceDefinition extends
OutputDefinition<LoadBalanceDefinitio
if (roundRobin) {
def.setRoundRobin(Boolean.toString(roundRobin));
}
- def.setInheritErrorHandler(inheritErrorHandler);
+ def.setInheritErrorHandler(Boolean.toString(inheritErrorHandler));
setLoadBalancerType(def);
return this;
}
@@ -189,7 +189,7 @@ public class LoadBalanceDefinition extends
OutputDefinition<LoadBalanceDefinitio
if (sticky) {
def.setSticky(Boolean.toString(sticky));
}
- def.setInheritErrorHandler(inheritErrorHandler);
+ def.setInheritErrorHandler(Boolean.toString(inheritErrorHandler));
setLoadBalancerType(def);
return this;
}
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
index ef985f54af44..5acd659582cc 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
@@ -96,7 +96,7 @@ public abstract class ProcessorDefinition<Type extends
ProcessorDefinition<Type>
@XmlTransient
private final int index;
@XmlTransient
- private Boolean inheritErrorHandler; // used for camel-jta
+ private String inheritErrorHandler; // used for camel-jta
protected ProcessorDefinition() {
// every time we create a definition we should inc the counter
@@ -4507,11 +4507,11 @@ public abstract class ProcessorDefinition<Type extends
ProcessorDefinition<Type>
this.disabled = disabled;
}
- public Boolean getInheritErrorHandler() {
+ public String getInheritErrorHandler() {
return inheritErrorHandler;
}
- public void setInheritErrorHandler(Boolean inheritErrorHandler) {
+ public void setInheritErrorHandler(String inheritErrorHandler) {
this.inheritErrorHandler = inheritErrorHandler;
}
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/loadbalancer/FailoverLoadBalancerDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/loadbalancer/FailoverLoadBalancerDefinition.java
index a27abb7b129f..b8e7fe8219a4 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/loadbalancer/FailoverLoadBalancerDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/loadbalancer/FailoverLoadBalancerDefinition.java
@@ -67,7 +67,7 @@ public class FailoverLoadBalancerDefinition extends
LoadBalancerDefinition {
description = "Whether to inherit the error handler."
+ " If turned off, the load balancer will fail
over immediately on an error"
+ " instead of waiting for Camel error handler to
exhaust retries.")
- private Boolean inheritErrorHandler;
+ private String inheritErrorHandler;
public FailoverLoadBalancerDefinition() {
}
@@ -127,11 +127,11 @@ public class FailoverLoadBalancerDefinition extends
LoadBalancerDefinition {
this.maximumFailoverAttempts = maximumFailoverAttempts;
}
- public Boolean getInheritErrorHandler() {
+ public String getInheritErrorHandler() {
return inheritErrorHandler;
}
- public void setInheritErrorHandler(Boolean inheritErrorHandler) {
+ public void setInheritErrorHandler(String inheritErrorHandler) {
this.inheritErrorHandler = inheritErrorHandler;
}
diff --git
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/LoadBalanceReifier.java
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/LoadBalanceReifier.java
index 8211a27531b0..d222a75c4fe5 100644
---
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/LoadBalanceReifier.java
+++
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/LoadBalanceReifier.java
@@ -62,7 +62,7 @@ public class LoadBalanceReifier extends
ProcessorReifier<LoadBalanceDefinition>
loadBalancer.addProcessor(channel);
}
- Boolean inherit = definition.getInheritErrorHandler();
+ Boolean inherit = parseBoolean(definition.getInheritErrorHandler());
if (definition.getLoadBalancerType() instanceof
FailoverLoadBalancerDefinition) {
// special for failover load balancer where you can configure it to
// not inherit error handler for its children
diff --git
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
index 0c6a44314633..2d964fa98a2d 100644
---
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
+++
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
@@ -656,7 +656,7 @@ public abstract class ProcessorReifier<T extends
ProcessorDefinition<?>> extends
}
protected Channel wrapChannel(Processor processor, ProcessorDefinition<?>
child) throws Exception {
- return wrapChannel(processor, child,
definition.getInheritErrorHandler());
+ return wrapChannel(processor, child,
parseBoolean(definition.getInheritErrorHandler()));
}
protected Channel wrapChannel(Processor processor, ProcessorDefinition<?>
child, Boolean inheritErrorHandler)
diff --git
a/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java
b/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java
index 14d9a9bde751..3b3b14e5315e 100644
---
a/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java
+++
b/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java
@@ -1850,7 +1850,7 @@ public class JavaDslModelWriter extends
JavaDslModelWriterSupport {
protected void doWriteCircuitBreakerDefinition(StringBuilder sb,
CircuitBreakerDefinition def) {
doWriteProcessorDefinitionAttributes(sb, def);
doWriteAttribute(sb, "configuration", def.getConfiguration(), null);
- doWriteAttribute(sb, "inheritErrorHandler",
toString(def.getInheritErrorHandler()), "false");
+ doWriteAttribute(sb, "inheritErrorHandler",
def.getInheritErrorHandler(), "false");
doWriteChildElement(sb, "resilience4jConfiguration",
def.getResilience4jConfiguration(),
this::doWriteResilience4jConfigurationDefinition);
doWriteChildElement(sb, "faultToleranceConfiguration",
def.getFaultToleranceConfiguration(),
this::doWriteFaultToleranceConfigurationDefinition);
doWriteChildElement(sb, "onFallback", def.getOnFallback(),
this::doWriteOnFallbackDefinition);
@@ -3677,7 +3677,7 @@ public class JavaDslModelWriter extends
JavaDslModelWriterSupport {
doWriteAttribute(sb, "roundRobin", def.getRoundRobin(), null);
doWriteAttribute(sb, "sticky", def.getSticky(), null);
doWriteAttribute(sb, "maximumFailoverAttempts",
def.getMaximumFailoverAttempts(), "-1");
- doWriteAttribute(sb, "inheritErrorHandler",
toString(def.getInheritErrorHandler()), "true");
+ doWriteAttribute(sb, "inheritErrorHandler",
def.getInheritErrorHandler(), "true");
doWriteStringList(sb, null, "exception", def.getExceptions());
}
protected void doWriteRandomLoadBalancerDefinition(StringBuilder sb,
RandomLoadBalancerDefinition def) {
diff --git
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index 9393502a94eb..73ef9c9d48fc 100644
---
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -296,7 +296,7 @@ public class ModelParser extends BaseParser {
protected CircuitBreakerDefinition doParseCircuitBreakerDefinition()
throws IOException, XmlPullParserException {
return doParse(new CircuitBreakerDefinition(), (def, key, val) ->
switch (key) {
case "configuration": def.setConfiguration(val); yield true;
- case "inheritErrorHandler":
def.setInheritErrorHandler(Boolean.valueOf(val)); yield true;
+ case "inheritErrorHandler": def.setInheritErrorHandler(val);
yield true;
default: yield
processorDefinitionAttributeHandler().accept(def, key, val);
}, (def, key) -> switch (key) {
case "faultToleranceConfiguration":
def.setFaultToleranceConfiguration(doParseFaultToleranceConfigurationDefinition());
yield true;
@@ -2431,7 +2431,7 @@ public class ModelParser extends BaseParser {
}
protected FailoverLoadBalancerDefinition
doParseFailoverLoadBalancerDefinition() throws IOException,
XmlPullParserException {
return doParse(new FailoverLoadBalancerDefinition(), (def, key, val)
-> switch (key) {
- case "inheritErrorHandler":
def.setInheritErrorHandler(Boolean.valueOf(val)); yield true;
+ case "inheritErrorHandler": def.setInheritErrorHandler(val);
yield true;
case "maximumFailoverAttempts":
def.setMaximumFailoverAttempts(val); yield true;
case "roundRobin": def.setRoundRobin(val); yield true;
case "sticky": def.setSticky(val); yield true;
diff --git
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
index 4fd5f78262cb..b5e89597ba28 100644
---
a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
+++
b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
@@ -905,7 +905,7 @@ public class ModelWriter extends BaseWriter {
startElement(name);
doWriteProcessorDefinitionAttributes(def);
doWriteAttribute("configuration", def.getConfiguration(), null);
- doWriteAttribute("inheritErrorHandler",
toString(def.getInheritErrorHandler()), "false");
+ doWriteAttribute("inheritErrorHandler", def.getInheritErrorHandler(),
"false");
doWriteElement("resilience4jConfiguration",
def.getResilience4jConfiguration(),
this::doWriteResilience4jConfigurationDefinition);
doWriteElement("faultToleranceConfiguration",
def.getFaultToleranceConfiguration(),
this::doWriteFaultToleranceConfigurationDefinition);
doWriteList(null, null, def.getOutputs(),
this::doWriteProcessorDefinitionRef);
@@ -3166,7 +3166,7 @@ public class ModelWriter extends BaseWriter {
doWriteAttribute("roundRobin", def.getRoundRobin(), null);
doWriteAttribute("sticky", def.getSticky(), null);
doWriteAttribute("maximumFailoverAttempts",
def.getMaximumFailoverAttempts(), "-1");
- doWriteAttribute("inheritErrorHandler",
toString(def.getInheritErrorHandler()), "true");
+ doWriteAttribute("inheritErrorHandler", def.getInheritErrorHandler(),
"true");
doWriteList(null, "exception", def.getExceptions(),
this::doWriteString);
endElement(name);
}
diff --git
a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java
b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java
index af8cd632617c..6090291d50d0 100644
---
a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java
+++
b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java
@@ -900,7 +900,7 @@ public class YamlModelWriter extends YamlModelWriterSupport
{
JsonObject jo = new JsonObject();
doWriteProcessorDefinitionAttributes(jo, def);
doWriteAttribute(jo, "configuration", def.getConfiguration(), null);
- doWriteAttribute(jo, "inheritErrorHandler",
toString(def.getInheritErrorHandler()), "false");
+ doWriteAttribute(jo, "inheritErrorHandler",
def.getInheritErrorHandler(), "false");
doWriteChildElement(jo, "resilience4jConfiguration",
def.getResilience4jConfiguration(),
this::doWriteResilience4jConfigurationDefinition);
doWriteChildElement(jo, "faultToleranceConfiguration",
def.getFaultToleranceConfiguration(),
this::doWriteFaultToleranceConfigurationDefinition);
doWriteChildElement(jo, "onFallback", def.getOnFallback(),
this::doWriteOnFallbackDefinition);
@@ -3164,7 +3164,7 @@ public class YamlModelWriter extends
YamlModelWriterSupport {
doWriteAttribute(jo, "roundRobin", def.getRoundRobin(), null);
doWriteAttribute(jo, "sticky", def.getSticky(), null);
doWriteAttribute(jo, "maximumFailoverAttempts",
def.getMaximumFailoverAttempts(), "-1");
- doWriteAttribute(jo, "inheritErrorHandler",
toString(def.getInheritErrorHandler()), "true");
+ doWriteAttribute(jo, "inheritErrorHandler",
def.getInheritErrorHandler(), "true");
doWriteStringList(jo, null, "exception", def.getExceptions());
return jo;
}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index e973045d1446..de812b6cca9d 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -1990,6 +1990,40 @@ The accessors changed accordingly:
The fluent builder `ParamDefinition.required(Boolean)` is unchanged, and a
`required(String)` overload
was added for placeholders. Routes written in XML, YAML or the Java DSL do not
need any change.
+=== camel-core - the inheritErrorHandler attribute on circuitBreaker and
failoverLoadBalancer is now a String
+
+`CircuitBreakerDefinition.inheritErrorHandler` and
`FailoverLoadBalancerDefinition.inheritErrorHandler` are now
+declared as `String` instead of `Boolean`, the same way nearly every other
scalar attribute in the Camel model
+is declared. This allows a property placeholder to be used, which is resolved
when the route starts:
+
+[source,yaml]
+----
+- route:
+ from:
+ uri: direct:start
+ steps:
+ - circuitBreaker:
+ inheritErrorHandler: "{{myInheritFlag}}"
+ steps:
+ - to:
+ uri: mock:a
+----
+
+Before this change the value was converted to a `Boolean` while the route was
being loaded, so
+`+inheritErrorHandler: "{{myInheritFlag}}"+` silently evaluated to `false`
instead of resolving the placeholder.
+
+The accessors changed accordingly:
+
+* `ProcessorDefinition.getInheritErrorHandler()` and
`setInheritErrorHandler(...)` now use `String` instead of
+ `Boolean`, and so do the overrides on `CircuitBreakerDefinition` and the
accessors on
+ `FailoverLoadBalancerDefinition`. Use
`CamelContextHelper.parseBoolean(camelContext, getInheritErrorHandler())`
+ where a `CamelContext` is available to resolve the value.
+
+The fluent builder `CircuitBreakerDefinition.inheritErrorHandler(boolean)` and
the `failover(...)` methods on
+`LoadBalanceDefinition` are unchanged, and a
`CircuitBreakerDefinition.inheritErrorHandler(String)` overload was
+added for placeholders. Routes written in XML, YAML or the Java DSL do not
need any change; the `inheritErrorHandler`
+attribute in the XML schema is now `xs:string` so a placeholder validates.
+
=== camel-weaviate - removed the unused vector field name header
The `CamelweaviateVectorFieldName` header
(`WeaviateVectorDbHeaders.VECTOR_FIELD_NAME`) has been removed.
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index 416175fdc142..828ccbd0fa72 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -2075,7 +2075,7 @@ public final class ModelDeserializers extends
YamlDeserializerSupport {
}
case "inheritErrorHandler": {
String val = asText(node);
-
target.setInheritErrorHandler(java.lang.Boolean.valueOf(val));
+ target.setInheritErrorHandler(val);
break;
}
case "onFallback": {
@@ -5330,7 +5330,7 @@ public final class ModelDeserializers extends
YamlDeserializerSupport {
}
case "inheritErrorHandler": {
String val = asText(node);
-
target.setInheritErrorHandler(java.lang.Boolean.valueOf(val));
+ target.setInheritErrorHandler(val);
break;
}
case "maximumFailoverAttempts": {
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
index 25351b09f954..366604c23b5a 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
@@ -813,9 +813,10 @@ public class YamlValidator {
* Everything else stays strict: unknown properties, structure (a map
where a list is expected), enums, and strings
* that do not parse as the expected type.
* <p>
- * This assumes the runtime defers the conversion for every scalar
attribute the schema exposes. The few model
- * attributes that are still converted while deserializing (so a
placeholder is never resolved for them) are not
- * reachable from the schema today - see CAMEL-24696 before exposing one
of them.
+ * This assumes the runtime defers the conversion for every scalar
attribute the schema exposes. The only model
+ * attribute that is still converted while deserializing (so a placeholder
is never resolved for it) is
+ * {@code BeanConstructorDefinition.index}, which is a map key and is not
reachable from the schema - see
+ * CAMEL-24696 before exposing it.
*/
static boolean isRuntimeAcceptedScalar(Error error) {
if (!"type".equals(error.getKeyword())) {
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorSchemaGroupsTest.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorSchemaGroupsTest.java
index e8fa22a06836..432cde9cb890 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorSchemaGroupsTest.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorSchemaGroupsTest.java
@@ -97,6 +97,12 @@ public class YamlValidatorSchemaGroupsTest {
Assertions.assertTrue(report.isEmpty(), "Expected no errors but got: "
+ messages(report));
}
+ @Test
+ public void testInheritErrorHandlerPlaceholder() throws Exception {
+ List<Error> report = validator.validate(new
File("src/test/resources/inherit-error-handler-placeholder.yaml"));
+ Assertions.assertTrue(report.isEmpty(), "Expected no errors but got: "
+ messages(report));
+ }
+
private static List<String> messages(List<Error> report) {
return report.stream().map(Error::getMessage).toList();
}
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/inherit-error-handler-placeholder.yaml
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/inherit-error-handler-placeholder.yaml
new file mode 100644
index 000000000000..52b80634ae05
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/inherit-error-handler-placeholder.yaml
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+- route:
+ from:
+ uri: direct:start
+ steps:
+ - circuitBreaker:
+ inheritErrorHandler: "{{myInherit}}"
+ steps:
+ - to:
+ uri: mock:a
+ - loadBalance:
+ failoverLoadBalancer:
+ inheritErrorHandler: "{{myInherit}}"
+ maximumFailoverAttempts: "10"
+ steps:
+ - to:
+ uri: mock:b
+ - to:
+ uri: mock:c
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/CircuitBreakerTest.groovy
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/CircuitBreakerTest.groovy
index 410e346990af..6c1e8421d4ee 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/CircuitBreakerTest.groovy
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/CircuitBreakerTest.groovy
@@ -60,6 +60,28 @@ class CircuitBreakerTest extends YamlTestSupport {
}
}
+ def "circuitBreaker inheritErrorHandler placeholder"() {
+ when:
+ // YamlTestSupport validates against the raw schema (without the
placeholder leniency of YamlValidator),
+ // which types inheritErrorHandler as boolean; the runtime resolves
the placeholder when the route starts
+ // and YamlValidatorSchemaGroupsTest covers that the validator accepts
it (CAMEL-24696)
+ loadRoutesNoValidate '''
+ - from:
+ uri: "direct:start"
+ steps:
+ - circuitBreaker:
+ inheritErrorHandler: "{{myInherit}}"
+ steps:
+ - log: "test"
+ '''
+ then:
+ with(context.routeDefinitions[0], RouteDefinition) {
+ with(outputs[0], CircuitBreakerDefinition) {
+ inheritErrorHandler == '{{myInherit}}'
+ }
+ }
+ }
+
def "circuitBreaker with onFallback steps"() {
when:
loadRoutes '''
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/LoadBalanceTest.groovy
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/LoadBalanceTest.groovy
index ada1ac578b4e..3929bb5aee02 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/LoadBalanceTest.groovy
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/LoadBalanceTest.groovy
@@ -18,6 +18,9 @@ package org.apache.camel.dsl.yaml
import org.apache.camel.dsl.yaml.support.YamlTestSupport
import org.apache.camel.component.mock.MockEndpoint
+import org.apache.camel.model.LoadBalanceDefinition
+import org.apache.camel.model.RouteDefinition
+import org.apache.camel.model.loadbalancer.FailoverLoadBalancerDefinition
import org.junit.jupiter.api.Assertions
class LoadBalanceTest extends YamlTestSupport {
@@ -56,4 +59,31 @@ class LoadBalanceTest extends YamlTestSupport {
MockEndpoint.assertIsSatisfied(context)
}
+ def "failoverLoadBalancer inheritErrorHandler placeholder"() {
+ when:
+ // YamlTestSupport validates against the raw schema (without the
placeholder leniency of YamlValidator),
+ // which types inheritErrorHandler as boolean; the runtime
resolves the placeholder when the route starts
+ // and YamlValidatorSchemaGroupsTest covers that the validator
accepts it (CAMEL-24696)
+ loadRoutesNoValidate '''
+ - from:
+ uri: "direct:start"
+ steps:
+ - loadBalance:
+ failoverLoadBalancer:
+ inheritErrorHandler: "{{myInherit}}"
+ maximumFailoverAttempts: "3"
+ steps:
+ - to: "mock:x"
+ - to: "mock:y"
+ '''
+ then:
+ with(context.routeDefinitions[0], RouteDefinition) {
+ with(outputs[0], LoadBalanceDefinition) {
+ with(loadBalancerType, FailoverLoadBalancerDefinition) {
+ inheritErrorHandler == '{{myInherit}}'
+ maximumFailoverAttempts == '3'
+ }
+ }
+ }
+ }
}