Camel - Rest: request/response data type judgement
binding mode
org.apache.camel.reifier.rest.RestBindingReifier#createRestBindingAdvice
public RestBindingAdvice createRestBindingAdvice() throws Exception {
RestConfiguration config = CamelContextHelper.getRestConfiguration(camelContext, definition.getComponent());
// these options can be overridden per rest verb
String mode = config.getBindingMode().name();
if (definition.getBindingMode() != null) {
mode = parse(RestBindingMode.class, definition.getBindingMode()).name();
}
// omit
if ("off".equals(mode)) {
// binding mode is off, so create a off mode binding processor
return new RestBindingAdvice(
camelContext, null, null, null, null,
parseString(definition.getConsumes()), parseString(definition.getProduces()), mode, skip, validation, cors,
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 = "json-jackson";
}
// this will create a new instance as the name was not already
// pre-created
json = camelContext.resolveDataFormat(name);
outJson = camelContext.resolveDataFormat(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.resolveDataFormat(name);
outJaxb = camelContext.resolveDataFormat(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
camelContext.adapt(ExtendedCamelContext.class).getRestBindingJaxbDataFormatFactory().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, corsHeaders,
definition.getDefaultValues(), definition.getRequiredBody() != null ? definition.getRequiredBody() : false,
definition.getRequiredQueryParameters(), definition.getRequiredHeaders());
}
unmarshal
org.apache.camel.processor.RestBindingAdvice#unmarshal
判定请求内容格式的逻辑
boolean isXml = false;
boolean isJson = false;
// 判定contentType,如果contentType包含xml,设置isXml = true, 如果contentType包含json,设置isJson = true
String contentType = ExchangeHelper.getContentType(exchange);
if (contentType != null) {
isXml = contentType.toLowerCase(Locale.ENGLISH).contains("xml");
isJson = contentType.toLowerCase(Locale.ENGLISH).contains("json");
}
// 如果content type没有告诉我们是xml还是json,则根据consumers配置检查请求内容类型;
// 如果consumers包含xml,设置 isXml = true; 如果consumers包含json,设置 isJson = true;
if (!isXml && !isJson) {
isXml = consumes != null && consumes.toLowerCase(Locale.ENGLISH).contains("xml");
isJson = consumes != null && consumes.toLowerCase(Locale.ENGLISH).contains("json");
}
// 如果请求内容是DataTypeAware类型,则设置data type
if (exchange.getContext().isUseDataType()) {
if (exchange.getIn() instanceof DataTypeAware && (isJson || isXml)) {
((DataTypeAware) exchange.getIn()).setDataType(new DataType(isJson ? "json" : "xml"));
}
}
// 只有bindMode为auto或xml时,isXml的值才有效
// 只有bindMode为auto或json时,isJson的值才有效
isXml &= bindingMode.equals("auto") || bindingMode.contains("xml");
isJson &= bindingMode.equals("auto") || bindingMode.contains("json");
// 如果此时 isXml、isJson的值均为false,则根据bindMode获取请求内容格式
// 如果bindMode为auto或xml时,isXml = true
// 如果bindMode为auto或json时,isJson = true
if (!isJson && !isXml) {
isXml = bindingMode.equals("auto") || bindingMode.contains("xml");
isJson = bindingMode.equals("auto") || bindingMode.contains("json");
}
// 如果 isXml和isJson 的值均为true,则根据请求内容判定请求格式,如果是以<开始,则 isXml = true; 否则 isXml = true;
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;
}
}
}
}
marshal
boolean isXml = false;
boolean isJson = false;
// 如果accept包含xml,isXml = true; 如果accept包含json, isXml = true;
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");
}
// 如果无法判定响应类型,根据content type判定响应类型,如果content type包含xml,isXml = true; 如果content type包含json,isJson = ture
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");
}
}
// 如果无法判定响应类型,则根据配置producers判断响应类型,如果producers包含xml,isXml = ture; 如果producers包含json,isJson = true
if (!isXml && !isJson) {
isXml = produces != null && produces.toLowerCase(Locale.ENGLISH).contains("xml");
isJson = produces != null && produces.toLowerCase(Locale.ENGLISH).contains("json");
}
// 只有在binding mode允许的情况下,isXml和isJson的值才能生效(当binding mode关闭的情况下isXml、isJson的值仍然生效)
if (bindingMode != null) {
isXml &= bindingMode.equals("off") || bindingMode.equals("auto") || bindingMode.contains("xml");
isJson &= bindingMode.equals("off") || bindingMode.equals("auto") || bindingMode.contains("json");
// 如果此时尚未判定响应内容的值,则根据binding mode的值进行判定。如果binding mode的值是auto或xml,则isXml = true,如果binding mode的值是auto或json,则isJson = true
if (!isJson && !isXml) {
isXml = bindingMode.equals("auto") || bindingMode.contains("xml");
isJson = bindingMode.equals("auto") || bindingMode.contains("json");
}
}
// 如果此时仍然不能决定响应类型,则取请求内容的类型
if (isXml && isJson) {
isXml = state.get(STATE_KEY_DO_MARSHAL).equals(STATE_XML);
isJson = !isXml;
}