in core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java [180:331]
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);
// 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());
}
}
}
// perform client request validation
if (clientRequestValidation) {
RestClientRequestValidator.ValidationContext vc = new RestClientRequestValidator.ValidationContext(
consumes, produces, requiredBody, queryDefaultValues, queryAllowedValues, requiredQueryParameters,
requiredHeaders);
RestClientRequestValidator.ValidationError error = clientRequestValidator.validate(exchange, vc);
if (error != null) {
exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, error.statusCode());
exchange.getMessage().setBody(error.body());
exchange.setRouteStop(true);
return;
}
}
String body = null;
if (ObjectHelper.isNotEmpty(exchange.getIn().getBody())) {
// 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 (ObjectHelper.isNotEmpty(body)) {
if (exchange.getIn() instanceof DataTypeAware dataTypeAware) {
dataTypeAware.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;
}
}
}
}
// 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));
}
}
}