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/11/30 09:21:57 UTC

(camel) 01/04: CAMEL-20130: camel-core - PropertyBuilderSupport add support for fluent builder classes.

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

davsclaus pushed a commit to branch builder-class
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c65bdb48409e7ee05d7523a53c604267db7386fc
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Nov 30 09:32:43 2023 +0100

    CAMEL-20130: camel-core - PropertyBuilderSupport add support for fluent builder classes.
---
 .../PropertyBindingSupportBuildMethodTest.java     | 104 +++++++++++++++++++++
 .../camel/support/PropertyBindingSupport.java      |  31 ++++++
 .../modules/ROOT/pages/property-binding.adoc       |  51 ++++++++++
 3 files changed, 186 insertions(+)

diff --git a/core/camel-main/src/test/java/org/apache/camel/main/PropertyBindingSupportBuildMethodTest.java b/core/camel-main/src/test/java/org/apache/camel/main/PropertyBindingSupportBuildMethodTest.java
new file mode 100644
index 00000000000..507b686f704
--- /dev/null
+++ b/core/camel-main/src/test/java/org/apache/camel/main/PropertyBindingSupportBuildMethodTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.main;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.support.PropertyBindingSupport;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit test for PropertyBindingSupport
+ */
+public class PropertyBindingSupportBuildMethodTest {
+
+    @Test
+    public void testBuildClass() throws Exception {
+        CamelContext context = new DefaultCamelContext();
+
+        context.start();
+
+        MyDriver driver = PropertyBindingSupport.build()
+                .withCamelContext(context)
+                .withTarget(new MyDriverBuilder())
+                .withFluentBuilder(true)
+                .withProperty("url", "localhost:1234")
+                .withProperty("username", "scott")
+                .withProperty("password", "tiger")
+                .build(MyDriver.class);
+
+        Assertions.assertNotNull(driver);
+        Assertions.assertEquals("localhost:1234", driver.getUrl());
+        Assertions.assertEquals("scott", driver.getUsername());
+        Assertions.assertEquals("tiger", driver.getPassword());
+
+        context.stop();
+    }
+
+    public static class MyDriver {
+
+        private final String url;
+        private final String username;
+        private final String password;
+
+        public MyDriver(String url, String username, String password) {
+            this.url = url;
+            this.username = username;
+            this.password = password;
+        }
+
+        public String getUrl() {
+            return url;
+        }
+
+        public String getUsername() {
+            return username;
+        }
+
+        public String getPassword() {
+            return password;
+        }
+    }
+
+    public static class MyDriverBuilder {
+
+        private String url;
+        private String username;
+        private String password;
+
+        public MyDriverBuilder url(String url) {
+            this.url = url;
+            return this;
+        }
+
+        public MyDriverBuilder username(String username) {
+            this.username = username;
+            return this;
+        }
+
+        public MyDriverBuilder password(String password) {
+            this.password = password;
+            return this;
+        }
+
+        public MyDriver build() {
+            return new MyDriver(url, username, password);
+        }
+    }
+
+}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java b/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java
index 7d766645ee1..5f6bcaae369 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java
@@ -38,6 +38,7 @@ import java.util.stream.Collectors;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Component;
 import org.apache.camel.PropertyBindingException;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.BeanIntrospection;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.PropertyConfigurer;
@@ -1874,6 +1875,36 @@ public final class PropertyBindingSupport {
             return this;
         }
 
+        /**
+         * Binds the properties to the target object, and builds the output as the given type, by invoking the build
+         * method (uses build as name)
+         *
+         * @param type the type of the output class
+         */
+        public <T> T build(Class<T> type) {
+            return build(type, "build");
+        }
+
+        /**
+         * Binds the properties to the target object, and builds the output as the given type, by invoking the build
+         * method (via reflection).
+         *
+         * @param type         the type of the output class
+         * @param buildMethod  the name of the builder method to invoke
+         */
+        public <T> T build(Class<T> type, String buildMethod) {
+            // first bind
+            bind();
+
+            // then invoke the build method on target via reflection
+            try {
+                Object out = ObjectHelper.invokeMethodSafe(buildMethod, target);
+                return camelContext.getTypeConverter().convertTo(type, out);
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
+            }
+        }
+
         /**
          * Binds the properties to the target object, and removes the property that was bound from properties.
          *
diff --git a/docs/user-manual/modules/ROOT/pages/property-binding.adoc b/docs/user-manual/modules/ROOT/pages/property-binding.adoc
index 8687eee222c..31d578cebd6 100644
--- a/docs/user-manual/modules/ROOT/pages/property-binding.adoc
+++ b/docs/user-manual/modules/ROOT/pages/property-binding.adoc
@@ -193,6 +193,57 @@ PropertyBindingSupport.build().withCamelContext(context).withTarget(foo)
     .bind();
 ----
 
+=== Using fluent builder class
+
+When you are in need to configure a bean via _fluent builder class_, such as the following example:
+
+[source,java]
+----
+public class MyDriverBuilder {
+
+ private String url;
+ private String username;
+ private String password;
+
+ public MyDriverBuilder url(String url) {
+     this.url = url;
+     return this;
+ }
+
+ public MyDriverBuilder username(String username) {
+     this.username = username;
+     return this;
+ }
+
+ public MyDriverBuilder password(String password) {
+     this.password = password;
+     return this;
+ }
+
+ public MyDriver build() {
+     return new MyDriver(url, username, password);
+ }
+}
+----
+
+And you want to create an instance of `MyDriver` via the `MyDriverBuilder` class, then this can be done as follows:
+
+[source,java]
+----
+MyDriver driver = PropertyBindingSupport.build()
+  .withCamelContext(context)
+  .withTarget(new MyDriverBuilder())
+  .withFluentBuilder(true)
+  .withProperty("url", "localhost:1234")
+  .withProperty("username", "scott")
+  .withProperty("password", "tiger")
+  .build(MyDriver.class);
+----
+
+Notice how we use the `build(MyDriver.class)` to build the bean via the target class `.withTarget(new MyDriverBuilder())`.
+The build method will by default invoke `build` as the builder method, but you can specify the name, such as `.build(MyDriver.class, "myBuilderMethod");`
+
+
 == More details
 
 Property binding is notably used when running Camel in standalone mode with Camel Main, or using Camel Spring Boot, Camel K,