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 2019/08/20 19:05:23 UTC

[camel] 03/12: CAMEL-13870: Fast property configuration of Camel endpoints. Work in progress.

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

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

commit 8da3dbe2945d917ebbda19fe8324737784ade6a0
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Aug 20 11:02:24 2019 +0200

    CAMEL-13870: Fast property configuration of Camel endpoints. Work in progress.
---
 .../camel-log/src/main/docs/log-component.adoc     |  19 +-
 .../apache/camel/component/log/LogEndpoint.java    |  11 +-
 .../camel/component/log/LogEndpointConfigurer.java |  50 ---
 .../java/org/apache/camel/CamelContextAware.java   |   3 +-
 .../src/main/java/org/apache/camel/Component.java  |  11 +
 ...rAware.java => EndpointPropertyConfigurer.java} |  13 +-
 .../java/org/apache/camel/spi/FactoryFinder.java   |  10 +
 .../apache/camel/spi/PropertyConfigurerAware.java  |  11 +-
 .../camel/impl/engine/DefaultFactoryFinder.java    |  24 +-
 .../endpoint/dsl/LogEndpointBuilderFactory.java    | 420 ---------------------
 .../org/apache/camel/support/DefaultComponent.java |  42 ++-
 .../org/apache/camel/support/DefaultEndpoint.java  |  14 +-
 .../tools/apt/EndpointAnnotationProcessor.java     |   9 +
 .../apt/EndpointPropertyConfigurerGenerator.java   | 131 +++++++
 14 files changed, 248 insertions(+), 520 deletions(-)

diff --git a/components/camel-log/src/main/docs/log-component.adoc b/components/camel-log/src/main/docs/log-component.adoc
index 23a7668..1826e98 100644
--- a/components/camel-log/src/main/docs/log-component.adoc
+++ b/components/camel-log/src/main/docs/log-component.adoc
@@ -93,7 +93,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (27 parameters):
+=== Query Parameters (10 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -109,23 +109,6 @@ with the following path and query parameters:
 | *marker* (producer) | An optional Marker name to use. |  | String
 | *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
 | *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
-| *maxChars* (formatting) | Limits the number of characters logged per line. | 10000 | int
-| *multiline* (formatting) | If enabled then each information is outputted on a newline. | false | boolean
-| *showAll* (formatting) | Quick option for turning all options on. (multiline, maxChars has to be manually set if to be used) | false | boolean
-| *showBody* (formatting) | Show the message body. | true | boolean
-| *showBodyType* (formatting) | Show the body Java type. | true | boolean
-| *showCaughtException* (formatting) | f the exchange has a caught exception, show the exception message (no stack trace).A caught exception is stored as a property on the exchange (using the key org.apache.camel.Exchange#EXCEPTION_CAUGHT and for instance a doCatch can catch exceptions. | false | boolean
-| *showException* (formatting) | If the exchange has an exception, show the exception message (no stacktrace) | false | boolean
-| *showExchangeId* (formatting) | Show the unique exchange ID. | false | boolean
-| *showExchangePattern* (formatting) | Shows the Message Exchange Pattern (or MEP for short). | true | boolean
-| *showFiles* (formatting) | If enabled Camel will output files | false | boolean
-| *showFuture* (formatting) | If enabled Camel will on Future objects wait for it to complete to obtain the payload to be logged. | false | boolean
-| *showHeaders* (formatting) | Show the message headers. | false | boolean
-| *showProperties* (formatting) | Show the exchange properties. | false | boolean
-| *showStackTrace* (formatting) | Show the stack trace, if an exchange has an exception. Only effective if one of showAll, showException or showCaughtException are enabled. | false | boolean
-| *showStreams* (formatting) | Whether Camel should show stream bodies or not (eg such as java.io.InputStream). Beware if you enable this option then you may not be able later to access the message body as the stream have already been read by this logger. To remedy this you will have to use Stream Caching. | false | boolean
-| *skipBodyLineSeparator* (formatting) | Whether to skip line separators when logging the message body.This allows to log the message body in one line, setting this option to false will preserve any line separators from the body, which then will log the body as is. | true | boolean
-| *style* (formatting) | Sets the outputs style to use. | Default | OutputStyle
 |===
 // endpoint options: END
 
diff --git a/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java b/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java
index f7119d7..b2bb66b 100644
--- a/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java
+++ b/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpoint.java
@@ -25,7 +25,6 @@ import org.apache.camel.spi.CamelLogger;
 import org.apache.camel.spi.ExchangeFormatter;
 import org.apache.camel.spi.MaskingFormatter;
 import org.apache.camel.spi.Metadata;
-import org.apache.camel.spi.PropertyConfigurer;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
@@ -64,8 +63,9 @@ public class LogEndpoint extends ProcessorEndpoint {
     @UriParam
     private Long groupDelay;
     // we want to include the uri options of the DefaultExchangeFormatter
-    @UriParam(label = "advanced")
-    private DefaultExchangeFormatter exchangeFormatter;
+    // TODO: Make this correct instead of cheating
+    //@UriParam(label = "advanced")
+    //private DefaultExchangeFormatter exchangeFormatter;
     @UriParam
     private Boolean logMask;
 
@@ -82,11 +82,6 @@ public class LogEndpoint extends ProcessorEndpoint {
     }
 
     @Override
-    public PropertyConfigurer getPropertyConfigurer() {
-        return new LogEndpointConfigurer(this, getCamelContext());
-    }
-
-    @Override
     protected void doStart() throws Exception {
         if (logger == null) {
             logger = createLogger();
diff --git a/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpointConfigurer.java b/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpointConfigurer.java
deleted file mode 100644
index 206d10c..0000000
--- a/components/camel-log/src/main/java/org/apache/camel/component/log/LogEndpointConfigurer.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.log;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.spi.PropertyConfigurer;
-
-public class LogEndpointConfigurer implements PropertyConfigurer<Object> {
-
-    private final Map<String, Supplier<Object>> readPlaceholders = new HashMap<>();
-    private final Map<String, Consumer<Object>> writePlaceholders = new HashMap<>();
-
-    public LogEndpointConfigurer(final Object target, final CamelContext camelContext) {
-        final LogEndpoint endpoint = (LogEndpoint) target;
-
-        readPlaceholders.put("loggerName", endpoint::getLoggerName);
-        writePlaceholders.put("loggerName", o -> endpoint.setLoggerName(camelContext.getTypeConverter().convertTo(String.class, o)));
-        readPlaceholders.put("groupSize", endpoint::getGroupSize);
-        writePlaceholders.put("groupSize", o -> endpoint.setGroupSize(camelContext.getTypeConverter().convertTo(Integer.class, o)));
-    }
-
-    @Override
-    public Map<String, Supplier<Object>> getReadPropertyPlaceholderOptions(CamelContext camelContext) {
-        return readPlaceholders;
-    }
-
-    @Override
-    public Map<String, Consumer<Object>> getWritePropertyPlaceholderOptions(CamelContext camelContext) {
-        return writePlaceholders;
-    }
-}
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java b/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java
index 5f6c9c6..0fde100 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java
@@ -17,8 +17,7 @@
 package org.apache.camel;
 
 /**
- * An interface to represent an object which wishes to be injected with
- * a {@link CamelContext} such as when working with Spring or Guice
+ * An interface to represent an object which wishes to be injected with the {@link CamelContext}
  */
 public interface CamelContextAware {
 
diff --git a/core/camel-api/src/main/java/org/apache/camel/Component.java b/core/camel-api/src/main/java/org/apache/camel/Component.java
index 9909f3c..e1f512b 100644
--- a/core/camel-api/src/main/java/org/apache/camel/Component.java
+++ b/core/camel-api/src/main/java/org/apache/camel/Component.java
@@ -22,6 +22,7 @@ import java.util.Map;
 import java.util.Optional;
 
 import org.apache.camel.component.extension.ComponentExtension;
+import org.apache.camel.spi.PropertyConfigurer;
 
 /**
  * A <a href="http://camel.apache.org/component.html">component</a> is
@@ -72,6 +73,16 @@ public interface Component extends CamelContextAware, Service {
     boolean useRawUri();
 
     /**
+     * Gets the endpoint {@link PropertyConfigurer}.
+     *
+     * @param  endpoint  the endpoint
+     * @return the configurer, or <tt>null</tt> if the endpoint does not support using property configurer.
+     */
+    default PropertyConfigurer getEndpointPropertyConfigurer(Object endpoint) {
+        return null;
+    }
+
+    /**
      * Gets a list of supported extensions.
      *
      * @return the list of extensions.
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/PropertyConfigurerAware.java b/core/camel-api/src/main/java/org/apache/camel/spi/EndpointPropertyConfigurer.java
similarity index 75%
copy from core/camel-api/src/main/java/org/apache/camel/spi/PropertyConfigurerAware.java
copy to core/camel-api/src/main/java/org/apache/camel/spi/EndpointPropertyConfigurer.java
index 7223e41..f0b556b 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/PropertyConfigurerAware.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/EndpointPropertyConfigurer.java
@@ -1,13 +1,13 @@
-/*
+/**
  * 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
- *
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
  * 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.
@@ -16,8 +16,9 @@
  */
 package org.apache.camel.spi;
 
-public interface PropertyConfigurerAware {
+import org.apache.camel.CamelContext;
 
-    PropertyConfigurer getPropertyConfigurer();
+public interface EndpointPropertyConfigurer extends PropertyConfigurer<Object> {
 
+    void configure(Object endpoint, CamelContext camelContext);
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/FactoryFinder.java b/core/camel-api/src/main/java/org/apache/camel/spi/FactoryFinder.java
index a6ba2aa..ddd9948 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/FactoryFinder.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/FactoryFinder.java
@@ -73,4 +73,14 @@ public interface FactoryFinder {
      * @return the factory class
      */
     Optional<Class<?>> findClass(String key, String propertyPrefix, Class<?> clazz);
+
+    /**
+     * Finds the optional factory class using the key to lookup.
+     *
+     * @param key is the key to add to the path to find a text file containing the factory name
+     * @param propertyPrefix prefix on key
+     * @return the factory class if found, or <tt>null</tt> if no class existed
+     */
+    Optional<Class<?>> findOptionalClass(String key, String propertyPrefix);
+
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/PropertyConfigurerAware.java b/core/camel-api/src/main/java/org/apache/camel/spi/PropertyConfigurerAware.java
index 7223e41..bdd4efa 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/PropertyConfigurerAware.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/PropertyConfigurerAware.java
@@ -16,8 +16,17 @@
  */
 package org.apache.camel.spi;
 
+/**
+ * An interface to represent an object which is capable of configuring
+ * via {@link PropertyConfigurer}.
+ */
 public interface PropertyConfigurerAware {
 
-    PropertyConfigurer getPropertyConfigurer();
+    /**
+     * Gets the configurer.
+     *
+     * @param instance  the bean instance
+     */
+    PropertyConfigurer getPropertyConfigurer(Object instance);
 
 }
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultFactoryFinder.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultFactoryFinder.java
index ae97d77..800f463 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultFactoryFinder.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultFactoryFinder.java
@@ -74,7 +74,7 @@ public class DefaultFactoryFinder implements FactoryFinder {
         Class<?> clazz = addToClassMap(classKey, () -> {
             Properties prop = doFindFactoryProperties(key);
             if (prop != null) {
-                return doNewInstance(prop, prefix).orElse(null);
+                return doNewInstance(prop, prefix, true).orElse(null);
             } else {
                 return null;
             }
@@ -88,15 +88,33 @@ public class DefaultFactoryFinder implements FactoryFinder {
         return findClass(key, propertyPrefix);
     }
 
+    @Override
+    public Optional<Class<?>> findOptionalClass(String key, String propertyPrefix) {
+        final String prefix = propertyPrefix != null ? propertyPrefix : "";
+        final String classKey = prefix + key;
+
+        Class<?> clazz = addToClassMap(classKey, () -> {
+            Properties prop = doFindFactoryProperties(key);
+            if (prop != null) {
+                return doNewInstance(prop, prefix, false).orElse(null);
+            } else {
+                return null;
+            }
+        });
+        return Optional.ofNullable(clazz);
+    }
+
     private Object doNewInstance(String key, String propertyPrefix) {
         Optional<Class<?>> clazz = findClass(key, propertyPrefix);
         return clazz.map(ObjectHelper::newInstance).orElse(null);
     }
 
-    private Optional<Class<?>> doNewInstance(Properties properties, String propertyPrefix) throws IOException {
+    private Optional<Class<?>> doNewInstance(Properties properties, String propertyPrefix, boolean mandatory) throws IOException {
         String className = properties.getProperty(propertyPrefix + "class");
-        if (className == null) {
+        if (className == null && mandatory) {
             throw new IOException("Expected property is missing: " + propertyPrefix + "class");
+        } else if (className == null) {
+            return Optional.empty();
         }
 
         Class<?> clazz = classResolver.resolveClass(className);
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/LogEndpointBuilderFactory.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/LogEndpointBuilderFactory.java
index 9d85afa..7613db1 100644
--- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/LogEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/LogEndpointBuilderFactory.java
@@ -178,416 +178,6 @@ public interface LogEndpointBuilderFactory {
             setProperty("marker", marker);
             return this;
         }
-        /**
-         * Limits the number of characters logged per line.
-         * 
-         * The option is a: <code>int</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder maxChars(int maxChars) {
-            setProperty("maxChars", maxChars);
-            return this;
-        }
-        /**
-         * Limits the number of characters logged per line.
-         * 
-         * The option will be converted to a <code>int</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder maxChars(String maxChars) {
-            setProperty("maxChars", maxChars);
-            return this;
-        }
-        /**
-         * If enabled then each information is outputted on a newline.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder multiline(boolean multiline) {
-            setProperty("multiline", multiline);
-            return this;
-        }
-        /**
-         * If enabled then each information is outputted on a newline.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder multiline(String multiline) {
-            setProperty("multiline", multiline);
-            return this;
-        }
-        /**
-         * Quick option for turning all options on. (multiline, maxChars has to
-         * be manually set if to be used).
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showAll(boolean showAll) {
-            setProperty("showAll", showAll);
-            return this;
-        }
-        /**
-         * Quick option for turning all options on. (multiline, maxChars has to
-         * be manually set if to be used).
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showAll(String showAll) {
-            setProperty("showAll", showAll);
-            return this;
-        }
-        /**
-         * Show the message body.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showBody(boolean showBody) {
-            setProperty("showBody", showBody);
-            return this;
-        }
-        /**
-         * Show the message body.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showBody(String showBody) {
-            setProperty("showBody", showBody);
-            return this;
-        }
-        /**
-         * Show the body Java type.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showBodyType(boolean showBodyType) {
-            setProperty("showBodyType", showBodyType);
-            return this;
-        }
-        /**
-         * Show the body Java type.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showBodyType(String showBodyType) {
-            setProperty("showBodyType", showBodyType);
-            return this;
-        }
-        /**
-         * f the exchange has a caught exception, show the exception message (no
-         * stack trace).A caught exception is stored as a property on the
-         * exchange (using the key org.apache.camel.Exchange#EXCEPTION_CAUGHT
-         * and for instance a doCatch can catch exceptions.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showCaughtException(
-                boolean showCaughtException) {
-            setProperty("showCaughtException", showCaughtException);
-            return this;
-        }
-        /**
-         * f the exchange has a caught exception, show the exception message (no
-         * stack trace).A caught exception is stored as a property on the
-         * exchange (using the key org.apache.camel.Exchange#EXCEPTION_CAUGHT
-         * and for instance a doCatch can catch exceptions.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showCaughtException(
-                String showCaughtException) {
-            setProperty("showCaughtException", showCaughtException);
-            return this;
-        }
-        /**
-         * If the exchange has an exception, show the exception message (no
-         * stacktrace).
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showException(boolean showException) {
-            setProperty("showException", showException);
-            return this;
-        }
-        /**
-         * If the exchange has an exception, show the exception message (no
-         * stacktrace).
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showException(String showException) {
-            setProperty("showException", showException);
-            return this;
-        }
-        /**
-         * Show the unique exchange ID.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showExchangeId(boolean showExchangeId) {
-            setProperty("showExchangeId", showExchangeId);
-            return this;
-        }
-        /**
-         * Show the unique exchange ID.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showExchangeId(String showExchangeId) {
-            setProperty("showExchangeId", showExchangeId);
-            return this;
-        }
-        /**
-         * Shows the Message Exchange Pattern (or MEP for short).
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showExchangePattern(
-                boolean showExchangePattern) {
-            setProperty("showExchangePattern", showExchangePattern);
-            return this;
-        }
-        /**
-         * Shows the Message Exchange Pattern (or MEP for short).
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showExchangePattern(
-                String showExchangePattern) {
-            setProperty("showExchangePattern", showExchangePattern);
-            return this;
-        }
-        /**
-         * If enabled Camel will output files.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showFiles(boolean showFiles) {
-            setProperty("showFiles", showFiles);
-            return this;
-        }
-        /**
-         * If enabled Camel will output files.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showFiles(String showFiles) {
-            setProperty("showFiles", showFiles);
-            return this;
-        }
-        /**
-         * If enabled Camel will on Future objects wait for it to complete to
-         * obtain the payload to be logged.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showFuture(boolean showFuture) {
-            setProperty("showFuture", showFuture);
-            return this;
-        }
-        /**
-         * If enabled Camel will on Future objects wait for it to complete to
-         * obtain the payload to be logged.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showFuture(String showFuture) {
-            setProperty("showFuture", showFuture);
-            return this;
-        }
-        /**
-         * Show the message headers.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showHeaders(boolean showHeaders) {
-            setProperty("showHeaders", showHeaders);
-            return this;
-        }
-        /**
-         * Show the message headers.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showHeaders(String showHeaders) {
-            setProperty("showHeaders", showHeaders);
-            return this;
-        }
-        /**
-         * Show the exchange properties.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showProperties(boolean showProperties) {
-            setProperty("showProperties", showProperties);
-            return this;
-        }
-        /**
-         * Show the exchange properties.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showProperties(String showProperties) {
-            setProperty("showProperties", showProperties);
-            return this;
-        }
-        /**
-         * Show the stack trace, if an exchange has an exception. Only effective
-         * if one of showAll, showException or showCaughtException are enabled.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showStackTrace(boolean showStackTrace) {
-            setProperty("showStackTrace", showStackTrace);
-            return this;
-        }
-        /**
-         * Show the stack trace, if an exchange has an exception. Only effective
-         * if one of showAll, showException or showCaughtException are enabled.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showStackTrace(String showStackTrace) {
-            setProperty("showStackTrace", showStackTrace);
-            return this;
-        }
-        /**
-         * Whether Camel should show stream bodies or not (eg such as
-         * java.io.InputStream). Beware if you enable this option then you may
-         * not be able later to access the message body as the stream have
-         * already been read by this logger. To remedy this you will have to use
-         * Stream Caching.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showStreams(boolean showStreams) {
-            setProperty("showStreams", showStreams);
-            return this;
-        }
-        /**
-         * Whether Camel should show stream bodies or not (eg such as
-         * java.io.InputStream). Beware if you enable this option then you may
-         * not be able later to access the message body as the stream have
-         * already been read by this logger. To remedy this you will have to use
-         * Stream Caching.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder showStreams(String showStreams) {
-            setProperty("showStreams", showStreams);
-            return this;
-        }
-        /**
-         * Whether to skip line separators when logging the message body.This
-         * allows to log the message body in one line, setting this option to
-         * false will preserve any line separators from the body, which then
-         * will log the body as is.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder skipBodyLineSeparator(
-                boolean skipBodyLineSeparator) {
-            setProperty("skipBodyLineSeparator", skipBodyLineSeparator);
-            return this;
-        }
-        /**
-         * Whether to skip line separators when logging the message body.This
-         * allows to log the message body in one line, setting this option to
-         * false will preserve any line separators from the body, which then
-         * will log the body as is.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder skipBodyLineSeparator(
-                String skipBodyLineSeparator) {
-            setProperty("skipBodyLineSeparator", skipBodyLineSeparator);
-            return this;
-        }
-        /**
-         * Sets the outputs style to use.
-         * 
-         * The option is a:
-         * <code>org.apache.camel.support.processor.DefaultExchangeFormatter$OutputStyle</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder style(OutputStyle style) {
-            setProperty("style", style);
-            return this;
-        }
-        /**
-         * Sets the outputs style to use.
-         * 
-         * The option will be converted to a
-         * <code>org.apache.camel.support.processor.DefaultExchangeFormatter$OutputStyle</code> type.
-         * 
-         * Group: formatting
-         */
-        default LogEndpointBuilder style(String style) {
-            setProperty("style", style);
-            return this;
-        }
     }
 
     /**
@@ -650,16 +240,6 @@ public interface LogEndpointBuilderFactory {
             return this;
         }
     }
-
-    /**
-     * Proxy enum for
-     * <code>org.apache.camel.support.processor.DefaultExchangeFormatter$OutputStyle</code> enum.
-     */
-    enum OutputStyle {
-        Default,
-        Tab,
-        Fixed;
-    }
     /**
      * Log (camel-log)
      * The log component logs message exchanges to the underlying logging
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultComponent.java b/core/camel-support/src/main/java/org/apache/camel/support/DefaultComponent.java
index 591260d..eecb64c 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultComponent.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/DefaultComponent.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.support;
 
+import java.lang.annotation.Annotation;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -31,8 +32,12 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Component;
 import org.apache.camel.Endpoint;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.NoFactoryAvailableException;
 import org.apache.camel.ResolveEndpointFailedException;
 import org.apache.camel.component.extension.ComponentExtension;
+import org.apache.camel.spi.ComponentResolver;
+import org.apache.camel.spi.EndpointPropertyConfigurer;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.PropertyConfigurer;
 import org.apache.camel.spi.PropertyConfigurerAware;
@@ -52,6 +57,10 @@ public abstract class DefaultComponent extends ServiceSupport implements Compone
      */
     private static final Pattern RAW_PATTERN = Pattern.compile("RAW[({].*&&.*[)}]");
 
+    private static final String RESOURCE_PATH = "META-INF/services/org/apache/camel/component/";
+
+    private volatile Class endpointPropertyConfigurerClass;
+
     private final List<Supplier<ComponentExtension>> extensions = new ArrayList<>();
 
     private CamelContext camelContext;
@@ -320,6 +329,21 @@ public abstract class DefaultComponent extends ServiceSupport implements Compone
     }
 
     @Override
+    protected void doInit() throws Exception {
+        org.apache.camel.spi.annotations.Component ann = ObjectHelper.getAnnotation(this, org.apache.camel.spi.annotations.Component.class);
+        if (ann != null) {
+            String name = ann.value();
+            try {
+                Optional<Class<?>> clazz = getCamelContext().getExtension(ExtendedCamelContext.class).getFactoryFinder(RESOURCE_PATH)
+                        .findOptionalClass(name, "endpoint-property-configurer-");
+                clazz.ifPresent(aClass -> endpointPropertyConfigurerClass = aClass);
+            } catch (NoFactoryAvailableException e) {
+                // ignore
+            }
+        }
+    }
+
+    @Override
     protected void doStart() throws Exception {
         ObjectHelper.notNull(getCamelContext(), "camelContext");
     }
@@ -369,17 +393,29 @@ public abstract class DefaultComponent extends ServiceSupport implements Compone
                     .bind(camelContext, bean, parameters);
         } else {
             PropertyConfigurer configurer = null;
-            if (bean instanceof PropertyConfigurerAware) {
-                configurer = ((PropertyConfigurerAware) bean).getPropertyConfigurer();
+            if (bean instanceof Endpoint) {
+                configurer = getEndpointPropertyConfigurer(bean);
+            } else if (bean instanceof PropertyConfigurerAware) {
+                configurer = ((PropertyConfigurerAware) bean).getPropertyConfigurer(bean);
             }
             // use advanced binding
             PropertyBindingSupport.build().withConfigurer(configurer).bind(camelContext, bean, parameters);
         }
     }
 
+    @Override
+    public PropertyConfigurer getEndpointPropertyConfigurer(Object endpoint) {
+        EndpointPropertyConfigurer answer = null;
+        if (endpointPropertyConfigurerClass != null) {
+            answer = org.apache.camel.support.ObjectHelper.newInstance(endpointPropertyConfigurerClass, EndpointPropertyConfigurer.class);
+            answer.configure(endpoint, getCamelContext());
+        }
+        return answer;
+    }
+
     /**
      * Derived classes may wish to overload this to prevent the default introspection of URI parameters
-     * on the created Endpoint instance
+     * on the created {@link Endpoint} instance.
      */
     protected boolean useIntrospectionOnEndpoint() {
         return true;
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultEndpoint.java b/core/camel-support/src/main/java/org/apache/camel/support/DefaultEndpoint.java
index d4d502f..de7dd80 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultEndpoint.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/DefaultEndpoint.java
@@ -28,7 +28,6 @@ import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
 import org.apache.camel.PollingConsumer;
-import org.apache.camel.Producer;
 import org.apache.camel.ResolveEndpointFailedException;
 import org.apache.camel.spi.ExceptionHandler;
 import org.apache.camel.spi.HasId;
@@ -51,7 +50,7 @@ import org.apache.camel.util.URISupport;
  * model or not. The option is default <tt>false</tt> which means asynchronous
  * processing is allowed.
  */
-public abstract class DefaultEndpoint extends ServiceSupport implements Endpoint, HasId, CamelContextAware, PropertyConfigurerAware {
+public abstract class DefaultEndpoint extends ServiceSupport implements Endpoint, HasId, CamelContextAware {
 
     private final String id = EndpointHelper.createEndpointId();
     private transient String endpointUriToString;
@@ -418,19 +417,16 @@ public abstract class DefaultEndpoint extends ServiceSupport implements Endpoint
                     .bind(camelContext, bean, parameters);
         } else {
             PropertyConfigurer configurer = null;
-            if (bean instanceof PropertyConfigurerAware) {
-                configurer = ((PropertyConfigurerAware) bean).getPropertyConfigurer();
+            if (bean instanceof Endpoint) {
+                configurer = getComponent().getEndpointPropertyConfigurer(bean);
+            } else if (bean instanceof PropertyConfigurerAware) {
+                configurer = ((PropertyConfigurerAware) bean).getPropertyConfigurer(bean);
             }
             // use advanced binding
             PropertyBindingSupport.build().withConfigurer(configurer).bind(camelContext, bean, parameters);
         }
     }
 
-    @Override
-    public PropertyConfigurer getPropertyConfigurer() {
-        return null;
-    }
-
     /**
      * A factory method to lazily create the endpointUri if none is specified
      */
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
index 262cbef..e8d2f01 100644
--- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java
@@ -172,6 +172,15 @@ public class EndpointAnnotationProcessor extends AbstractCamelAnnotationProcesso
 
         String json = createParameterJsonSchema(componentModel, componentOptions, endpointPaths, endpointOptions, schemes, parentData);
         writer.println(json);
+
+        TypeElement parent = findTypeElement(processingEnv, roundEnv, "org.apache.camel.spi.EndpointPropertyConfigurer");
+        String fqen = classElement.getQualifiedName().toString();
+        String pn = fqen.substring(0, fqen.lastIndexOf('.'));
+        String en = classElement.getSimpleName().toString();
+        String cn = en + "Configurer";
+        String fqn = pn + "." + cn;
+
+        EndpointPropertyConfigurerGenerator.generatePropertyConfigurer(processingEnv, parent, pn, cn, fqn, en, fqen, endpointPaths, endpointOptions);
     }
 
     public String createParameterJsonSchema(ComponentModel componentModel, Set<ComponentOption> componentOptions,
diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointPropertyConfigurerGenerator.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointPropertyConfigurerGenerator.java
new file mode 100644
index 0000000..fb3001a
--- /dev/null
+++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointPropertyConfigurerGenerator.java
@@ -0,0 +1,131 @@
+/*
+ * 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.tools.apt;
+
+import java.io.Writer;
+import java.util.Set;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+
+import org.apache.camel.tools.apt.helper.IOHelper;
+import org.apache.camel.tools.apt.model.EndpointOption;
+import org.apache.camel.tools.apt.model.EndpointPath;
+
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.dumpExceptionToErrorFile;
+
+public final class EndpointPropertyConfigurerGenerator {
+
+    private EndpointPropertyConfigurerGenerator() {
+    }
+
+    public static void generatePropertyConfigurer(ProcessingEnvironment processingEnv, TypeElement parent,
+                                                  String pn, String cn, String fqn, String en, String fqen,
+                                                  Set<EndpointPath> paths, Set<EndpointOption> options) {
+
+        Writer w = null;
+        try {
+            JavaFileObject src = processingEnv.getFiler().createSourceFile(fqn, parent);
+            w = src.openWriter();
+
+            int size = paths.size() + options.size();
+
+            w.write("/* Generated by org.apache.camel:apt */\n");
+            w.write("package " + pn + ";\n");
+            w.write("\n");
+            w.write("import java.util.HashMap;\n");
+            w.write("import java.util.Map;\n");
+            w.write("import java.util.function.Consumer;\n");
+            w.write("import java.util.function.Supplier;\n");
+            w.write("\n");
+            w.write("import org.apache.camel.CamelContext;\n");
+            w.write("import " + fqen + ";\n");
+            w.write("import org.apache.camel.spi.EndpointPropertyConfigurer;\n");
+            w.write("\n");
+            w.write("/**\n");
+            w.write(" * Source code generated by org.apache.camel:apt\n");
+            w.write(" */\n");
+            w.write("public class " + cn + " implements EndpointPropertyConfigurer {\n");
+            w.write("\n");
+            w.write("    private final Map<String, Supplier<Object>> readPlaceholders = new HashMap<>(" + size + ");\n");
+            w.write("    private final Map<String, Consumer<Object>> writePlaceholders = new HashMap<>(" + size + ");\n");
+            w.write("\n");
+
+            // add constructor
+            w.write("    public void configure(Object object, CamelContext camelContext) {\n");
+            w.write("        " + en + " endpoint = (" + en + ") object;\n");
+            w.write("\n");
+
+            // only include string types as they are the only ones we can use for property placeholders
+            for (EndpointPath option : paths) {
+                String getOrSet = option.getName();
+                getOrSet = Character.toUpperCase(getOrSet.charAt(0)) + getOrSet.substring(1);
+                String getterLambda = getterLambda(getOrSet, option.getName(), option.getType());
+                String setterLambda = setterLambda(getOrSet, option.getName(), option.getType());
+                w.write("        readPlaceholders.put(\"" + option.getName() + "\", " + getterLambda + ");\n");
+                w.write("        writePlaceholders.put(\"" + option.getName() + "\", " + setterLambda + ");\n");
+            }
+            for (EndpointOption option : options) {
+                String getOrSet = option.getName();
+                getOrSet = Character.toUpperCase(getOrSet.charAt(0)) + getOrSet.substring(1);
+                String getterLambda = getterLambda(getOrSet, option.getName(), option.getType());
+                String setterLambda = setterLambda(getOrSet, option.getName(), option.getType());
+                w.write("        readPlaceholders.put(\"" + option.getName() + "\", " + getterLambda + ");\n");
+                w.write("        writePlaceholders.put(\"" + option.getName() + "\", " + setterLambda + ");\n");
+            }
+
+            w.write("    }\n");
+            w.write("\n");
+            w.write("    @Override\n");
+            w.write("    public Map<String, Supplier<Object>> getReadPropertyPlaceholderOptions(CamelContext camelContext) {\n");
+            w.write("        return readPlaceholders;\n");
+            w.write("    }\n");
+            w.write("\n");
+            w.write("    @Override\n");
+            w.write("    public Map<String, Consumer<Object>> getWritePropertyPlaceholderOptions(CamelContext camelContext) {\n");
+            w.write("        return writePlaceholders;\n");
+            w.write("    }\n");
+            w.write("\n");
+            w.write("}\n");
+            w.write("\n");
+        } catch (Exception e) {
+            processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to generate source code file: " + fqn + ": " + e.getMessage());
+            dumpExceptionToErrorFile("camel-apt-error.log", "Unable to generate source code file: " + fqn, e);
+        } finally {
+            IOHelper.close(w);
+        }
+    }
+
+    private static String getterLambda(String getOrSet, String name, String type) {
+        String getPrefix = "boolean".equals(type) ? "is" : "get";
+        return "endpoint::" + getPrefix + getOrSet;
+    }
+
+    private static String setterLambda(String getOrSet, String name, String type) {
+        // type may contain generics so remove those
+        if (type.indexOf('<') != -1) {
+            type = type.substring(0, type.indexOf('<'));
+        }
+
+        //  writePlaceholders.put("groupSize", o -> endpoint.setGroupSize(camelContext.getTypeConverter().convertTo(Integer.class, o)));
+        StringBuilder sb = new StringBuilder();
+        sb.append("o -> endpoint.set").append(getOrSet).append("(camelContext.getTypeConverter().convertTo(").append(type).append(".class, o))");
+        return sb.toString();
+    }
+
+}