private void unmarshal()

in core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java [166:371]


    private void unmarshal(Exchange exchange, Map<String, Object> state) throws Exception {
        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));
            }
        }

    }