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 2941c6725eca3307a136779cbb86acdf440a9c92 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Apr 3 12:26:15 2024 +0200 CAMEL-20557: Rest DSL to use openapi spec directly --- .../apache/camel/processor/RestBindingAdvice.java | 55 ------ .../camel/reifier/rest/RestBindingReifier.java | 203 +++------------------ .../support/processor/RestBindingFactory.java | 27 +-- .../support/processor/RestBindingSupport.java | 33 ++-- 4 files changed, 56 insertions(+), 262 deletions(-) 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 deleted file mode 100644 index 0bb4a6d7406..00000000000 --- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java +++ /dev/null @@ -1,55 +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 - * - * 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.processor; - -import java.util.Map; -import java.util.Set; - -import org.apache.camel.CamelContext; -import org.apache.camel.spi.CamelInternalProcessorAdvice; -import org.apache.camel.spi.DataFormat; -import org.apache.camel.support.processor.RestBindingSupport; - -/** - * 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} - */ -@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, - boolean enableNoContentResponse, - Map<String, String> corsHeaders, Map<String, String> queryDefaultValues, - boolean requiredBody, Set<String> requiredQueryParameters, - Set<String> requiredHeaders) throws Exception { - - 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 20b9cf309c1..e7dcb142e30 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 @@ -16,20 +16,15 @@ */ package org.apache.camel.reifier.rest; -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.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.PluginHelper; -import org.apache.camel.support.PropertyBindingSupport; +import org.apache.camel.support.processor.RestBindingConfiguration; +import org.apache.camel.support.processor.RestBindingFactory; +import org.apache.camel.support.processor.RestBindingSupport; public class RestBindingReifier extends AbstractReifier { @@ -40,202 +35,48 @@ public class RestBindingReifier extends AbstractReifier { this.definition = definition; } - public RestBindingAdvice createRestBindingAdvice() throws Exception { - // TODO: Use RestBindingFactory - + public RestBindingSupport createRestBindingAdvice() throws Exception { RestConfiguration config = CamelContextHelper.getRestConfiguration(camelContext, definition.getComponent()); + RestBindingConfiguration rbc = new RestBindingConfiguration(); // these options can be overridden per rest verb String mode = config.getBindingMode().name(); if (definition.getBindingMode() != null) { mode = parse(RestBindingMode.class, definition.getBindingMode()).name(); } + rbc.setBindingMode(mode); boolean cors = config.isEnableCORS(); if (definition.getEnableCORS() != null) { cors = parseBoolean(definition.getEnableCORS(), false); } + rbc.setEnableCORS(cors); boolean noContentResponse = config.isEnableNoContentResponse(); if (definition.getEnableNoContentResponse() != null) { noContentResponse = parseBoolean(definition.getEnableNoContentResponse(), false); } + rbc.setEnableNoContentResponse(noContentResponse); boolean skip = config.isSkipBindingOnErrorCode(); if (definition.getSkipBindingOnErrorCode() != null) { skip = parseBoolean(definition.getSkipBindingOnErrorCode(), false); } + rbc.setSkipBindingOnErrorCode(skip); boolean validation = config.isClientRequestValidation(); 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(); - - if ("off".equals(mode)) { - // binding mode is off, so create off mode binding processor - return new RestBindingAdvice( - camelContext, null, null, null, null, - consumes, produces, mode, skip, validation, cors, - noContentResponse, corsHeaders, - definition.getDefaultValues(), definition.getRequiredBody() != null ? definition.getRequiredBody() : false, - definition.getRequiredQueryParameters(), definition.getRequiredHeaders()); - } - - // setup json data format - DataFormat json = null; - DataFormat outJson = null; - if (mode.contains("json") || "auto".equals(mode)) { - String name = config.getJsonDataFormat(); - if (name != null) { - // must only be a name, not refer to an existing instance - Object instance = lookupByName(name); - if (instance != null) { - throw new IllegalArgumentException( - "JsonDataFormat name: " + name + " must not be an existing bean instance from the registry"); - } - } else { - name = "jackson"; - } - // this will create a new instance as the name was not already - // pre-created - json = camelContext.createDataFormat(name); - outJson = camelContext.createDataFormat(name); - - if (json != null) { - setupJson( - config, - parseString(definition.getType()), definition.getTypeClass(), - parseString(definition.getOutType()), definition.getOutTypeClass(), - json, outJson); - } - } - - // setup xml data format - DataFormat jaxb = null; - DataFormat outJaxb = null; - if (mode.contains("xml") || "auto".equals(mode)) { - String name = config.getXmlDataFormat(); - if (name != null) { - // must only be a name, not refer to an existing instance - Object instance = lookupByName(name); - if (instance != null) { - throw new IllegalArgumentException( - "XmlDataFormat name: " + name + " must not be an existing bean instance from the registry"); - } - } else { - name = "jaxb"; - } - // this will create a new instance as the name was not already - // pre-created - jaxb = camelContext.createDataFormat(name); - outJaxb = camelContext.createDataFormat(name); - - // is xml binding required? - if (mode.contains("xml") && jaxb == null) { - throw new IllegalArgumentException("XML DataFormat " + name + " not found."); - } - - 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); - } - } - - return new RestBindingAdvice( - 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()); - } - - @Deprecated - protected void setupJson( - RestConfiguration config, String type, Class<?> typeClass, String outType, Class<?> outTypeClass, DataFormat json, - DataFormat outJson) - throws Exception { - Class<?> clazz = null; - boolean useList = false; - - if (typeClass != null) { - useList = typeClass.isArray(); - clazz = useList ? typeClass.getComponentType() : typeClass; - } else if (type != null) { - useList = type.endsWith("[]"); - String typeName = useList ? type.substring(0, type.length() - 2) : type; - clazz = camelContext.getClassResolver().resolveMandatoryClass(typeName); - } - final BeanIntrospection beanIntrospection = PluginHelper.getBeanIntrospection(camelContext); - if (clazz != null) { - beanIntrospection.setProperty(camelContext, json, - "unmarshalType", clazz); - beanIntrospection.setProperty(camelContext, json, "useList", - useList); - } - - setAdditionalConfiguration(config, json, "json.in."); - - Class<?> outClazz = null; - boolean outUseList = false; - - if (outTypeClass != null) { - outUseList = outTypeClass.isArray(); - outClazz = outUseList ? outTypeClass.getComponentType() : outTypeClass; - } else if (outType != null) { - outUseList = outType.endsWith("[]"); - String typeName = outUseList ? outType.substring(0, outType.length() - 2) : outType; - outClazz = camelContext.getClassResolver().resolveMandatoryClass(typeName); - } - - if (outClazz != null) { - beanIntrospection.setProperty(camelContext, outJson, - "unmarshalType", outClazz); - beanIntrospection.setProperty(camelContext, outJson, "useList", - outUseList); - } - - 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 - // introspection setProperties - Map<String, Object> copy = new HashMap<>(); - - // filter keys on prefix - // - either its a known prefix and must match the prefix parameter - // - or its a common configuration that we should always use - for (Map.Entry<String, Object> entry : config.getDataFormatProperties().entrySet()) { - String key = entry.getKey(); - String copyKey; - boolean known = isKeyKnownPrefix(key); - if (known) { - // remove the prefix from the key to use - copyKey = key.substring(prefix.length()); - } else { - // use the key as is - copyKey = key; - } - if (!known || key.startsWith(prefix)) { - copy.put(copyKey, entry.getValue()); - } - } - - PropertyBindingSupport.build().bind(camelContext, dataFormat, copy); - } - } - - @Deprecated - private boolean isKeyKnownPrefix(String key) { - return key.startsWith("json.in.") || key.startsWith("json.out.") || key.startsWith("xml.in.") - || key.startsWith("xml.out."); + rbc.setClientRequestValidation(validation); + rbc.setRequiredBody(definition.getRequiredBody() != null && definition.getRequiredBody()); + rbc.setConsumes(parseString(definition.getConsumes())); + rbc.setProduces(parseString(definition.getProduces())); + rbc.setCorsHeaders(config.getCorsHeaders()); + rbc.setRequiredQueryParameters(definition.getRequiredQueryParameters()); + rbc.setQueryDefaultValues(definition.getDefaultValues()); + rbc.setType(parseString(definition.getType())); + rbc.setTypeClass(definition.getTypeClass()); + rbc.setOutType(parseString(definition.getOutType())); + rbc.setOutTypeClass(definition.getOutTypeClass()); + + return RestBindingFactory.build(camelContext, rbc); } } diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingFactory.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingFactory.java index b1d9072d05f..a6a387680d1 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingFactory.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingFactory.java @@ -33,20 +33,21 @@ import org.apache.camel.support.PropertyBindingSupport; public class RestBindingFactory { public static RestBindingSupport build(CamelContext camelContext, RestBindingConfiguration bc) throws Exception { - RestConfiguration config = camelContext.getRestConfiguration(); - String mode = config.getBindingMode().name(); + String mode = bc.getBindingMode(); if ("off".equals(mode)) { // binding mode is off, so create off mode binding processor return new RestBindingSupport( camelContext, null, null, null, null, - bc.getConsumes(), bc.getProduces(), mode, bc.isSkipBindingOnErrorCode(), bc.isClientRequestValidation(), bc.isEnableCORS(), + 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 + RestConfiguration config = camelContext.getRestConfiguration(); DataFormat json = null; DataFormat outJson = null; if (mode.contains("json") || "auto".equals(mode)) { @@ -101,23 +102,24 @@ public class RestBindingFactory { if (jaxb != null) { // to setup JAXB we need to use camel-jaxb - PluginHelper.getRestBindingJaxbDataFormatFactory(camelContext). - setupJaxb(camelContext, config, - bc.getType(), bc.getTypeClass(), - bc.getOutType(), bc.getOutTypeClass(), - jaxb, outJaxb); + PluginHelper.getRestBindingJaxbDataFormatFactory(camelContext).setupJaxb(camelContext, config, + bc.getType(), bc.getTypeClass(), + bc.getOutType(), bc.getOutTypeClass(), + jaxb, outJaxb); } } return new RestBindingSupport( camelContext, json, jaxb, outJson, outJaxb, - bc.getConsumes(), bc.getProduces(), mode, bc.isSkipBindingOnErrorCode(), bc.isClientRequestValidation(), bc.isEnableCORS(), + bc.getConsumes(), bc.getProduces(), mode, bc.isSkipBindingOnErrorCode(), bc.isClientRequestValidation(), + bc.isEnableCORS(), bc.isEnableNoContentResponse(), bc.getCorsHeaders(), bc.getQueryDefaultValues(), bc.isRequiredBody(), bc.getRequiredQueryParameters(), bc.getRequiredHeaders()); } - protected static void setupJson(CamelContext camelContext, + protected static void setupJson( + CamelContext camelContext, RestConfiguration config, String type, Class<?> typeClass, String outType, Class<?> outTypeClass, DataFormat json, DataFormat outJson) throws Exception { @@ -164,7 +166,8 @@ public class RestBindingFactory { setAdditionalConfiguration(camelContext, config, outJson, "json.out."); } - private static void setAdditionalConfiguration(CamelContext camelContext, 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 @@ -195,7 +198,7 @@ public class RestBindingFactory { 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) { diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingSupport.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingSupport.java index f7ca71d7515..b7f521450fc 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingSupport.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingSupport.java @@ -16,6 +16,11 @@ */ package org.apache.camel.support.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; @@ -34,15 +39,15 @@ 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; /** * Used for Rest DSL with binding to json/xml for incoming requests and outgoing responses. + * <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} * * @see RestBindingFactory */ @@ -75,14 +80,14 @@ public class RestBindingSupport extends ServiceSupport implements CamelInternalP * 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, - boolean enableNoContentResponse, - Map<String, String> corsHeaders, - Map<String, String> queryDefaultValues, - boolean requiredBody, Set<String> requiredQueryParameters, - Set<String> requiredHeaders) throws Exception { + DataFormat outJsonDataFormat, DataFormat outXmlDataFormat, + String consumes, String produces, String bindingMode, + boolean skipBindingOnErrorCode, boolean clientRequestValidation, boolean enableCORS, + boolean enableNoContentResponse, + 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); @@ -285,7 +290,7 @@ public class RestBindingSupport extends ServiceSupport implements CamelInternalP } } 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.");