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 861026f8faa2 CAMEL-24702: camel-yaml-dsl - YAML load errors say what
to write: unknown expression or field with the nearest name, beans class not
found (#26361)
861026f8faa2 is described below
commit 861026f8faa21946933aca88b3f5033d3e97e424
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Sep 13 15:49:46 2026 +0200
CAMEL-24702: camel-yaml-dsl - YAML load errors say what to write: unknown
expression or field with the nearest name, beans class not found (#26361)
* CAMEL-24702: camel-yaml-dsl - YAML load errors say what to write: unknown
expression or field with the nearest name, beans class not found, the file's
shape
Squash of the 5 commits on fix/CAMEL-24702 (the run-by-run history is on
bench/after-run).
camel-yaml-dsl - say that an expression is expected when a plain value is
used for handled, continued and the other expression options
camel-yaml-dsl - do not wrap the expression message in Error constructing
YAML node id
camel-yaml-dsl - 'Unknown expression with id: bean' says the bean language
is written as method:
camel-yaml-dsl - an unsupported field names the node and the field, and
bean as a language says method:
camel-yaml-dsl - 'Error creating bean' names the class that was not found
and the built-in strategy package
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Bp3538HRBPMQkb5ta9xRaj
* CAMEL-24702: camel-yaml-dsl - the class-not-found hint names the class in
dotted form also for NoClassDefFoundError
Review note on PR 26361: NoClassDefFoundError.getMessage() uses the
internal java/lang/Foo form.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Bp3538HRBPMQkb5ta9xRaj
---------
Co-authored-by: Claude Fable 5.1 <[email protected]>
---
.../yaml/common/YamlDeserializationContext.java | 17 ++-
.../deserializers/ExpressionDeserializers.java | 8 +-
.../dsl/yaml/deserializers/BeansDeserializer.java | 28 ++++-
.../dsl/yaml/GenerateYamlDeserializersMojo.java | 15 ++-
.../camel/dsl/yaml/validator/YamlValidator.java | 53 +++++++-
.../validator/YamlValidatorExpressionHintTest.java | 139 +++++++++++++++++++++
.../apache/camel/dsl/yaml/OnExceptionTest.groovy | 40 ++++++
7 files changed, 294 insertions(+), 6 deletions(-)
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationContext.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationContext.java
index cb95ebf8e3b7..5cbabd0a741b 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationContext.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-common/src/main/java/org/apache/camel/dsl/yaml/common/YamlDeserializationContext.java
@@ -28,7 +28,9 @@ import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.Service;
import org.apache.camel.dsl.yaml.common.exception.DuplicateKeyException;
+import org.apache.camel.dsl.yaml.common.exception.InvalidExpressionException;
import org.apache.camel.dsl.yaml.common.exception.UnknownNodeIdException;
+import org.apache.camel.dsl.yaml.common.exception.UnsupportedFieldException;
import org.apache.camel.dsl.yaml.common.exception.YamlDeserializationException;
import org.apache.camel.spi.Resource;
import org.apache.camel.support.OrderedComparator;
@@ -404,8 +406,21 @@ public class YamlDeserializationContext extends
StandardConstructor implements C
return constructor.construct(node);
} catch (DuplicateKeyException | UnknownNodeIdException e) {
throw e;
- } catch (YamlDeserializationException e) {
+ } catch (YamlDeserializationException | InvalidExpressionException e) {
+ // already says what is wrong and where
throw e;
+ } catch (UnsupportedFieldException e) {
+ // name the node and the field, and for a field that is a mistaken
language name say what to write
+ String field = e.getProblem() != null &&
e.getProblem().startsWith("Unsupported field: ")
+ ? e.getProblem().substring("Unsupported field: ".length())
: null;
+ String hint = "";
+ if ("bean".equals(field)) {
+ hint = " (the bean language is written as method: {ref:
myBean, method: process})";
+ } else if ("expression".equals(field) || "language".equals(field))
{
+ hint = " (an expression is written with the language as the
key: simple: \"...\", constant: \"...\")";
+ }
+ throw new YamlDeserializationException(
+ node, "Error constructing YAML node id: " + id + ":
unsupported field: " + field + hint, e);
} catch (RuntimeException e) {
throw new YamlDeserializationException(node, "Error constructing
YAML node id: " + id, e);
}
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ExpressionDeserializers.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ExpressionDeserializers.java
index 394bc6839bbb..9933c583d163 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ExpressionDeserializers.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ExpressionDeserializers.java
@@ -8,6 +8,7 @@ import java.lang.SuppressWarnings;
import javax.annotation.processing.Generated;
import org.apache.camel.dsl.yaml.common.YamlDeserializationContext;
import org.apache.camel.dsl.yaml.common.YamlDeserializerSupport;
+import org.apache.camel.dsl.yaml.common.exception.InvalidExpressionException;
import org.apache.camel.model.language.ExpressionDefinition;
import org.apache.camel.spi.annotations.YamlProperty;
import org.apache.camel.spi.annotations.YamlType;
@@ -15,6 +16,7 @@ import org.snakeyaml.engine.v2.api.ConstructNode;
import org.snakeyaml.engine.v2.nodes.MappingNode;
import org.snakeyaml.engine.v2.nodes.Node;
import org.snakeyaml.engine.v2.nodes.NodeTuple;
+import org.snakeyaml.engine.v2.nodes.ScalarNode;
/**
* The model automatically scan all classes, also those one deprecated. They
will be dropped when removed from core model.
@@ -37,7 +39,7 @@ public final class ExpressionDeserializers extends
YamlDeserializerSupport {
Node val = setDeserializationContext(nt.getValueNode(), dc);
ExpressionDefinition answer = constructExpressionType(key, val);
if (answer == null) {
- throw new
org.apache.camel.dsl.yaml.common.exception.InvalidExpressionException(node,
"Unknown expression with id: " + key);
+ throw new
org.apache.camel.dsl.yaml.common.exception.InvalidExpressionException(node,
"Unknown expression with id: " + key + ("bean".equals(key) ? " (the bean
language is written as method: {ref: myBean, method: process})" : ""));
}
return answer;
}
@@ -219,6 +221,10 @@ public final class ExpressionDeserializers extends
YamlDeserializerSupport {
public static class ExpressionSubElementDefinitionDeserializers implements
ConstructNode {
@Override
public Object construct(Node node) {
+ if (!(node instanceof MappingNode)) {
+ String text = node instanceof ScalarNode ? asText(node) :
node.getNodeType().name().toLowerCase();
+ throw new InvalidExpressionException(node, "an expression is
expected here, not a plain value (" + text + "): write constant: \"" + text +
"\" for a fixed value, or simple: \"...\" for a dynamic one");
+ }
ExpressionDefinition val = constructExpressionType(node);
return new
org.apache.camel.model.ExpressionSubElementDefinition(val);
}
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/BeansDeserializer.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/BeansDeserializer.java
index a5a53eded9df..cc616d59e384 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/BeansDeserializer.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/BeansDeserializer.java
@@ -125,7 +125,7 @@ public class BeansDeserializer extends
YamlDeserializerSupport implements Constr
} else {
String msg
= name != null ? "Error creating bean: " + name + " of
type: " + type : "Error creating bean: " + type;
- throw new RuntimeException(msg, e);
+ throw new RuntimeException(msg + classNotFoundHint(e), e);
}
}
}
@@ -190,4 +190,30 @@ public class BeansDeserializer extends
YamlDeserializerSupport implements Constr
model.addCustomBean(def);
}
+ /**
+ * The cause of a bean that could not be created is a
ClassNotFoundException more often than not (a wrong package, a
+ * missing dependency); say so, and for a Camel aggregation strategy
written in the wrong package name the right
+ * one.
+ */
+ static String classNotFoundHint(Throwable e) {
+ for (Throwable t = e; t != null; t = t.getCause()) {
+ if (t instanceof ClassNotFoundException || t instanceof
NoClassDefFoundError) {
+ // NoClassDefFoundError names the class in internal form
(java/lang/Foo)
+ String cls = t.getMessage() != null ?
t.getMessage().trim().replace('/', '.') : "";
+ String simple = cls.substring(cls.lastIndexOf('.') + 1);
+ String hint = ": class " + cls + " was not found";
+ if (simple.endsWith("AggregationStrategy") &&
!cls.startsWith("org.apache.camel.processor.aggregate.")) {
+ String candidate = "org.apache.camel.processor.aggregate."
+ simple;
+ try {
+ Class.forName(candidate, false,
BeansDeserializer.class.getClassLoader());
+ return hint + " (did you mean " + candidate + "?)";
+ } catch (Throwable ignore) {
+ // not one of the built-in strategies
+ }
+ }
+ return hint + " (check the package name; a class from another
library needs its dependency added)";
+ }
+ }
+ return "";
+ }
}
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlDeserializersMojo.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlDeserializersMojo.java
index d0d60ae00fa9..632d5f8565f8 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlDeserializersMojo.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlDeserializersMojo.java
@@ -184,7 +184,7 @@ public class GenerateYamlDeserializersMojo extends
GenerateYamlSupportMojo {
.addStatement("ExpressionDefinition answer =
constructExpressionType(key, val)")
.beginControlFlow("if (answer == null)")
.addStatement(
- "throw new
org.apache.camel.dsl.yaml.common.exception.InvalidExpressionException(node,
\"Unknown expression with id: \" + key)")
+ "throw new
org.apache.camel.dsl.yaml.common.exception.InvalidExpressionException(node,
\"Unknown expression with id: \" + key + (\"bean\".equals(key) ? \" (the bean
language is written as method: {ref: myBean, method: process})\" : \"\"))")
.endControlFlow()
.addStatement("return answer")
.build())
@@ -295,6 +295,19 @@ public class GenerateYamlDeserializersMojo extends
GenerateYamlSupportMojo {
.addAnnotation(Override.class)
.addParameter(Node.class, "node")
.returns(Object.class)
+ // CAMEL-24702: a plain value
(handled: true) must say what is expected instead
+ .beginControlFlow("if (!(node
instanceof $T))",
+
ClassName.get("org.snakeyaml.engine.v2.nodes", "MappingNode"))
+ .addStatement(
+ "String text = node instanceof
$T ? asText(node) : node.getNodeType().name().toLowerCase()",
+
ClassName.get("org.snakeyaml.engine.v2.nodes", "ScalarNode"))
+ .addStatement("throw new $T(node, $S +
text + $S + text + $S)",
+
ClassName.get("org.apache.camel.dsl.yaml.common.exception",
+
"InvalidExpressionException"),
+ "an expression is expected
here, not a plain value (",
+ "): write constant: \"",
+ "\" for a fixed value, or
simple: \"...\" for a dynamic one")
+ .endControlFlow()
.addStatement("$T val =
constructExpressionType(node)", CN_EXPRESSION_DEFINITION)
.addStatement("return new
org.apache.camel.model.ExpressionSubElementDefinition(val)")
.build())
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 882b2b9b022c..d5be9f63144d 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
@@ -118,6 +118,7 @@ public class YamlValidator {
private List<Error> validate(JsonNode target) {
var errors = filterOneOfNoise(new
ArrayList<>(schema.validate(target)));
errors.removeIf(YamlValidator::isRuntimeAcceptedScalar);
+ errors = withExpressionHints(errors);
if (canonical) {
checkOneOfCardinality(target, new NodePath(PathType.JSON_POINTER),
errors);
}
@@ -351,8 +352,8 @@ public class YamlValidator {
* <li>a quoted scalar that parses as the expected type (e.g. {@code
parallelProcessing: "true"}) - the runtime
* converts the text.</li>
* </ul>
- * 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.
+ * 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
@@ -383,6 +384,54 @@ public class YamlValidator {
return (instance.isNumber() || instance.isBoolean()) &&
isExpectedType(error, "string");
}
+ /**
+ * Replaces the schema's "boolean found, object expected" for a plain
value at an option that takes an expression
+ * (such as {@code handled: true} on onException, or {@code
completionSizeExpression: 10} on aggregate) with a
+ * message that shows the expression form, and drops the duplicates the
schema composition produces for it.
+ */
+ static List<Error> withExpressionHints(List<Error> errors) {
+ List<Error> answer = new ArrayList<>(errors.size());
+ Set<String> seen = new LinkedHashSet<>();
+ for (Error error : errors) {
+ Error hinted = withExpressionHint(error);
+ if (hinted == error || seen.add(hinted.getInstanceLocation() + " "
+ hinted.getMessage())) {
+ answer.add(hinted);
+ }
+ }
+ return answer;
+ }
+
+ static Error withExpressionHint(Error error) {
+ if (!"type".equals(error.getKeyword())) {
+ return error;
+ }
+ JsonNode instance = error.getInstanceNode();
+ if (instance == null || !instance.isValueNode()) {
+ return error;
+ }
+ String schemaLocation = String.valueOf(error.getSchemaLocation());
+ String evaluationPath = String.valueOf(error.getEvaluationPath());
+ if (!schemaLocation.contains(EXPRESSION_SUB_ELEMENT) &&
!evaluationPath.contains(EXPRESSION_SUB_ELEMENT)) {
+ return error;
+ }
+ String location = String.valueOf(error.getInstanceLocation());
+ String name = location.substring(location.lastIndexOf('/') + 1);
+ String value = instance.asText();
+ String message = String.format(
+ "a plain value (%s) found, an expression expected: write %s:
{constant: \"%s\"} for a fixed value, or %s: {simple: \"...\"} for a dynamic
one",
+ value, name, value, name);
+ // the message is not a MessageFormat pattern (it contains braces), so
pass it as the single argument
+ return Error.builder()
+ .keyword("type")
+ .instanceLocation(error.getInstanceLocation())
+ .messageKey("expression")
+ .format(new MessageFormat("{0}"))
+ .arguments(message)
+ .build();
+ }
+
+ private static final String EXPRESSION_SUB_ELEMENT =
"ExpressionSubElementDefinition";
+
private static boolean isBooleanText(String text) {
String s = text.trim();
return "true".equalsIgnoreCase(s) || "false".equalsIgnoreCase(s);
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorExpressionHintTest.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorExpressionHintTest.java
new file mode 100644
index 000000000000..1fe58e691fd5
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorExpressionHintTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.dsl.yaml.validator;
+
+import java.util.List;
+
+import com.networknt.schema.Error;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * CAMEL-24702: options that take an expression (handled, continued,
retryWhile, the aggregate and throttle correlation
+ * expressions) are commonly written as a plain value. The DSL does not accept
that, so the validator must say what to
+ * write instead of "boolean found, object expected".
+ */
+public class YamlValidatorExpressionHintTest {
+
+ private static YamlValidator classic;
+ private static YamlValidator canonical;
+
+ @BeforeAll
+ public static void setup() throws Exception {
+ classic = new YamlValidator();
+ classic.init();
+ canonical = new YamlValidator(true);
+ canonical.init();
+ }
+
+ @Test
+ public void testHandledAsPlainValue() {
+ String yaml = """
+ - onException:
+ exception:
+ - java.lang.Exception
+ handled: true
+ steps:
+ - log:
+ message: "Error: ${exception.message}"
+ """;
+ assertHint(yaml, "handled: {constant: \"true\"}", "handled: {simple:
\"...\"}");
+ }
+
+ @Test
+ public void testContinuedAsPlainValue() {
+ String yaml = """
+ - onException:
+ exception:
+ - java.lang.Exception
+ continued: "true"
+ steps:
+ - log:
+ message: "Error: ${exception.message}"
+ """;
+ assertHint(yaml, "continued: {constant: \"true\"}");
+ }
+
+ @Test
+ public void testAggregateCompletionSizeAsPlainValue() {
+ String yaml = """
+ - from:
+ uri: timer:tick
+ steps:
+ - aggregate:
+ correlationExpression:
+ constant:
+ expression: "a"
+ completionSizeExpression: 10
+ aggregationStrategy: myStrategy
+ steps:
+ - log:
+ message: "${body}"
+ """;
+ assertHint(yaml, "completionSizeExpression: {constant: \"10\"}");
+ }
+
+ @Test
+ public void testExpressionFormIsAccepted() {
+ // explicit form, so that it is valid in canonical mode too
+ String yaml = """
+ - onException:
+ exception:
+ - java.lang.Exception
+ handled:
+ constant:
+ expression: "true"
+ continued:
+ simple:
+ expression: "${header.retry} == null"
+ steps:
+ - log:
+ message: "Error: ${exception.message}"
+ """;
+ for (YamlValidator validator : List.of(classic, canonical)) {
+ assertThat(validate(validator, yaml)).isEmpty();
+ }
+ }
+
+ private void assertHint(String yaml, String... expectedInMessage) {
+ for (YamlValidator validator : List.of(classic, canonical)) {
+ String mode = validator.isCanonical() ? "canonical" : "classic";
+ List<Error> errors = validate(validator, yaml);
+ assertThat(errors).as("%s mode must report the plain value:\n%s",
mode, yaml).isNotEmpty();
+ for (String expected : expectedInMessage) {
+ assertThat(errors)
+ .as("%s mode must show the expression form '%s'",
mode, expected)
+ .anyMatch(e -> e.getMessage().contains(expected));
+ }
+ // one hint, not the two or three type errors the schema
composition produces
+ assertThat(errors.stream().filter(e -> e.getMessage().contains("an
expression expected")).count())
+ .as("%s mode must report the hint once", mode)
+ .isEqualTo(1);
+ assertThat(errors).noneMatch(e -> e.getMessage().contains("object
expected"));
+ }
+ }
+
+ private List<Error> validate(YamlValidator validator, String yaml) {
+ try {
+ return validator.validate(yaml);
+ } catch (Exception e) {
+ throw new AssertionError("Failed to validate:\n" + yaml, e);
+ }
+ }
+}
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/OnExceptionTest.groovy
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/OnExceptionTest.groovy
index d37d2b9e1749..f880731fc838 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/OnExceptionTest.groovy
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/OnExceptionTest.groovy
@@ -20,6 +20,7 @@ import org.apache.camel.dsl.yaml.support.YamlTestSupport
import org.apache.camel.component.mock.MockEndpoint
import org.apache.camel.dsl.yaml.support.model.MyException
import org.apache.camel.dsl.yaml.support.model.MyFailingProcessor
+import org.apache.camel.support.ResourceHelper
import org.junit.jupiter.api.Assertions
class OnExceptionTest extends YamlTestSupport {
@@ -59,4 +60,43 @@ class OnExceptionTest extends YamlTestSupport {
MockEndpoint.assertIsSatisfied(context)
}
+ // CAMEL-24702: handled is an expression; a plain value must fail with a
message that says what to write
+ def "onException handled as plain value fails with a helpful message"() {
+ when:
+ loadRoutes([ResourceHelper.fromString("route-0.yaml", '''
+ - onException:
+ handled: true
+ exception:
+ - java.lang.Exception
+ steps:
+ - to: "mock:on-exception"
+ '''.stripIndent())], false)
+ then:
+ def e = thrown(Exception)
+ def messages = []
+ for (Throwable t = e; t != null; t = t.cause) {
+ messages << t.message
+ }
+ messages.any { it != null && it.contains('an expression is
expected here, not a plain value (true)') && it.contains('constant: "true"') }
+ }
+
+
+ // CAMEL-24702: an unsupported field names the node and the field; bean as
a language says method:
+ def "setBody with bean as a field fails with a message naming the field"()
{
+ when:
+ loadRoutes([ResourceHelper.fromString("route-1.yaml", '''
+ - from:
+ uri: timer:tick
+ steps:
+ - setBody:
+ bean: myBean
+ '''.stripIndent())], false)
+ then:
+ def e = thrown(Exception)
+ def messages = []
+ for (Throwable t = e; t != null; t = t.cause) {
+ messages << t.message
+ }
+ messages.any { it != null && it.contains('Error constructing YAML
node id: setBody: unsupported field: bean') && it.contains('method: {ref:
myBean, method: process}') }
+ }
}