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

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

commit 6d455b136be879908105330eecdbf6ff836726a7
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Tue Apr 2 12:28:31 2024 +0200

    CAMEL-20557: Rest DSL to use openapi spec directly
---
 ...mHttpRestOpenApiConsumerRestDslBindingTest.java |   4 +-
 .../DefaultRestOpenapiProcessorStrategy.java       |  30 +-
 .../rest/openapi/RestOpenApiConsumerPath.java      |  18 +-
 .../rest/openapi/RestOpenApiProcessor.java         | 120 ++++-
 .../rest/openapi/RestOpenapiProcessorStrategy.java |  23 +-
 .../apache/camel/processor/RestBindingAdvice.java  | 555 +--------------------
 .../camel/reifier/rest/RestBindingReifier.java     |   9 +-
 .../processor/RestBindingConfiguration.java        | 171 +++++++
 .../support/processor/RestBindingFactory.java}     | 115 ++---
 .../support/processor/RestBindingSupport.java}     |  46 +-
 10 files changed, 403 insertions(+), 688 deletions(-)

diff --git 
a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslBindingTest.java
 
b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslBindingTest.java
index 45fd9cbac50..ab62516d8c6 100644
--- 
a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslBindingTest.java
+++ 
b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslBindingTest.java
@@ -41,10 +41,12 @@ public class 
PlatformHttpRestOpenApiConsumerRestDslBindingTest {
 
                     from("direct:getPetById")
                             .process(e -> {
+                                // build response body as POJO
                                 Pet pet = new Pet();
                                 pet.setId(e.getMessage().getHeader("petId", 
long.class));
                                 pet.setName("tony the tiger");
                                 pet.setStatus(Pet.Status.AVAILABLE);
+                                e.getMessage().setBody(pet);
                             });
                 }
             });
@@ -56,7 +58,7 @@ public class 
PlatformHttpRestOpenApiConsumerRestDslBindingTest {
                     .get("/api/v3/pet/123")
                     .then()
                     .statusCode(200)
-                    .body(equalTo("{\"pet\": \"tony the tiger\"}"));
+                    .body(equalTo("{\"id\":123,\"name\":\"tony the 
tiger\",\"status\":\"AVAILABLE\"}"));
 
         } finally {
             context.stop();
diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
index f1d47dbc6c8..b6860956d7f 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
@@ -20,6 +20,7 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 import io.swagger.v3.oas.models.OpenAPI;
@@ -32,7 +33,6 @@ import org.apache.camel.CamelContextAware;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.NonManagedService;
-import org.apache.camel.Processor;
 import org.apache.camel.Route;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.platform.http.PlatformHttpComponent;
@@ -42,6 +42,7 @@ import org.apache.camel.spi.Resource;
 import org.apache.camel.support.ExchangeHelper;
 import org.apache.camel.support.PluginHelper;
 import org.apache.camel.support.cache.DefaultProducerCache;
+import org.apache.camel.support.processor.RestBindingSupport;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.FileUtil;
@@ -164,36 +165,35 @@ public class DefaultRestOpenapiProcessorStrategy extends 
ServiceSupport
     @Override
     public boolean process(
             Operation operation, String path,
-            Processor beforeBinding, Processor afterBinding,
+            RestBindingSupport binding,
             Exchange exchange, AsyncCallback callback) {
+
         if ("mock".equalsIgnoreCase(missingOperation)) {
             // check if there is a route
             Endpoint e = camelContext.hasEndpoint(component + ":" + 
operation.getOperationId());
             if (e == null) {
+                // no route then try to load mock data as the answer
                 loadMockData(operation, path, exchange);
                 callback.done(true);
                 return true;
             }
         }
 
-        if (beforeBinding != null) {
-            try {
-                beforeBinding.process(exchange);
-            } catch (Exception e) {
-                exchange.setException(e);
-                callback.done(true);
-                return true;
-            }
+        Map<String, Object> state;
+        try {
+            state = binding.before(exchange);
+        } catch (Exception e) {
+            exchange.setException(e);
+            callback.done(true);
+            return true;
         }
 
-        Endpoint e = camelContext.getEndpoint(component + ":" + 
operation.getOperationId());
-        AsyncProducer p = producerCache.acquireProducer(e);
+        final Endpoint e = camelContext.getEndpoint(component + ":" + 
operation.getOperationId());
+        final AsyncProducer p = producerCache.acquireProducer(e);
         return p.process(exchange, doneSync -> {
             try {
                 producerCache.releaseProducer(e, p);
-                if (afterBinding != null) {
-                    afterBinding.process(exchange);
-                }
+                binding.after(exchange, state);
             } catch (Exception ex) {
                 exchange.setException(ex);
             } finally {
diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiConsumerPath.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiConsumerPath.java
index f4123ec2f18..6938a42c00b 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiConsumerPath.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiConsumerPath.java
@@ -17,24 +17,22 @@
 package org.apache.camel.component.rest.openapi;
 
 import io.swagger.v3.oas.models.Operation;
-import org.apache.camel.Processor;
 import org.apache.camel.support.RestConsumerContextPathMatcher;
+import org.apache.camel.support.processor.RestBindingSupport;
 
 class RestOpenApiConsumerPath implements 
RestConsumerContextPathMatcher.ConsumerPath<Operation> {
 
     private final String verb;
     private final String path;
     private final Operation consumer;
-    private final Processor bindingBefore;
-    private final Processor bindingAfter;
+    private final RestBindingSupport binding;
 
     public RestOpenApiConsumerPath(String verb, String path, Operation 
consumer,
-                                   Processor bindingBefore, Processor 
bindingAfter) {
+                                   RestBindingSupport binding) {
         this.verb = verb;
         this.path = path;
         this.consumer = consumer;
-        this.bindingBefore = bindingBefore;
-        this.bindingAfter = bindingAfter;
+        this.binding = binding;
     }
 
     @Override
@@ -57,11 +55,7 @@ class RestOpenApiConsumerPath implements 
RestConsumerContextPathMatcher.Consumer
         return false;
     }
 
-    public Processor getBindingBefore() {
-        return bindingBefore;
-    }
-
-    public Processor getBindingAfter() {
-        return bindingAfter;
+    public RestBindingSupport getBinding() {
+        return binding;
     }
 }
diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java
index a79a1d66f89..e47063cc94b 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java
@@ -21,6 +21,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -41,6 +42,9 @@ import org.apache.camel.support.ExchangeHelper;
 import org.apache.camel.support.MessageHelper;
 import org.apache.camel.support.RestConsumerContextPathMatcher;
 import org.apache.camel.support.processor.DelegateAsyncProcessor;
+import org.apache.camel.support.processor.RestBindingConfiguration;
+import org.apache.camel.support.processor.RestBindingFactory;
+import org.apache.camel.support.processor.RestBindingSupport;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
@@ -94,23 +98,15 @@ public class RestOpenApiProcessor extends 
DelegateAsyncProcessor implements Came
 
         RestConsumerContextPathMatcher.ConsumerPath<Operation> m
                 = RestConsumerContextPathMatcher.matchBestPath(verb, path, 
paths);
-        if (m != null) {
-            Operation o = m.getConsumer();
-
-            // before and after processors for binding
-            Processor before = null;
-            Processor after = null;
-            if (m instanceof RestOpenApiConsumerPath mp) {
-                before = mp.getBindingBefore();
-                after = mp.getBindingAfter();
-            }
+        if (m instanceof RestOpenApiConsumerPath rcp) {
+            Operation o = rcp.getConsumer();
 
             // binding mode
             RestConfiguration config = camelContext.getRestConfiguration();
             RestConfiguration.RestBindingMode bindingMode = 
config.getBindingMode();
 
             // map path-parameters from operation to camel headers
-            HttpHelper.evalPlaceholders(exchange.getMessage().getHeaders(), 
path, m.getConsumerPath());
+            HttpHelper.evalPlaceholders(exchange.getMessage().getHeaders(), 
path, rcp.getConsumerPath());
 
             // we have found the op to call, but if validation is enabled then 
we need
             // to validate the incoming request first
@@ -120,7 +116,7 @@ public class RestOpenApiProcessor extends 
DelegateAsyncProcessor implements Came
             }
 
             // process the incoming request
-            return restOpenapiProcessorStrategy.process(o, path, before, 
after, exchange, callback);
+            return restOpenapiProcessorStrategy.process(o, path, 
rcp.getBinding(), exchange, callback);
         }
 
         // is it the api-context path
@@ -325,19 +321,101 @@ public class RestOpenApiProcessor extends 
DelegateAsyncProcessor implements Came
         super.doBuild();
 
         CamelContextAware.trySetCamelContext(restOpenapiProcessorStrategy, 
getCamelContext());
+
         // register all openapi paths
         for (var e : openAPI.getPaths().entrySet()) {
             String path = e.getKey(); // path
             for (var o : e.getValue().readOperationsMap().entrySet()) {
                 String v = o.getKey().name(); // verb
-                RestOpenApiBindingBefore before = new 
RestOpenApiBindingBefore();
-                RestOpenApiBindingAfter after = new RestOpenApiBindingAfter();
-                paths.add(new RestOpenApiConsumerPath(v, path, o.getValue(), 
before, after));
+                // create per operation binding
+                RestBindingSupport binding = createRestBinding(o.getValue());
+                ServiceHelper.buildService(binding);
+                paths.add(new RestOpenApiConsumerPath(v, path, o.getValue(), 
binding));
             }
         }
         ServiceHelper.buildService(restOpenapiProcessorStrategy);
     }
 
+    private RestBindingSupport createRestBinding(Operation o) throws Exception 
{
+        RestConfiguration config = camelContext.getRestConfiguration();
+        RestConfiguration.RestBindingMode mode = config.getBindingMode();
+
+        RestBindingConfiguration bc = new RestBindingConfiguration();
+        bc.setBindingMode(mode.name());
+        bc.setEnableCORS(config.isEnableCORS());
+        bc.setCorsHeaders(config.getCorsHeaders());
+        bc.setClientRequestValidation(config.isClientRequestValidation());
+        bc.setEnableNoContentResponse(config.isEnableNoContentResponse());
+        bc.setSkipBindingOnErrorCode(config.isSkipBindingOnErrorCode());
+
+        String consumes = endpoint.getConsumes();
+        String produces = endpoint.getProduces();
+        // the operation may have specific information what it can consume
+        if (o.getRequestBody() != null) {
+            Content c = o.getRequestBody().getContent();
+            if (c != null) {
+                consumes = 
c.keySet().stream().sorted().collect(Collectors.joining(","));
+            }
+        }
+        // the operation may have specific information what it can produce
+        if (o.getResponses() != null) {
+            for (var a : o.getResponses().values()) {
+                Content c = a.getContent();
+                if (c != null) {
+                    produces = 
c.keySet().stream().sorted().collect(Collectors.joining(","));
+                }
+            }
+        }
+        bc.setConsumes(consumes);
+        bc.setProduces(produces);
+
+        boolean requiredBody = false;
+        if (o.getRequestBody() != null) {
+            requiredBody = Boolean.TRUE == o.getRequestBody().getRequired();
+        }
+        bc.setRequiredBody(requiredBody);
+
+        Set<String> requiredQueryParameters = null;
+        if (o.getParameters() != null) {
+            requiredQueryParameters = o.getParameters().stream()
+                    .filter(p -> "query".equals(p.getIn()))
+                    .filter(p -> Boolean.TRUE == p.getRequired())
+                    .map(Parameter::getName)
+                    .collect(Collectors.toSet());
+        }
+        if (requiredQueryParameters != null) {
+            bc.setRequiredQueryParameters(requiredQueryParameters);
+        }
+
+        Set<String> requiredHeaders = null;
+        if (o.getParameters() != null) {
+            requiredHeaders = o.getParameters().stream()
+                    .filter(p -> "header".equals(p.getIn()))
+                    .filter(p -> Boolean.TRUE == p.getRequired())
+                    .map(Parameter::getName)
+                    .collect(Collectors.toSet());
+        }
+        if (requiredHeaders != null) {
+            bc.setRequiredHeaders(requiredHeaders);
+        }
+        // TODO: should type be string/int/long for basic types?
+        Map<String, String> defaultQueryValues = null;
+        if (o.getParameters() != null) {
+            defaultQueryValues = o.getParameters().stream()
+                    .filter(p -> "query".equals(p.getIn()))
+                    .filter(p -> p.getSchema() != null)
+                    .filter(p -> p.getSchema().getDefault() != null)
+                    .collect(Collectors.toMap(Parameter::getName, p -> 
p.getSchema().getDefault().toString()));
+        }
+        if (defaultQueryValues != null) {
+            bc.setQueryDefaultValues(defaultQueryValues);
+        }
+
+        // TODO: type/outType
+
+        return RestBindingFactory.build(camelContext, bc);
+    }
+
     @Override
     protected void doInit() throws Exception {
         super.doInit();
@@ -354,12 +432,22 @@ public class RestOpenApiProcessor extends 
DelegateAsyncProcessor implements Came
     protected void doStart() throws Exception {
         super.doStart();
         ServiceHelper.startService(restOpenapiProcessorStrategy);
+        for (var p : paths) {
+            if (p instanceof RestOpenApiConsumerPath rcp) {
+                ServiceHelper.startService(rcp.getBinding());
+            }
+        }
     }
 
     @Override
     protected void doStop() throws Exception {
         super.doStop();
-        paths.clear();
         ServiceHelper.stopService(restOpenapiProcessorStrategy);
+        for (var p : paths) {
+            if (p instanceof RestOpenApiConsumerPath rcp) {
+                ServiceHelper.stopService(rcp.getBinding());
+            }
+        }
+        paths.clear();
     }
 }
diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java
index 8b4c516d310..4a22f91635f 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java
@@ -20,7 +20,7 @@ import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.Operation;
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
+import org.apache.camel.support.processor.RestBindingSupport;
 
 /**
  * Strategy for processing the Rest DSL that services an OpenAPI spec.
@@ -64,20 +64,19 @@ public interface RestOpenapiProcessorStrategy {
     /**
      * Strategy for processing the Rest DSL operation
      *
-     * @param  operation     the rest operation
-     * @param  path          the context-path
-     * @param  bindingBefore optional binding to execute before processing the 
Rest DSL operation
-     * @param  bindingAfter  optional binding to execute after processing the 
Rest DSL operation
-     * @param  exchange      the exchange
-     * @param  callback      the AsyncCallback will be invoked when the 
processing of the exchange is completed. If the
-     *                       exchange is completed synchronously, then the 
callback is also invoked synchronously. The
-     *                       callback should therefore be careful of starting 
recursive loop.
-     * @return               (doneSync) true to continue execute 
synchronously, false to continue being executed
-     *                       asynchronously
+     * @param  operation the rest operation
+     * @param  path      the context-path
+     * @param  binding   binding advice
+     * @param  exchange  the exchange
+     * @param  callback  the AsyncCallback will be invoked when the processing 
of the exchange is completed. If the
+     *                   exchange is completed synchronously, then the 
callback is also invoked synchronously. The
+     *                   callback should therefore be careful of starting 
recursive loop.
+     * @return           (doneSync) true to continue execute synchronously, 
false to continue being executed
+     *                   asynchronously
      */
     boolean process(
             Operation operation, String path,
-            Processor bindingBefore, Processor bindingAfter,
+            RestBindingSupport binding,
             Exchange exchange, AsyncCallback callback);
 
     /**
diff --git 
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
 
b/core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
index 0efcf7c0dae..0bb4a6d7406 100644
--- 
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
+++ 
b/core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
@@ -16,30 +16,13 @@
  */
 package org.apache.camel.processor;
 
-import java.util.HashMap;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.camel.AsyncProcessor;
 import org.apache.camel.CamelContext;
-import org.apache.camel.CamelExchangeException;
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
 import org.apache.camel.spi.CamelInternalProcessorAdvice;
 import org.apache.camel.spi.DataFormat;
-import org.apache.camel.spi.DataType;
-import org.apache.camel.spi.DataTypeAware;
-import org.apache.camel.spi.RestConfiguration;
-import org.apache.camel.support.ExchangeHelper;
-import org.apache.camel.support.MessageHelper;
-import org.apache.camel.support.processor.MarshalProcessor;
-import org.apache.camel.support.processor.UnmarshalProcessor;
-import org.apache.camel.util.ObjectHelper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static 
org.apache.camel.support.http.RestUtil.isValidOrAcceptedContentType;
+import org.apache.camel.support.processor.RestBindingSupport;
 
 /**
  * A {@link CamelInternalProcessorAdvice} that binds the REST DSL incoming and 
outgoing messages from sources of json or
@@ -50,539 +33,23 @@ import static 
org.apache.camel.support.http.RestUtil.isValidOrAcceptedContentTyp
  * <p/>
  * The rest producer side is implemented in {@link 
org.apache.camel.component.rest.RestProducerBindingProcessor}
  */
-public class RestBindingAdvice implements 
CamelInternalProcessorAdvice<Map<String, Object>> {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(RestBindingAdvice.class);
-    private static final String STATE_KEY_DO_MARSHAL = "doMarshal";
-    private static final String STATE_KEY_ACCEPT = "accept";
-    private static final String STATE_JSON = "json";
-    private static final String STATE_XML = "xml";
-
-    private final AsyncProcessor jsonUnmarshal;
-    private final AsyncProcessor xmlUnmarshal;
-    private final AsyncProcessor jsonMarshal;
-    private final AsyncProcessor xmlMarshal;
-    private final String consumes;
-    private final String produces;
-    private final String bindingMode;
-    private final boolean skipBindingOnErrorCode;
-    private final boolean clientRequestValidation;
-    private final boolean enableCORS;
-    private final boolean enableNoContentResponse;
-    private final Map<String, String> corsHeaders;
-    private final Map<String, String> queryDefaultValues;
-    private final boolean requiredBody;
-    private final Set<String> requiredQueryParameters;
-    private final Set<String> requiredHeaders;
+@Deprecated
+public class RestBindingAdvice extends RestBindingSupport {
 
     public RestBindingAdvice(CamelContext camelContext, DataFormat 
jsonDataFormat, DataFormat xmlDataFormat,
                              DataFormat outJsonDataFormat, DataFormat 
outXmlDataFormat,
-                             String consumes, String produces, String 
bindingMode,
-                             boolean skipBindingOnErrorCode, boolean 
clientRequestValidation, boolean enableCORS,
+                             String consumes, String produces,
+                             String bindingMode, boolean 
skipBindingOnErrorCode,
+                             boolean clientRequestValidation, boolean 
enableCORS,
                              boolean enableNoContentResponse,
-                             Map<String, String> corsHeaders,
-                             Map<String, String> queryDefaultValues,
+                             Map<String, String> corsHeaders, Map<String, 
String> queryDefaultValues,
                              boolean requiredBody, Set<String> 
requiredQueryParameters,
                              Set<String> requiredHeaders) throws Exception {
 
-        if (jsonDataFormat != null) {
-            this.jsonUnmarshal = new UnmarshalProcessor(jsonDataFormat);
-        } else {
-            this.jsonUnmarshal = null;
-        }
-        if (outJsonDataFormat != null) {
-            this.jsonMarshal = new MarshalProcessor(outJsonDataFormat);
-        } else if (jsonDataFormat != null) {
-            this.jsonMarshal = new MarshalProcessor(jsonDataFormat);
-        } else {
-            this.jsonMarshal = null;
-        }
-
-        if (xmlDataFormat != null) {
-            this.xmlUnmarshal = new UnmarshalProcessor(xmlDataFormat);
-        } else {
-            this.xmlUnmarshal = null;
-        }
-        if (outXmlDataFormat != null) {
-            this.xmlMarshal = new MarshalProcessor(outXmlDataFormat);
-        } else if (xmlDataFormat != null) {
-            this.xmlMarshal = new MarshalProcessor(xmlDataFormat);
-        } else {
-            this.xmlMarshal = null;
-        }
-
-        if (jsonMarshal != null) {
-            camelContext.addService(jsonMarshal, true);
-        }
-        if (jsonUnmarshal != null) {
-            camelContext.addService(jsonUnmarshal, true);
-        }
-        if (xmlMarshal != null) {
-            camelContext.addService(xmlMarshal, true);
-        }
-        if (xmlUnmarshal != null) {
-            camelContext.addService(xmlUnmarshal, true);
-        }
-
-        this.consumes = consumes;
-        this.produces = produces;
-        this.bindingMode = bindingMode;
-        this.skipBindingOnErrorCode = skipBindingOnErrorCode;
-        this.clientRequestValidation = clientRequestValidation;
-        this.enableCORS = enableCORS;
-        this.corsHeaders = corsHeaders;
-        this.queryDefaultValues = queryDefaultValues;
-        this.requiredBody = requiredBody;
-        this.requiredQueryParameters = requiredQueryParameters;
-        this.requiredHeaders = requiredHeaders;
-        this.enableNoContentResponse = enableNoContentResponse;
-    }
-
-    @Override
-    public Map<String, Object> before(Exchange exchange) throws Exception {
-        Map<String, Object> state = new HashMap<>();
-        if (isOptionsMethod(exchange, state)) {
-            return state;
-        }
-        unmarshal(exchange, state);
-        return state;
-    }
-
-    @Override
-    public void after(Exchange exchange, Map<String, Object> state) throws 
Exception {
-        if (enableCORS) {
-            setCORSHeaders(exchange);
-        }
-        if (state.get(STATE_KEY_DO_MARSHAL) != null) {
-            marshal(exchange, state);
-        }
-    }
-
-    private boolean isOptionsMethod(Exchange exchange, Map<String, Object> 
state) {
-        String method = exchange.getIn().getHeader(Exchange.HTTP_METHOD, 
String.class);
-        if ("OPTIONS".equalsIgnoreCase(method)) {
-            // for OPTIONS methods then we should not route at all as its part 
of CORS
-            exchange.setRouteStop(true);
-            return true;
-        }
-        return false;
-    }
-
-    private void unmarshal(Exchange exchange, Map<String, Object> state) {
-        boolean isXml = false;
-        boolean isJson = false;
-
-        String contentType = ExchangeHelper.getContentType(exchange);
-        if (contentType != null) {
-            isXml = contentType.toLowerCase(Locale.ENGLISH).contains("xml");
-            isJson = contentType.toLowerCase(Locale.ENGLISH).contains("json");
-        }
-        // if content type could not tell us if it was json or xml, then 
fallback to if the binding was configured with
-        // that information in the consumes
-        if (!isXml && !isJson) {
-            isXml = consumes != null && 
consumes.toLowerCase(Locale.ENGLISH).contains("xml");
-            isJson = consumes != null && 
consumes.toLowerCase(Locale.ENGLISH).contains("json");
-        }
-
-        // set data type if in use
-        if (exchange.getContext().isUseDataType()) {
-            if (exchange.getIn() instanceof DataTypeAware && (isJson || 
isXml)) {
-                ((DataTypeAware) exchange.getIn()).setDataType(new 
DataType(isJson ? "json" : "xml"));
-            }
-        }
-
-        // only allow xml/json if the binding mode allows that
-        isXml &= bindingMode.equals("auto") || bindingMode.contains("xml");
-        isJson &= bindingMode.equals("auto") || bindingMode.contains("json");
-
-        // if we do not yet know if its xml or json, then use the binding mode 
to know the mode
-        if (!isJson && !isXml) {
-            isXml = bindingMode.equals("auto") || bindingMode.contains("xml");
-            isJson = bindingMode.equals("auto") || 
bindingMode.contains("json");
-        }
-
-        String accept = exchange.getMessage().getHeader("Accept", 
String.class);
-        state.put(STATE_KEY_ACCEPT, accept);
-
-        // perform client request validation
-        if (clientRequestValidation) {
-            // check if the content-type is accepted according to consumes
-            if (!isValidOrAcceptedContentType(consumes, contentType)) {
-                LOG.trace("Consuming content type does not match contentType 
header {}. Stopping routing.", contentType);
-                // the content-type is not something we can process so its a 
HTTP_ERROR 415
-                exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 
415);
-                // set empty response body as http error code indicate the 
problem
-                exchange.getMessage().setBody(null);
-                // stop routing and return
-                exchange.setRouteStop(true);
-                return;
-            }
-
-            // check if what is produces is accepted by the client
-            if (!isValidOrAcceptedContentType(produces, accept)) {
-                LOG.trace("Produced content type does not match accept header 
{}. Stopping routing.", contentType);
-                // the response type is not accepted by the client so its a 
HTTP_ERROR 406
-                exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 
406);
-                // set empty response body as http error code indicate the 
problem
-                exchange.getMessage().setBody(null);
-                // stop routing and return
-                exchange.setRouteStop(true);
-                return;
-            }
-        }
-
-        String body = null;
-        if (exchange.getIn().getBody() != null) {
-
-            // okay we have a binding mode, so need to check for empty body as 
that can cause the marshaller to fail
-            // as they assume a non-empty body
-            if (isXml || isJson) {
-                // we have binding enabled, so we need to know if there body 
is empty or not
-                // so force reading the body as a String which we can work with
-                body = MessageHelper.extractBodyAsString(exchange.getIn());
-                if (body != null) {
-                    if (exchange.getIn() instanceof DataTypeAware) {
-                        ((DataTypeAware) exchange.getIn()).setBody(body, new 
DataType(isJson ? "json" : "xml"));
-                    } else {
-                        exchange.getIn().setBody(body);
-                    }
-
-                    if (isXml && isJson) {
-                        // we have still not determined between xml or json, 
so check the body if its xml based or not
-                        isXml = body.startsWith("<");
-                        isJson = !isXml;
-                    }
-                }
-            }
-        }
-
-        // add missing default values which are mapped as headers
-        if (queryDefaultValues != null) {
-            for (Map.Entry<String, String> entry : 
queryDefaultValues.entrySet()) {
-                if (exchange.getIn().getHeader(entry.getKey()) == null) {
-                    exchange.getIn().setHeader(entry.getKey(), 
entry.getValue());
-                }
-            }
-        }
-
-        // check for required
-        if (clientRequestValidation) {
-            if (requiredBody) {
-                // the body is required so we need to know if we have a body 
or not
-                // so force reading the body as a String which we can work with
-                if (body == null) {
-                    body = MessageHelper.extractBodyAsString(exchange.getIn());
-                    if (ObjectHelper.isNotEmpty(body)) {
-                        exchange.getIn().setBody(body);
-                    }
-                }
-                if (ObjectHelper.isEmpty(body)) {
-                    // this is a bad request, the client did not include a 
message body
-                    
exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
-                    exchange.getMessage().setBody("The request body is 
missing.");
-                    // stop routing and return
-                    exchange.setRouteStop(true);
-                    return;
-                }
-            }
-            if (requiredQueryParameters != null
-                    && 
!exchange.getIn().getHeaders().keySet().containsAll(requiredQueryParameters)) {
-                // this is a bad request, the client did not include some 
required query parameters
-                exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 
400);
-                exchange.getMessage().setBody("Some of the required query 
parameters are missing.");
-                // stop routing and return
-                exchange.setRouteStop(true);
-                return;
-            }
-            if (requiredHeaders != null && 
!exchange.getIn().getHeaders().keySet().containsAll(requiredHeaders)) {
-                // this is a bad request, the client did not include some 
required http headers
-                exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 
400);
-                exchange.getMessage().setBody("Some of the required HTTP 
headers are missing.");
-                // stop routing and return
-                exchange.setRouteStop(true);
-                return;
-            }
-        }
-
-        // favor json over xml
-        if (isJson && jsonUnmarshal != null) {
-            // add reverse operation
-            state.put(STATE_KEY_DO_MARSHAL, STATE_JSON);
-            if (ObjectHelper.isNotEmpty(body)) {
-                try {
-                    jsonUnmarshal.process(exchange);
-                    ExchangeHelper.prepareOutToIn(exchange);
-                } catch (Exception e) {
-                    exchange.setException(e);
-                }
-                if (exchange.isFailed()) {
-                    // we want to indicate that this is a bad request instead 
of 500 due to parsing error
-                    
exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
-                }
-            }
-            if (clientRequestValidation && exchange.isFailed()) {
-                // this is a bad request, the client included message body 
that cannot be parsed to json
-                exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 
400);
-                exchange.getMessage().setBody("Invalid JSon payload.");
-                // clear exception
-                exchange.setException(null);
-                // stop routing and return
-                exchange.setRouteStop(true);
-                return;
-            }
-            return;
-        } else if (isXml && xmlUnmarshal != null) {
-            // add reverse operation
-            state.put(STATE_KEY_DO_MARSHAL, STATE_XML);
-            if (ObjectHelper.isNotEmpty(body)) {
-                try {
-                    xmlUnmarshal.process(exchange);
-                    ExchangeHelper.prepareOutToIn(exchange);
-                } catch (Exception e) {
-                    exchange.setException(e);
-                }
-                if (exchange.isFailed()) {
-                    // we want to indicate that this is a bad request instead 
of 500 due to parsing error
-                    
exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
-                }
-            }
-            if (clientRequestValidation && exchange.isFailed()) {
-                // this is a bad request, the client included message body 
that cannot be parsed to XML
-                exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 
400);
-                exchange.getMessage().setBody("Invalid XML payload.");
-                // clear exception
-                exchange.setException(null);
-                // stop routing and return
-                exchange.setRouteStop(true);
-                return;
-            }
-            return;
-        }
-
-        // we could not bind
-        if ("off".equals(bindingMode) || bindingMode.equals("auto")) {
-            // okay for auto we do not mind if we could not bind
-            state.put(STATE_KEY_DO_MARSHAL, STATE_JSON);
-        } else {
-            if (bindingMode.contains("xml")) {
-                exchange.setException(
-                        new CamelExchangeException("Cannot bind to xml as 
message body is not xml compatible", exchange));
-            } else {
-                exchange.setException(
-                        new CamelExchangeException("Cannot bind to json as 
message body is not json compatible", exchange));
-            }
-        }
-
-    }
-
-    private void marshal(Exchange exchange, Map<String, Object> state) {
-        // only marshal if there was no exception
-        if (exchange.getException() != null) {
-            return;
-        }
-
-        if (skipBindingOnErrorCode) {
-            Integer code = 
exchange.getMessage().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
-            // if there is a custom http error code then skip binding
-            if (code != null && code >= 300) {
-                return;
-            }
-        }
-
-        boolean isXml = false;
-        boolean isJson = false;
-
-        // accept takes precedence
-        String accept = (String) state.get(STATE_KEY_ACCEPT);
-        if (accept != null) {
-            isXml = accept.toLowerCase(Locale.ENGLISH).contains("xml");
-            isJson = accept.toLowerCase(Locale.ENGLISH).contains("json");
-        }
-        // fallback to content type if still undecided
-        if (!isXml && !isJson) {
-            String contentType = ExchangeHelper.getContentType(exchange);
-            if (contentType != null) {
-                isXml = 
contentType.toLowerCase(Locale.ENGLISH).contains("xml");
-                isJson = 
contentType.toLowerCase(Locale.ENGLISH).contains("json");
-            }
-        }
-        // if content type could not tell us if it was json or xml, then 
fallback to if the binding was configured with
-        // that information in the consumes
-        if (!isXml && !isJson) {
-            isXml = produces != null && 
produces.toLowerCase(Locale.ENGLISH).contains("xml");
-            isJson = produces != null && 
produces.toLowerCase(Locale.ENGLISH).contains("json");
-        }
-
-        // only allow xml/json if the binding mode allows that (when off we 
still want to know if its xml or json)
-        if (bindingMode != null) {
-            isXml &= bindingMode.equals("off") || bindingMode.equals("auto") 
|| bindingMode.contains("xml");
-            isJson &= bindingMode.equals("off") || bindingMode.equals("auto") 
|| bindingMode.contains("json");
-
-            // if we do not yet know if its xml or json, then use the binding 
mode to know the mode
-            if (!isJson && !isXml) {
-                isXml = bindingMode.equals("auto") || 
bindingMode.contains("xml");
-                isJson = bindingMode.equals("auto") || 
bindingMode.contains("json");
-            }
-        }
-
-        // in case we have not yet been able to determine if xml or json, then 
use the same as in the unmarshaller
-        if (isXml && isJson) {
-            isXml = state.get(STATE_KEY_DO_MARSHAL).equals(STATE_XML);
-            isJson = !isXml;
-        }
-
-        // need to prepare exchange first
-        ExchangeHelper.prepareOutToIn(exchange);
-
-        // ensure there is a content type header (even if binding is off)
-        ensureHeaderContentType(produces, isXml, isJson, exchange);
-
-        if (bindingMode == null || "off".equals(bindingMode)) {
-            // binding is off, so no message body binding
-            return;
-        }
-
-        // is there any marshaller at all
-        if (jsonMarshal == null && xmlMarshal == null) {
-            return;
-        }
-
-        // is the body empty
-        if (exchange.getMessage().getBody() == null) {
-            return;
-        }
-
-        String contentType = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, 
String.class);
-        // need to lower-case so the contains check below can match if using 
upper case
-        contentType = contentType.toLowerCase(Locale.US);
-        try {
-            // favor json over xml
-            if (isJson && jsonMarshal != null) {
-                // only marshal if its json content type
-                if (contentType.contains("json")) {
-                    jsonMarshal.process(exchange);
-                    setOutputDataType(exchange, new DataType("json"));
-
-                    if (enableNoContentResponse) {
-                        String body = 
MessageHelper.extractBodyAsString(exchange.getMessage());
-                        if (ObjectHelper.isNotEmpty(body) && 
(body.equals("[]") || body.equals("{}"))) {
-                            
exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 204);
-                            exchange.getMessage().setBody("");
-                        }
-                    }
-                }
-            } else if (isXml && xmlMarshal != null) {
-                // only marshal if its xml content type
-                if (contentType.contains("xml")) {
-                    xmlMarshal.process(exchange);
-                    setOutputDataType(exchange, new DataType("xml"));
-
-                    if (enableNoContentResponse) {
-                        String body = 
MessageHelper.extractBodyAsString(exchange.getMessage()).replace("\n", "");
-                        if (ObjectHelper.isNotEmpty(body)) {
-                            int open = 0;
-                            int close = body.indexOf('>');
-                            // xml declaration
-                            if (body.startsWith("<?xml")) {
-                                open = close;
-                                close = body.indexOf('>', close + 1);
-                            }
-                            // empty root element <el/> or <el></el>
-                            if (body.length() == close + 1 || body.length() == 
(open + 1 + 2 * (close - open) + 1)) {
-                                
exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 204);
-                                exchange.getMessage().setBody("");
-                            }
-                        }
-                    }
-                }
-            } else {
-                // we could not bind
-                if (bindingMode.equals("auto")) {
-                    // okay for auto we do not mind if we could not bind
-                } else {
-                    if (bindingMode.contains("xml")) {
-                        exchange.setException(new CamelExchangeException(
-                                "Cannot bind to xml as message body is not xml 
compatible", exchange));
-                    } else {
-                        exchange.setException(new CamelExchangeException(
-                                "Cannot bind to json as message body is not 
json compatible", exchange));
-                    }
-                }
-            }
-        } catch (Exception e) {
-            exchange.setException(e);
-        }
-    }
-
-    private void setOutputDataType(Exchange exchange, DataType type) {
-        Message target = exchange.getMessage();
-        if (target instanceof DataTypeAware) {
-            ((DataTypeAware) target).setDataType(type);
-        }
-    }
-
-    private void ensureHeaderContentType(String contentType, boolean isXml, 
boolean isJson, Exchange exchange) {
-        // favor given content type
-        if (contentType != null) {
-            String type = ExchangeHelper.getContentType(exchange);
-            if (type == null) {
-                exchange.getIn().setHeader(Exchange.CONTENT_TYPE, contentType);
-            }
-        }
-
-        // favor json over xml
-        if (isJson) {
-            // make sure there is a content-type with json
-            String type = ExchangeHelper.getContentType(exchange);
-            if (type == null) {
-                exchange.getIn().setHeader(Exchange.CONTENT_TYPE, 
"application/json");
-            }
-        } else if (isXml) {
-            // make sure there is a content-type with xml
-            String type = ExchangeHelper.getContentType(exchange);
-            if (type == null) {
-                exchange.getIn().setHeader(Exchange.CONTENT_TYPE, 
"application/xml");
-            }
-        }
-    }
-
-    private void setCORSHeaders(Exchange exchange) {
-        // add the CORS headers after routing, but before the consumer writes 
the response
-        Message msg = exchange.getMessage();
-
-        // use default value if none has been configured
-        String allowOrigin = corsHeaders != null ? 
corsHeaders.get("Access-Control-Allow-Origin") : null;
-        if (allowOrigin == null) {
-            allowOrigin = RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_ORIGIN;
-        }
-        String allowMethods = corsHeaders != null ? 
corsHeaders.get("Access-Control-Allow-Methods") : null;
-        if (allowMethods == null) {
-            allowMethods = RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_METHODS;
-        }
-        String allowHeaders = corsHeaders != null ? 
corsHeaders.get("Access-Control-Allow-Headers") : null;
-        if (allowHeaders == null) {
-            allowHeaders = RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_HEADERS;
-        }
-        String maxAge = corsHeaders != null ? 
corsHeaders.get("Access-Control-Max-Age") : null;
-        if (maxAge == null) {
-            maxAge = RestConfiguration.CORS_ACCESS_CONTROL_MAX_AGE;
-        }
-        String allowCredentials = corsHeaders != null ? 
corsHeaders.get("Access-Control-Allow-Credentials") : null;
-
-        // Restrict the origin if credentials are allowed.
-        // https://www.w3.org/TR/cors/ - section 6.1, point 3
-        String origin = exchange.getIn().getHeader("Origin", String.class);
-        if ("true".equalsIgnoreCase(allowCredentials) && 
"*".equals(allowOrigin) && origin != null) {
-            allowOrigin = origin;
-        }
-
-        msg.setHeader("Access-Control-Allow-Origin", allowOrigin);
-        msg.setHeader("Access-Control-Allow-Methods", allowMethods);
-        msg.setHeader("Access-Control-Allow-Headers", allowHeaders);
-        msg.setHeader("Access-Control-Max-Age", maxAge);
-        if (allowCredentials != null) {
-            msg.setHeader("Access-Control-Allow-Credentials", 
allowCredentials);
-        }
+        super(camelContext, jsonDataFormat, xmlDataFormat, outJsonDataFormat, 
outXmlDataFormat,
+                consumes, produces, bindingMode, skipBindingOnErrorCode, 
clientRequestValidation,
+                enableCORS, enableNoContentResponse, corsHeaders, 
queryDefaultValues,
+                requiredBody, requiredQueryParameters, requiredHeaders);
     }
 
 }
diff --git 
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java
 
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java
index ccc54d21254..20b9cf309c1 100644
--- 
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java
+++ 
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java
@@ -41,6 +41,8 @@ public class RestBindingReifier extends AbstractReifier {
     }
 
     public RestBindingAdvice createRestBindingAdvice() throws Exception {
+        // TODO: Use RestBindingFactory
+
         RestConfiguration config = 
CamelContextHelper.getRestConfiguration(camelContext, 
definition.getComponent());
 
         // these options can be overridden per rest verb
@@ -64,6 +66,8 @@ public class RestBindingReifier extends AbstractReifier {
         if (definition.getClientRequestValidation() != null) {
             validation = parseBoolean(definition.getClientRequestValidation(), 
false);
         }
+        String consumes = parseString(definition.getConsumes());
+        String produces = parseString(definition.getProduces());
 
         // cors headers
         Map<String, String> corsHeaders = config.getCorsHeaders();
@@ -72,7 +76,7 @@ public class RestBindingReifier extends AbstractReifier {
             // binding mode is off, so create off mode binding processor
             return new RestBindingAdvice(
                     camelContext, null, null, null, null,
-                    parseString(definition.getConsumes()), 
parseString(definition.getProduces()), mode, skip, validation, cors,
+                    consumes, produces, mode, skip, validation, cors,
                     noContentResponse, corsHeaders,
                     definition.getDefaultValues(), 
definition.getRequiredBody() != null ? definition.getRequiredBody() : false,
                     definition.getRequiredQueryParameters(), 
definition.getRequiredHeaders());
@@ -150,6 +154,7 @@ public class RestBindingReifier extends AbstractReifier {
                 definition.getRequiredQueryParameters(), 
definition.getRequiredHeaders());
     }
 
+    @Deprecated
     protected void setupJson(
             RestConfiguration config, String type, Class<?> typeClass, String 
outType, Class<?> outTypeClass, DataFormat json,
             DataFormat outJson)
@@ -197,6 +202,7 @@ public class RestBindingReifier extends AbstractReifier {
         setAdditionalConfiguration(config, outJson, "json.out.");
     }
 
+    @Deprecated
     private void setAdditionalConfiguration(RestConfiguration config, 
DataFormat dataFormat, String prefix) {
         if (config.getDataFormatProperties() != null && 
!config.getDataFormatProperties().isEmpty()) {
             // must use a copy as otherwise the options gets removed during
@@ -226,6 +232,7 @@ public class RestBindingReifier extends AbstractReifier {
         }
     }
 
+    @Deprecated
     private boolean isKeyKnownPrefix(String key) {
         return key.startsWith("json.in.") || key.startsWith("json.out.") || 
key.startsWith("xml.in.")
                 || key.startsWith("xml.out.");
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingConfiguration.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingConfiguration.java
new file mode 100644
index 00000000000..2d54a15ca42
--- /dev/null
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingConfiguration.java
@@ -0,0 +1,171 @@
+/*
+ * 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.support.processor;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Configuration for {@link RestBindingSupport}.
+ */
+public class RestBindingConfiguration {
+
+    private String consumes;
+    private String produces;
+    private String bindingMode;
+    private boolean skipBindingOnErrorCode;
+    private boolean clientRequestValidation;
+    private boolean enableCORS;
+    private boolean enableNoContentResponse;
+    private Map<String, String> corsHeaders;
+    private Map<String, String> queryDefaultValues;
+    private boolean requiredBody;
+    private Set<String> requiredQueryParameters;
+    private Set<String> requiredHeaders;
+    private String type;
+    private Class<?> typeClass;
+    private String outType;
+    private Class<?> outTypeClass;
+
+    public String getConsumes() {
+        return consumes;
+    }
+
+    public void setConsumes(String consumes) {
+        this.consumes = consumes;
+    }
+
+    public String getProduces() {
+        return produces;
+    }
+
+    public void setProduces(String produces) {
+        this.produces = produces;
+    }
+
+    public String getBindingMode() {
+        return bindingMode;
+    }
+
+    public void setBindingMode(String bindingMode) {
+        this.bindingMode = bindingMode;
+    }
+
+    public boolean isSkipBindingOnErrorCode() {
+        return skipBindingOnErrorCode;
+    }
+
+    public void setSkipBindingOnErrorCode(boolean skipBindingOnErrorCode) {
+        this.skipBindingOnErrorCode = skipBindingOnErrorCode;
+    }
+
+    public boolean isClientRequestValidation() {
+        return clientRequestValidation;
+    }
+
+    public void setClientRequestValidation(boolean clientRequestValidation) {
+        this.clientRequestValidation = clientRequestValidation;
+    }
+
+    public boolean isEnableCORS() {
+        return enableCORS;
+    }
+
+    public void setEnableCORS(boolean enableCORS) {
+        this.enableCORS = enableCORS;
+    }
+
+    public boolean isEnableNoContentResponse() {
+        return enableNoContentResponse;
+    }
+
+    public void setEnableNoContentResponse(boolean enableNoContentResponse) {
+        this.enableNoContentResponse = enableNoContentResponse;
+    }
+
+    public Map<String, String> getCorsHeaders() {
+        return corsHeaders;
+    }
+
+    public void setCorsHeaders(Map<String, String> corsHeaders) {
+        this.corsHeaders = corsHeaders;
+    }
+
+    public Map<String, String> getQueryDefaultValues() {
+        return queryDefaultValues;
+    }
+
+    public void setQueryDefaultValues(Map<String, String> queryDefaultValues) {
+        this.queryDefaultValues = queryDefaultValues;
+    }
+
+    public boolean isRequiredBody() {
+        return requiredBody;
+    }
+
+    public void setRequiredBody(boolean requiredBody) {
+        this.requiredBody = requiredBody;
+    }
+
+    public Set<String> getRequiredQueryParameters() {
+        return requiredQueryParameters;
+    }
+
+    public void setRequiredQueryParameters(Set<String> 
requiredQueryParameters) {
+        this.requiredQueryParameters = requiredQueryParameters;
+    }
+
+    public Set<String> getRequiredHeaders() {
+        return requiredHeaders;
+    }
+
+    public void setRequiredHeaders(Set<String> requiredHeaders) {
+        this.requiredHeaders = requiredHeaders;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public Class<?> getTypeClass() {
+        return typeClass;
+    }
+
+    public void setTypeClass(Class<?> typeClass) {
+        this.typeClass = typeClass;
+    }
+
+    public String getOutType() {
+        return outType;
+    }
+
+    public void setOutType(String outType) {
+        this.outType = outType;
+    }
+
+    public Class<?> getOutTypeClass() {
+        return outTypeClass;
+    }
+
+    public void setOutTypeClass(Class<?> outTypeClass) {
+        this.outTypeClass = outTypeClass;
+    }
+}
diff --git 
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingFactory.java
similarity index 64%
copy from 
core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java
copy to 
core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingFactory.java
index ccc54d21254..b1d9072d05f 100644
--- 
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingFactory.java
@@ -14,68 +14,36 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.reifier.rest;
+package org.apache.camel.support.processor;
 
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.camel.Route;
-import org.apache.camel.model.rest.RestBindingDefinition;
-import org.apache.camel.model.rest.RestBindingMode;
-import org.apache.camel.processor.RestBindingAdvice;
-import org.apache.camel.reifier.AbstractReifier;
+import org.apache.camel.CamelContext;
 import org.apache.camel.spi.BeanIntrospection;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.spi.RestConfiguration;
-import org.apache.camel.support.CamelContextHelper;
+import org.apache.camel.support.EndpointHelper;
 import org.apache.camel.support.PluginHelper;
 import org.apache.camel.support.PropertyBindingSupport;
 
-public class RestBindingReifier extends AbstractReifier {
-
-    private final RestBindingDefinition definition;
-
-    public RestBindingReifier(Route route, RestBindingDefinition definition) {
-        super(route);
-        this.definition = definition;
-    }
-
-    public RestBindingAdvice createRestBindingAdvice() throws Exception {
-        RestConfiguration config = 
CamelContextHelper.getRestConfiguration(camelContext, 
definition.getComponent());
+/**
+ * Factory to create {@link RestBindingSupport} from the given configuration.
+ */
+public class RestBindingFactory {
 
-        // these options can be overridden per rest verb
+    public static RestBindingSupport build(CamelContext camelContext, 
RestBindingConfiguration bc) throws Exception {
+        RestConfiguration config = camelContext.getRestConfiguration();
         String mode = config.getBindingMode().name();
-        if (definition.getBindingMode() != null) {
-            mode = parse(RestBindingMode.class, 
definition.getBindingMode()).name();
-        }
-        boolean cors = config.isEnableCORS();
-        if (definition.getEnableCORS() != null) {
-            cors = parseBoolean(definition.getEnableCORS(), false);
-        }
-        boolean noContentResponse = config.isEnableNoContentResponse();
-        if (definition.getEnableNoContentResponse() != null) {
-            noContentResponse = 
parseBoolean(definition.getEnableNoContentResponse(), false);
-        }
-        boolean skip = config.isSkipBindingOnErrorCode();
-        if (definition.getSkipBindingOnErrorCode() != null) {
-            skip = parseBoolean(definition.getSkipBindingOnErrorCode(), false);
-        }
-        boolean validation = config.isClientRequestValidation();
-        if (definition.getClientRequestValidation() != null) {
-            validation = parseBoolean(definition.getClientRequestValidation(), 
false);
-        }
-
-        // cors headers
-        Map<String, String> corsHeaders = config.getCorsHeaders();
 
         if ("off".equals(mode)) {
             // binding mode is off, so create off mode binding processor
-            return new RestBindingAdvice(
+            return new RestBindingSupport(
                     camelContext, null, null, null, null,
-                    parseString(definition.getConsumes()), 
parseString(definition.getProduces()), mode, skip, validation, cors,
-                    noContentResponse, corsHeaders,
-                    definition.getDefaultValues(), 
definition.getRequiredBody() != null ? definition.getRequiredBody() : false,
-                    definition.getRequiredQueryParameters(), 
definition.getRequiredHeaders());
+                    bc.getConsumes(), bc.getProduces(), mode, 
bc.isSkipBindingOnErrorCode(), bc.isClientRequestValidation(), 
bc.isEnableCORS(),
+                    bc.isEnableNoContentResponse(), bc.getCorsHeaders(),
+                    bc.getQueryDefaultValues(), bc.isRequiredBody(), 
bc.getRequiredQueryParameters(),
+                    bc.getRequiredHeaders());
         }
 
         // setup json data format
@@ -85,7 +53,7 @@ public class RestBindingReifier extends AbstractReifier {
             String name = config.getJsonDataFormat();
             if (name != null) {
                 // must only be a name, not refer to an existing instance
-                Object instance = lookupByName(name);
+                Object instance = lookupByName(camelContext, name);
                 if (instance != null) {
                     throw new IllegalArgumentException(
                             "JsonDataFormat name: " + name + " must not be an 
existing bean instance from the registry");
@@ -99,10 +67,9 @@ public class RestBindingReifier extends AbstractReifier {
             outJson = camelContext.createDataFormat(name);
 
             if (json != null) {
-                setupJson(
-                        config,
-                        parseString(definition.getType()), 
definition.getTypeClass(),
-                        parseString(definition.getOutType()), 
definition.getOutTypeClass(),
+                setupJson(camelContext, config,
+                        bc.getType(), bc.getTypeClass(),
+                        bc.getOutType(), bc.getOutTypeClass(),
                         json, outJson);
             }
         }
@@ -114,7 +81,7 @@ public class RestBindingReifier extends AbstractReifier {
             String name = config.getXmlDataFormat();
             if (name != null) {
                 // must only be a name, not refer to an existing instance
-                Object instance = lookupByName(name);
+                Object instance = lookupByName(camelContext, name);
                 if (instance != null) {
                     throw new IllegalArgumentException(
                             "XmlDataFormat name: " + name + " must not be an 
existing bean instance from the registry");
@@ -134,23 +101,23 @@ public class RestBindingReifier extends AbstractReifier {
 
             if (jaxb != null) {
                 // to setup JAXB we need to use camel-jaxb
-                
PluginHelper.getRestBindingJaxbDataFormatFactory(camelContext).setupJaxb(
-                        camelContext, config,
-                        parseString(definition.getType()), 
definition.getTypeClass(),
-                        parseString(definition.getOutType()), 
definition.getOutTypeClass(),
-                        jaxb, outJaxb);
+                PluginHelper.getRestBindingJaxbDataFormatFactory(camelContext).
+                        setupJaxb(camelContext, config,
+                                bc.getType(), bc.getTypeClass(),
+                                bc.getOutType(), bc.getOutTypeClass(),
+                                jaxb, outJaxb);
             }
         }
 
-        return new RestBindingAdvice(
+        return new RestBindingSupport(
                 camelContext, json, jaxb, outJson, outJaxb,
-                parseString(definition.getConsumes()), 
parseString(definition.getProduces()),
-                mode, skip, validation, cors, noContentResponse, corsHeaders,
-                definition.getDefaultValues(), definition.getRequiredBody() != 
null ? definition.getRequiredBody() : false,
-                definition.getRequiredQueryParameters(), 
definition.getRequiredHeaders());
+                bc.getConsumes(), bc.getProduces(), mode, 
bc.isSkipBindingOnErrorCode(), bc.isClientRequestValidation(), 
bc.isEnableCORS(),
+                bc.isEnableNoContentResponse(), bc.getCorsHeaders(),
+                bc.getQueryDefaultValues(), bc.isRequiredBody(), 
bc.getRequiredQueryParameters(),
+                bc.getRequiredHeaders());
     }
 
-    protected void setupJson(
+    protected static void setupJson(CamelContext camelContext,
             RestConfiguration config, String type, Class<?> typeClass, String 
outType, Class<?> outTypeClass, DataFormat json,
             DataFormat outJson)
             throws Exception {
@@ -173,7 +140,7 @@ public class RestBindingReifier extends AbstractReifier {
                     useList);
         }
 
-        setAdditionalConfiguration(config, json, "json.in.");
+        setAdditionalConfiguration(camelContext, config, json, "json.in.");
 
         Class<?> outClazz = null;
         boolean outUseList = false;
@@ -194,10 +161,10 @@ public class RestBindingReifier extends AbstractReifier {
                     outUseList);
         }
 
-        setAdditionalConfiguration(config, outJson, "json.out.");
+        setAdditionalConfiguration(camelContext, config, outJson, "json.out.");
     }
 
-    private void setAdditionalConfiguration(RestConfiguration config, 
DataFormat dataFormat, String prefix) {
+    private static void setAdditionalConfiguration(CamelContext camelContext, 
RestConfiguration config, DataFormat dataFormat, String prefix) {
         if (config.getDataFormatProperties() != null && 
!config.getDataFormatProperties().isEmpty()) {
             // must use a copy as otherwise the options gets removed during
             // introspection setProperties
@@ -226,9 +193,21 @@ public class RestBindingReifier extends AbstractReifier {
         }
     }
 
-    private boolean isKeyKnownPrefix(String key) {
+    private static boolean isKeyKnownPrefix(String key) {
         return key.startsWith("json.in.") || key.startsWith("json.out.") || 
key.startsWith("xml.in.")
-                || key.startsWith("xml.out.");
+               || key.startsWith("xml.out.");
+    }
+
+    private static Object lookupByName(CamelContext camelContext, String name) 
{
+        if (name == null) {
+            return null;
+        }
+
+        if (EndpointHelper.isReferenceParameter(name)) {
+            return EndpointHelper.resolveReferenceParameter(camelContext, 
name, Object.class, false);
+        } else {
+            return camelContext.getRegistry().lookupByName(name);
+        }
     }
 
 }
diff --git 
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingSupport.java
similarity index 96%
copy from 
core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
copy to 
core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingSupport.java
index 0efcf7c0dae..f7ca71d7515 100644
--- 
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingSupport.java
@@ -14,12 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.processor;
-
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
+package org.apache.camel.support.processor;
 
 import org.apache.camel.AsyncProcessor;
 import org.apache.camel.CamelContext;
@@ -33,26 +28,27 @@ import org.apache.camel.spi.DataTypeAware;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.support.ExchangeHelper;
 import org.apache.camel.support.MessageHelper;
-import org.apache.camel.support.processor.MarshalProcessor;
-import org.apache.camel.support.processor.UnmarshalProcessor;
+import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
 import static 
org.apache.camel.support.http.RestUtil.isValidOrAcceptedContentType;
 
 /**
- * A {@link CamelInternalProcessorAdvice} that binds the REST DSL incoming and 
outgoing messages from sources of json or
- * xml to Java Objects.
- * <p/>
- * The binding uses {@link org.apache.camel.spi.DataFormat} for the actual 
work to transform from xml/json to Java
- * Objects and reverse again.
- * <p/>
- * The rest producer side is implemented in {@link 
org.apache.camel.component.rest.RestProducerBindingProcessor}
+ * Used for Rest DSL with binding to json/xml for incoming requests and 
outgoing responses.
+ *
+ * @see RestBindingFactory
  */
-public class RestBindingAdvice implements 
CamelInternalProcessorAdvice<Map<String, Object>> {
+public class RestBindingSupport extends ServiceSupport implements 
CamelInternalProcessorAdvice<Map<String, Object>> {
 
-    private static final Logger LOG = 
LoggerFactory.getLogger(RestBindingAdvice.class);
+    private static final Logger LOG = 
LoggerFactory.getLogger(RestBindingSupport.class);
     private static final String STATE_KEY_DO_MARSHAL = "doMarshal";
     private static final String STATE_KEY_ACCEPT = "accept";
     private static final String STATE_JSON = "json";
@@ -75,7 +71,10 @@ public class RestBindingAdvice implements 
CamelInternalProcessorAdvice<Map<Strin
     private final Set<String> requiredQueryParameters;
     private final Set<String> requiredHeaders;
 
-    public RestBindingAdvice(CamelContext camelContext, DataFormat 
jsonDataFormat, DataFormat xmlDataFormat,
+    /**
+     * Use {@link RestBindingFactory} to create.
+     */
+    public RestBindingSupport(CamelContext camelContext, DataFormat 
jsonDataFormat, DataFormat xmlDataFormat,
                              DataFormat outJsonDataFormat, DataFormat 
outXmlDataFormat,
                              String consumes, String produces, String 
bindingMode,
                              boolean skipBindingOnErrorCode, boolean 
clientRequestValidation, boolean enableCORS,
@@ -286,7 +285,7 @@ public class RestBindingAdvice implements 
CamelInternalProcessorAdvice<Map<Strin
                 }
             }
             if (requiredQueryParameters != null
-                    && 
!exchange.getIn().getHeaders().keySet().containsAll(requiredQueryParameters)) {
+                && 
!exchange.getIn().getHeaders().keySet().containsAll(requiredQueryParameters)) {
                 // this is a bad request, the client did not include some 
required query parameters
                 exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 
400);
                 exchange.getMessage().setBody("Some of the required query 
parameters are missing.");
@@ -585,4 +584,13 @@ public class RestBindingAdvice implements 
CamelInternalProcessorAdvice<Map<Strin
         }
     }
 
+    @Override
+    protected void doStart() throws Exception {
+        ServiceHelper.startService(jsonUnmarshal, xmlUnmarshal, jsonMarshal, 
xmlMarshal);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        ServiceHelper.stopService(jsonUnmarshal, xmlUnmarshal, jsonMarshal, 
xmlMarshal);
+    }
 }

Reply via email to