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 3404573 CAMEL-16913: convertBodyTo EIP - Allow to turn off mandatory. 3404573 is described below commit 34045738de92fc58eea935639468b46338d2b577 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Thu Sep 2 15:36:46 2021 +0200 CAMEL-16913: convertBodyTo EIP - Allow to turn off mandatory. --- .../org/apache/camel/model/convertBodyTo.json | 1 + .../org/apache/camel/model/dynamicRouter.json | 2 +- .../apache/camel/model/ConvertBodyDefinition.java | 22 ++++++++++++++++++++++ .../camel/model/DynamicRouterDefinition.java | 1 + .../apache/camel/model/ProcessorDefinition.java | 14 +++++++++++++- .../apache/camel/reifier/ConvertBodyReifier.java | 6 +++++- .../apache/camel/processor/ConvertBodyTest.java | 21 +++++++++++++++++++++ .../support/processor/ConvertBodyProcessor.java | 17 ++++++++++++++++- .../java/org/apache/camel/xml/in/ModelParser.java | 1 + .../dsl/yaml/deserializers/ModelDeserializers.java | 8 +++++++- .../src/generated/resources/camel-yaml-dsl.json | 5 ++++- 11 files changed, 92 insertions(+), 6 deletions(-) diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/convertBodyTo.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/convertBodyTo.json index 448e03b..4b84803 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/convertBodyTo.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/convertBodyTo.json @@ -12,6 +12,7 @@ }, "properties": { "type": { "kind": "attribute", "displayName": "Type", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The java type to convert to" }, + "mandatory": { "kind": "attribute", "displayName": "Mandatory", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "When mandatory then the conversion must return a value (cannot be null), if this is not possible then NoTypeConversionAvailableException is thrown. Setting this to false could mean conversion is not possible and the value is null." }, "charset": { "kind": "attribute", "displayName": "Charset", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To use a specific charset when converting" }, "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/dynamicRouter.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/dynamicRouter.json index 67431d9..345f21d 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/dynamicRouter.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/dynamicRouter.json @@ -13,7 +13,7 @@ "properties": { "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "description": "Expression to [...] "uriDelimiter": { "kind": "attribute", "displayName": "Uri Delimiter", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": ",", "description": "Sets the uri delimiter to use" }, - "ignoreInvalidEndpoints": { "kind": "attribute", "displayName": "Ignore Invalid Endpoints", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Ignore the invalidate endpoint exception when try to create a producer with that endpoint" }, + "ignoreInvalidEndpoints": { "kind": "attribute", "displayName": "Ignore Invalid Endpoints", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Ignore the invalidate endpoint exception when try to create a producer with that endpoint" }, "cacheSize": { "kind": "attribute", "displayName": "Cache Size", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the maximum size used by the org.apache.camel.spi.ProducerCache which is used to cache and reuse producers when using this dynamic router, when uris are reused. Beware that when using dynamic endpoints then it affects how well the cache can be utilized. If each dynamic end [...] "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/ConvertBodyDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/ConvertBodyDefinition.java index e0a387f..9795198 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/ConvertBodyDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/ConvertBodyDefinition.java @@ -34,6 +34,9 @@ public class ConvertBodyDefinition extends NoOutputDefinition<ConvertBodyDefinit @XmlAttribute(required = true) private String type; @XmlAttribute + @Metadata(javaType = "java.lang.Boolean", defaultValue = "true") + private String mandatory; + @XmlAttribute private String charset; @XmlTransient private Class<?> typeClass; @@ -50,6 +53,12 @@ public class ConvertBodyDefinition extends NoOutputDefinition<ConvertBodyDefinit setType(typeClass.getCanonicalName()); } + public ConvertBodyDefinition(Class<?> typeClass, boolean mandatory) { + setTypeClass(typeClass); + setType(typeClass.getCanonicalName()); + setMandatory(mandatory ? "true" : "false"); + } + public ConvertBodyDefinition(Class<?> typeClass, String charset) { setTypeClass(typeClass); setType(typeClass.getCanonicalName()); @@ -100,4 +109,17 @@ public class ConvertBodyDefinition extends NoOutputDefinition<ConvertBodyDefinit public void setCharset(String charset) { this.charset = charset; } + + public String getMandatory() { + return mandatory; + } + + /** + * When mandatory then the conversion must return a value (cannot be null), if this is not possible then + * NoTypeConversionAvailableException is thrown. Setting this to false could mean conversion is not possible and the + * value is null. + */ + public void setMandatory(String mandatory) { + this.mandatory = mandatory; + } } diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/DynamicRouterDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/DynamicRouterDefinition.java index d70289b..36a85b1 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/DynamicRouterDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/DynamicRouterDefinition.java @@ -42,6 +42,7 @@ public class DynamicRouterDefinition<Type extends ProcessorDefinition<Type>> ext @Metadata(defaultValue = ",") private String uriDelimiter; @XmlAttribute + @Metadata(javaType = "java.lang.Boolean") private String ignoreInvalidEndpoints; @XmlAttribute @Metadata(javaType = "java.lang.Integer") 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 6d2fe06..8efa326 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 @@ -2747,8 +2747,20 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type> /** * Converts the IN message body to the specified type * + * @param type the type to convert to + * @param mandatory whether to use mandatory type conversion or not + * @return the builder + */ + public Type convertBodyTo(Class<?> type, boolean mandatory) { + addOutput(new ConvertBodyDefinition(type, mandatory)); + return asType(); + } + + /** + * Converts the IN message body to the specified type + * * @param type the type to convert to - * @param charset the charset to use by type converters (not all converters support specifc charset) + * @param charset the charset to use by type converters (not all converters support specific charset) * @return the builder */ public Type convertBodyTo(Class<?> type, String charset) { diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ConvertBodyReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ConvertBodyReifier.java index 78fa218..441600d 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ConvertBodyReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ConvertBodyReifier.java @@ -35,7 +35,11 @@ public class ConvertBodyReifier extends ProcessorReifier<ConvertBodyDefinition> public Processor createProcessor() throws Exception { Class<?> typeClass = parse(Class.class, or(definition.getTypeClass(), parseString(definition.getType()))); String charset = validateCharset(parseString(definition.getCharset())); - return new ConvertBodyProcessor(typeClass, charset); + boolean mandatory = true; + if (definition.getMandatory() != null) { + mandatory = parseBoolean(definition.getMandatory(), true); + } + return new ConvertBodyProcessor(typeClass, charset, mandatory); } public static String validateCharset(String charset) throws UnsupportedCharsetException { diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/ConvertBodyTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/ConvertBodyTest.java index 54d6586..e8a8ab1 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/ConvertBodyTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/ConvertBodyTest.java @@ -24,6 +24,7 @@ import java.util.Locale; import org.apache.camel.ContextTestSupport; import org.apache.camel.Exchange; import org.apache.camel.InvalidPayloadException; +import org.apache.camel.NoTypeConversionAvailableException; import org.apache.camel.RuntimeCamelException; import org.apache.camel.builder.ExchangeBuilder; import org.apache.camel.builder.RouteBuilder; @@ -100,6 +101,25 @@ public class ConvertBodyTest extends ContextTestSupport { } @Test + public void testConvertToIntegerNotMandatory() throws Exception { + // mandatory should fail + try { + template.sendBody("direct:start", Double.NaN); + fail(); + } catch (Exception e) { + assertIsInstanceOf(NoTypeConversionAvailableException.class, e.getCause().getCause()); + } + + // optional should cause null body + getMockEndpoint("mock:result").expectedMessageCount(1); + getMockEndpoint("mock:result").message(0).body().isNull(); + + template.sendBody("direct:optional", Double.NaN); + + assertMockEndpointsSatisfied(); + } + + @Test public void testConvertNullBody() throws Exception { MockEndpoint result = getMockEndpoint("mock:result"); result.expectedMessageCount(1); @@ -189,6 +209,7 @@ public class ConvertBodyTest extends ContextTestSupport { return new RouteBuilder() { public void configure() { from("direct:start").convertBodyTo(Integer.class).to("mock:result"); + from("direct:optional").convertBodyTo(Integer.class, false).to("mock:result"); from("direct:invalid").convertBodyTo(Date.class).to("mock:result"); from("direct:charset").convertBodyTo(byte[].class, "iso-8859-1").to("mock:result"); from("direct:charset2").convertBodyTo(byte[].class, "utf-16").to("mock:result"); diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/ConvertBodyProcessor.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/ConvertBodyProcessor.java index 259f348..787c0f5 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/processor/ConvertBodyProcessor.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/ConvertBodyProcessor.java @@ -42,17 +42,27 @@ public class ConvertBodyProcessor extends ServiceSupport implements AsyncProcess private String routeId; private final Class<?> type; private final String charset; + private final boolean mandatory; public ConvertBodyProcessor(Class<?> type) { ObjectHelper.notNull(type, "type", this); this.type = type; this.charset = null; + this.mandatory = true; } public ConvertBodyProcessor(Class<?> type, String charset) { ObjectHelper.notNull(type, "type", this); this.type = type; this.charset = IOHelper.normalizeCharset(charset); + this.mandatory = true; + } + + public ConvertBodyProcessor(Class<?> type, String charset, boolean mandatory) { + ObjectHelper.notNull(type, "type", this); + this.type = type; + this.charset = IOHelper.normalizeCharset(charset); + this.mandatory = mandatory; } @Override @@ -103,7 +113,12 @@ public class ConvertBodyProcessor extends ServiceSupport implements AsyncProcess exchange.setProperty(ExchangePropertyKey.CHARSET_NAME, charset); } // use mandatory conversion - Object value = old.getMandatoryBody(type); + Object value; + if (mandatory) { + value = old.getMandatoryBody(type); + } else { + value = old.getBody(type); + } // create a new message container so we do not drag specialized message objects along // but that is only needed if the old message is a specialized message 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 b33981d..3026944 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 @@ -285,6 +285,7 @@ public class ModelParser extends BaseParser { return doParse(new ConvertBodyDefinition(), (def, key, val) -> { switch (key) { case "charset": def.setCharset(val); break; + case "mandatory": def.setMandatory(val); break; case "type": def.setType(val); break; default: return processorDefinitionAttributeHandler().accept(def, key, val); } 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 56ecd7b..e50ac3c 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 @@ -2126,6 +2126,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport { properties = { @YamlProperty(name = "charset", type = "string"), @YamlProperty(name = "inherit-error-handler", type = "boolean"), + @YamlProperty(name = "mandatory", type = "boolean"), @YamlProperty(name = "type", type = "string", required = true) } ) @@ -2158,6 +2159,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport { target.setInheritErrorHandler(java.lang.Boolean.valueOf(val)); break; } + case "mandatory": { + String val = asText(node); + target.setMandatory(val); + break; + } case "type": { String val = asText(node); target.setType(val); @@ -4191,7 +4197,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport { @YamlProperty(name = "__extends", type = "object:org.apache.camel.model.language.ExpressionDefinition"), @YamlProperty(name = "cache-size", type = "number"), @YamlProperty(name = "expression", type = "object:org.apache.camel.model.language.ExpressionDefinition"), - @YamlProperty(name = "ignore-invalid-endpoints", type = "string"), + @YamlProperty(name = "ignore-invalid-endpoints", type = "boolean"), @YamlProperty(name = "inherit-error-handler", type = "boolean"), @YamlProperty(name = "uri-delimiter", type = "string") } diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json index 10e7ac6..d5b780e 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json @@ -576,6 +576,9 @@ "inherit-error-handler" : { "type" : "boolean" }, + "mandatory" : { + "type" : "boolean" + }, "type" : { "type" : "string" } @@ -642,7 +645,7 @@ "$ref" : "#/items/definitions/org.apache.camel.model.language.ExpressionDefinition" }, "ignore-invalid-endpoints" : { - "type" : "string" + "type" : "boolean" }, "inherit-error-handler" : { "type" : "boolean"