You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/04/04 10:18:50 UTC

[camel] branch main updated (1ce12d32b1a -> bd857c0a18e)

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

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


    from 1ce12d32b1a added try with resources for ArangoCursor (#9793)
     new fbbb2753c14 CAMEL-19244: camel-bean - Add support for declaring type in parameter values using 'type.class value' style
     new d63f16d09db Guard against NPE
     new bd857c0a18e CAMEL-19244: camel-bean - Add support for declaring type in parameter values using 'type.class value' style

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../bean/AmbiguousMethodCallException.java         | 17 +++++++-
 .../apache/camel/component/bean/BeanHelper.java    | 22 +++++++---
 .../org/apache/camel/component/bean/BeanInfo.java  | 32 ++++++++++-----
 .../apache/camel/component/bean/MethodInfo.java    | 13 ++++--
 .../camel/impl/engine/DefaultRoutesLoader.java     |  2 +
 .../apache/camel/model/ProcessorDefinition.java    | 10 ++++-
 .../component/bean/BeanOverloadedMethodTest.java   |  2 +-
 .../bean/BeanOverloadsWithAssignableParamTest.java |  2 +-
 .../issues/BeanParameterTypeAndValueTest.java}     | 47 +++++++++++++---------
 .../modules/ROOT/pages/bean-binding.adoc           | 20 +++++++--
 10 files changed, 120 insertions(+), 47 deletions(-)
 copy core/camel-core/src/test/java/org/apache/camel/component/{validator/ValidatorLazyStartProducerTest.java => bean/issues/BeanParameterTypeAndValueTest.java} (50%)


[camel] 01/03: CAMEL-19244: camel-bean - Add support for declaring type in parameter values using 'type.class value' style

Posted by da...@apache.org.
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

commit fbbb2753c14139472612fedae4529043fc3dd990
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Apr 3 21:09:28 2023 +0200

    CAMEL-19244: camel-bean - Add support for declaring type in parameter values using 'type.class value' style
---
 .../apache/camel/component/bean/BeanHelper.java    | 22 +++++++++++++++++-----
 .../org/apache/camel/component/bean/BeanInfo.java  |  4 ++--
 .../apache/camel/component/bean/MethodInfo.java    | 13 +++++++++----
 3 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanHelper.java b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanHelper.java
index 25273912640..68bd15062c9 100644
--- a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanHelper.java
+++ b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanHelper.java
@@ -35,7 +35,7 @@ public final class BeanHelper {
      * @param  value the value
      * @return       the parameter type the given value is being mapped as, or <tt>null</tt> if not valid.
      */
-    public static Class<?> getValidParameterType(String value) {
+    public static Class<?> getValidParameterType(ClassResolver resolver, String value) {
         if (ObjectHelper.isEmpty(value)) {
             return null;
         }
@@ -70,7 +70,12 @@ public final class BeanHelper {
 
         // numeric is valid
         boolean numeric = true;
-        for (char ch : value.toCharArray()) {
+        char[] chars = value.toCharArray();
+        for (int i = 0; i < chars.length; i++) {
+            char ch = chars[i];
+            if (i == 0 && ch == '-') {
+                continue;
+            }
             if (!Character.isDigit(ch)) {
                 numeric = false;
                 break;
@@ -90,13 +95,13 @@ public final class BeanHelper {
      * @param  value the value
      * @return       <tt>true</tt> if valid, <tt>false</tt> otherwise
      */
-    public static boolean isValidParameterValue(String value) {
+    public static boolean isValidParameterValue(ClassResolver classResolver, String value) {
         if (ObjectHelper.isEmpty(value)) {
             // empty value is valid
             return true;
         }
 
-        return getValidParameterType(value) != null;
+        return getValidParameterType(classResolver, value) != null;
     }
 
     /**
@@ -117,7 +122,14 @@ public final class BeanHelper {
      *                       assignable, <tt>false</tt> if not assignable
      */
     public static Boolean isAssignableToExpectedType(ClassResolver resolver, String parameterType, Class<?> expectedType) {
-        if (parameterType == null || !parameterType.endsWith(".class")) {
+        if (parameterType == null || !parameterType.contains(".class")) {
+            // not a class so return null
+            return null;
+        }
+        if (parameterType.contains(" ")) {
+            parameterType = StringHelper.before(parameterType, " ");
+        }
+        if (!parameterType.endsWith(".class")) {
             // not a class so return null
             return null;
         }
diff --git a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
index baf5febbb9a..b918711dc1a 100644
--- a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
+++ b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
@@ -682,7 +682,7 @@ public class BeanInfo {
                     parameter = parameter.trim();
                 }
 
-                Class<?> parameterType = BeanHelper.getValidParameterType(parameter);
+                Class<?> parameterType = BeanHelper.getValidParameterType(exchange.getContext().getClassResolver(), parameter);
                 Class<?> expectedType = info.getParameters().get(index).getType();
 
                 if (parameterType != null && expectedType != null) {
@@ -1113,7 +1113,7 @@ public class BeanInfo {
                         continue;
                     }
 
-                    if (BeanHelper.isValidParameterValue(qualifyType)) {
+                    if (BeanHelper.isValidParameterValue(getCamelContext().getClassResolver(), qualifyType)) {
                         // its a parameter value, so continue to next parameter
                         // as we should only check for FQN/type parameters
                         continue;
diff --git a/components/camel-bean/src/main/java/org/apache/camel/component/bean/MethodInfo.java b/components/camel-bean/src/main/java/org/apache/camel/component/bean/MethodInfo.java
index 0a402f2e334..ee1b5cbb06f 100644
--- a/components/camel-bean/src/main/java/org/apache/camel/component/bean/MethodInfo.java
+++ b/components/camel-bean/src/main/java/org/apache/camel/component/bean/MethodInfo.java
@@ -259,7 +259,6 @@ public class MethodInfo {
         if (hasParameters) {
             if (parametersExpression != null) {
                 parametersExpression.init(camelContext);
-
                 return parametersExpression.evaluate(exchange, Object[].class);
             }
         }
@@ -648,10 +647,16 @@ public class MethodInfo {
 
             // convert the parameter value to a String
             String exp = exchange.getContext().getTypeConverter().convertTo(String.class, exchange, parameterValue);
+            boolean valid;
             if (exp != null) {
-                // check if its a valid parameter value
-                boolean valid = BeanHelper.isValidParameterValue(exp);
+                int pos1 = exp.indexOf(' ');
+                int pos2 = exp.indexOf(".class");
+                if (pos1 != -1 && pos2 != -1 && pos1 > pos2) {
+                    exp = exp.substring(pos2 + 7); // clip <space>.class
+                }
 
+                // check if its a valid parameter value (no type declared via .class syntax)
+                valid = BeanHelper.isValidParameterValue(exchange.getContext().getClassResolver(), exp);
                 if (!valid) {
                     // it may be a parameter type instead, and if so, then we should return null,
                     // as this method is only for evaluating parameter values
@@ -697,7 +702,7 @@ public class MethodInfo {
                             // which may change the parameterValue, so we have to check it again to see if it is now valid
                             exp = exchange.getContext().getTypeConverter().tryConvertTo(String.class, parameterValue);
                             // re-validate if the parameter was not valid the first time
-                            valid = BeanHelper.isValidParameterValue(exp);
+                            valid = BeanHelper.isValidParameterValue(exchange.getContext().getClassResolver(), exp);
                         }
                     }
                 }


[camel] 03/03: CAMEL-19244: camel-bean - Add support for declaring type in parameter values using 'type.class value' style

Posted by da...@apache.org.
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

commit bd857c0a18e18b4967acdb0c723b1d4b16def0c9
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Apr 4 12:16:05 2023 +0200

    CAMEL-19244: camel-bean - Add support for declaring type in parameter values using 'type.class value' style
---
 .../bean/AmbiguousMethodCallException.java         | 17 ++++-
 .../org/apache/camel/component/bean/BeanInfo.java  | 30 ++++++---
 .../apache/camel/model/ProcessorDefinition.java    | 10 ++-
 .../component/bean/BeanOverloadedMethodTest.java   |  2 +-
 .../bean/BeanOverloadsWithAssignableParamTest.java |  2 +-
 .../bean/issues/BeanParameterTypeAndValueTest.java | 74 ++++++++++++++++++++++
 .../modules/ROOT/pages/bean-binding.adoc           | 20 +++++-
 7 files changed, 138 insertions(+), 17 deletions(-)

diff --git a/components/camel-bean/src/main/java/org/apache/camel/component/bean/AmbiguousMethodCallException.java b/components/camel-bean/src/main/java/org/apache/camel/component/bean/AmbiguousMethodCallException.java
index 2ebe949c515..1cda5179744 100644
--- a/components/camel-bean/src/main/java/org/apache/camel/component/bean/AmbiguousMethodCallException.java
+++ b/components/camel-bean/src/main/java/org/apache/camel/component/bean/AmbiguousMethodCallException.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.bean;
 
 import java.util.Collection;
+import java.util.StringJoiner;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.RuntimeExchangeException;
@@ -30,7 +31,7 @@ public class AmbiguousMethodCallException extends RuntimeExchangeException {
     private final Collection<MethodInfo> methods;
 
     public AmbiguousMethodCallException(Exchange exchange, Collection<MethodInfo> methods) {
-        super("Ambiguous method invocations possible: " + methods, exchange);
+        super(createMessage(methods), exchange);
         this.methods = methods;
     }
 
@@ -40,4 +41,18 @@ public class AmbiguousMethodCallException extends RuntimeExchangeException {
     public Collection<MethodInfo> getMethods() {
         return methods;
     }
+
+    private static String createMessage(Collection<MethodInfo> methods) {
+        Class<?> clazz = null;
+        StringJoiner sj = new StringJoiner("\n\t");
+        for (MethodInfo mi : methods) {
+            if (clazz == null) {
+                clazz = mi.getMethod().getDeclaringClass();
+                sj.add("\tClass: " + clazz.getName());
+            }
+            sj.add("\t" + mi.getMethod().toGenericString());
+        }
+        return "Ambiguous method invocations possible:\n" + sj + "\n\n";
+    }
+
 }
diff --git a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
index b918711dc1a..c0f59bf911f 100644
--- a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
+++ b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
@@ -244,7 +244,7 @@ public class BeanInfo {
                         }
                     }
 
-                    if (methodInfo == null || name != null && !name.equals(methodInfo.getMethod().getName())) {
+                    if (methodInfo == null || !name.equals(methodInfo.getMethod().getName())) {
                         throw new AmbiguousMethodCallException(exchange, methods);
                     }
                 } else {
@@ -1091,7 +1091,7 @@ public class BeanInfo {
         String types = StringHelper.betweenOuterPair(methodName, '(', ')');
         if (org.apache.camel.util.ObjectHelper.isNotEmpty(types)) {
             // we must qualify based on types to match method
-            String[] parameters = StringQuoteHelper.splitSafeQuote(types, ',');
+            String[] parameters = StringQuoteHelper.splitSafeQuote(types, ',', true, true);
             Class<?>[] parameterTypes = null;
             Iterator<?> it = ObjectHelper.createIterator(parameters);
             for (int i = 0; i < method.getParameterCount(); i++) {
@@ -1107,18 +1107,23 @@ public class BeanInfo {
                     }
                     // trim the type
                     qualifyType = qualifyType.trim();
+                    String value = qualifyType;
+                    int pos1 = qualifyType.indexOf(' ');
+                    int pos2 = qualifyType.indexOf(".class");
+                    if (pos1 != -1 && pos2 != -1 && pos1 > pos2) {
+                        // a parameter can include type in the syntax to help with choosing correct method
+                        // therefore we need to check if type is provided in syntax (name.class value, name2.class value2, ...)
+                        value = qualifyType.substring(pos1);
+                        value = value.trim();
+                        qualifyType = qualifyType.substring(0, pos1);
+                        qualifyType = qualifyType.trim();
+                    }
 
                     if ("*".equals(qualifyType)) {
                         // * is a wildcard so we accept and match that parameter type
                         continue;
                     }
 
-                    if (BeanHelper.isValidParameterValue(getCamelContext().getClassResolver(), qualifyType)) {
-                        // its a parameter value, so continue to next parameter
-                        // as we should only check for FQN/type parameters
-                        continue;
-                    }
-
                     // if qualify type indeed is a class, then it must be assignable with the parameter type
                     Boolean assignable = BeanHelper.isAssignableToExpectedType(getCamelContext().getClassResolver(),
                             qualifyType, parameterType);
@@ -1127,6 +1132,13 @@ public class BeanInfo {
                         return false;
                     }
 
+                    if (!qualifyType.endsWith(".class")
+                            && !BeanHelper.isValidParameterValue(getCamelContext().getClassResolver(), value)) {
+                        // its a parameter value, so continue to next parameter
+                        // as we should only check for FQN/type parameters
+                        return false;
+                    }
+
                 } else {
                     // there method has more parameters than was specified in the method name qualifiers
                     return false;
@@ -1157,7 +1169,7 @@ public class BeanInfo {
     }
 
     /**
-     * Do we have a method with the given name.
+     * Do we have a method with the given name?
      * <p/>
      * Shorthand method names for getters is supported, so you can pass in eg 'name' and Camel will can find the real
      * 'getName' method instead.
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 5e1519d9b97..a58bb3afb76 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
@@ -2245,14 +2245,20 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type>
      * <a href="http://camel.apache.org/message-translator.html">Message Translator EIP:</a> Adds a bean which is
      * invoked which could be a final destination, or could be a transformation in a pipeline
      *
-     * @param  bean   the bean to invoke, or a reference to a bean if the type is a String
+     * @param  bean   the bean to invoke (if String then a reference to a bean, prefix with type: to specify FQN java
+     *                class)
      * @param  method the method name to invoke on the bean (can be used to avoid ambiguity)
      * @return        the builder
      */
     public Type bean(Object bean, String method) {
         BeanDefinition answer = new BeanDefinition();
         if (bean instanceof String) {
-            answer.setRef((String) bean);
+            String str = (String) bean;
+            if (str.startsWith("type:")) {
+                answer.setBeanType(str.substring(5));
+            } else {
+                answer.setRef(str);
+            }
         } else {
             answer.setBean(bean);
         }
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadedMethodTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadedMethodTest.java
index 1655eb68e9d..9753ef5751e 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadedMethodTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadedMethodTest.java
@@ -36,7 +36,7 @@ public class BeanOverloadedMethodTest extends ContextTestSupport {
     }
 
     @Test
-    public void testHelloOverloadedHeString() throws Exception {
+    public void testHelloOverloadedString() throws Exception {
         context.addRoutes(new RouteBuilder() {
             @Override
             public void configure() throws Exception {
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadsWithAssignableParamTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadsWithAssignableParamTest.java
index 8b6e11023b8..b572995abb8 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadsWithAssignableParamTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanOverloadsWithAssignableParamTest.java
@@ -36,7 +36,7 @@ public class BeanOverloadsWithAssignableParamTest extends ContextTestSupport {
         return new RouteBuilder() {
             @Override
             public void configure() throws Exception {
-                from("direct:stringParam").bean(new MyOtherFooBean(), "toString(String)").to("mock:stringParamResult");
+                from("direct:stringParam").bean(new MyOtherFooBean(), "toString(String.class)").to("mock:stringParamResult");
             }
         };
     }
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/bean/issues/BeanParameterTypeAndValueTest.java b/core/camel-core/src/test/java/org/apache/camel/component/bean/issues/BeanParameterTypeAndValueTest.java
new file mode 100644
index 00000000000..38673ad1048
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/component/bean/issues/BeanParameterTypeAndValueTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.bean.issues;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+public class BeanParameterTypeAndValueTest extends ContextTestSupport {
+
+    @Test
+    public void testBean() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("123");
+        getMockEndpoint("mock:result").message(0).body().isInstanceOf(Integer.class);
+
+        template.sendBody("direct:bean", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testBean2() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("44");
+        getMockEndpoint("mock:result").message(0).body().isInstanceOf(Integer.class);
+
+        template.sendBody("direct:bean2", "Hi World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testSimple() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("7");
+        getMockEndpoint("mock:result").message(0).body().isInstanceOf(Integer.class);
+
+        template.sendBody("direct:simple", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:bean")
+                        .bean(Math.class, "abs(int.class -123)")
+                        .to("mock:result");
+
+                from("direct:bean2")
+                        .bean("type:java.lang.Math", "abs(int.class -44)")
+                        .to("mock:result");
+
+                from("direct:simple")
+                        .setBody().simple("${bean:type:java.lang.Math?method=abs(int.class -7)}")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/docs/user-manual/modules/ROOT/pages/bean-binding.adoc b/docs/user-manual/modules/ROOT/pages/bean-binding.adoc
index 6236a3334e4..f5dce7d1489 100644
--- a/docs/user-manual/modules/ROOT/pages/bean-binding.adoc
+++ b/docs/user-manual/modules/ROOT/pages/bean-binding.adoc
@@ -369,11 +369,25 @@ the FQN, and *not* the simple name "MyOrder", then follow this example:
 .bean(OrderService.class, "doSomething(com.foo.MyOrder.class)")
 ----
 
-Camel currently only supports either specifying parameter binding or
+=== Declaring parameter type and value
+
+*Available as of Camel 4.0*
+
+Camel 3.x only supports either specifying parameter binding or
 type per parameter in the method name option. You *cannot* specify both
-at the same time, such as
+at the same time, such as:
+
+[source,text]
+----
+doSomething(com.foo.MyOrder.class ${body}, boolean ${header.high}, int 123)
+----
+
+However, we have implemented support for this in Camel 4,
+where you can declare both using _name.class value_ syntax as shown:
 
 [source,text]
 ----
-doSomething(com.foo.MyOrder.class ${body}, boolean ${header.high})
+doSomething(com.foo.MyOrder.class ${body}, boolean.class ${header.high}, int.class 123)
 ----
+
+Notice that you *MUST* use `name.class` when declaring the type, also for String, int, boolean etc.


[camel] 02/03: Guard against NPE

Posted by da...@apache.org.
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

commit d63f16d09dbc9207988f1214f7bf3f56e50b1ef3
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Apr 4 09:26:32 2023 +0200

    Guard against NPE
---
 .../src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java
index b6bee7885a4..13e82d97ce0 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoutesLoader.java
@@ -140,6 +140,8 @@ public class DefaultRoutesLoader extends ServiceSupport implements RoutesLoader,
 
     @Override
     public RoutesBuilderLoader getRoutesLoader(String extension) throws Exception {
+        ObjectHelper.notNull(extension, "extension");
+
         RoutesBuilderLoader answer = getCamelContext().getRegistry().lookupByNameAndType(
                 ROUTES_LOADER_KEY_PREFIX + extension,
                 RoutesBuilderLoader.class);