Repository: camel Updated Branches: refs/heads/master a6543970c -> f44872085
CAMEL-8528: rest-dsl should do more to ensure content-type header is set in the response. If none explict has been set, then use all the information from the rest-dsl configuration and binding to best effort guess if its json or xml. Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/dff9cd89 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/dff9cd89 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/dff9cd89 Branch: refs/heads/master Commit: dff9cd8924274f11356910bcb321c613c82dff7f Parents: a654397 Author: Claus Ibsen <davscl...@apache.org> Authored: Mon Sep 28 11:49:50 2015 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Mon Sep 28 11:55:33 2015 +0200 ---------------------------------------------------------------------- .../processor/binding/RestBindingProcessor.java | 103 ++++++++++--------- .../rest/FromRestGetContentTypeTest.java | 62 +++++++++++ 2 files changed, 117 insertions(+), 48 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/dff9cd89/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java index df5e5e1..f901f31 100644 --- a/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java +++ b/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java @@ -112,23 +112,9 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess exchange.addOnCompletion(new RestBindingCORSOnCompletion(corsHeaders)); } - if (bindingMode == null || "off".equals(bindingMode)) { - // binding is off - callback.done(true); - return true; - } - - // is there any unmarshaller at all - if (jsonUnmarshal == null && xmlUnmarshal == null) { - callback.done(true); - return true; - } - boolean isXml = false; boolean isJson = false; - String accept = exchange.getIn().getHeader("Accept", String.class); - String contentType = ExchangeHelper.getContentType(exchange); if (contentType != null) { isXml = contentType.toLowerCase(Locale.ENGLISH).contains("xml"); @@ -151,8 +137,9 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess isJson = bindingMode.equals("auto") || bindingMode.contains("json"); } - String body = null; + String accept = exchange.getIn().getHeader("Accept", String.class); + 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 @@ -195,7 +182,7 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess } // we could not bind - if (bindingMode.equals("auto")) { + if (bindingMode == null || "off".equals(bindingMode) || bindingMode.equals("auto")) { // okay for auto we do not mind if we could not bind exchange.addOnCompletion(new RestBindingMarshalOnCompletion(exchange.getFromRouteId(), jsonMarshal, xmlMarshal, false, accept)); callback.done(true); @@ -282,21 +269,6 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess } } - if (bindingMode == null || "off".equals(bindingMode)) { - // binding is off - return; - } - - // is there any marshaller at all - if (jsonMarshal == null && xmlMarshal == null) { - return; - } - - // is the body empty - if ((exchange.hasOut() && exchange.getOut().getBody() == null) || (!exchange.hasOut() && exchange.getIn().getBody() == null)) { - return; - } - boolean isXml = false; boolean isJson = false; @@ -320,14 +292,16 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess isJson = produces != null && produces.toLowerCase(Locale.ENGLISH).contains("json"); } - // only allow xml/json if the binding mode allows that - isXml &= bindingMode.equals("auto") || bindingMode.contains("xml"); - isJson &= bindingMode.equals("auto") || bindingMode.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"); + // 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 @@ -339,21 +313,29 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess // 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.hasOut() && exchange.getOut().getBody() == null) || (!exchange.hasOut() && exchange.getIn().getBody() == null)) { + return; + } + try { // favor json over xml if (isJson && jsonMarshal != null) { - // 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"); - } jsonMarshal.process(exchange); } else if (isXml && xmlMarshal != null) { - // 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"); - } xmlMarshal.process(exchange); } else { // we could not bind @@ -372,6 +354,31 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess } } + 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"); + } + } + } + @Override public String toString() { return "RestBindingMarshalOnCompletion"; http://git-wip-us.apache.org/repos/asf/camel/blob/dff9cd89/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetContentTypeTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetContentTypeTest.java b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetContentTypeTest.java new file mode 100644 index 0000000..e82e99e --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetContentTypeTest.java @@ -0,0 +1,62 @@ +/** + * 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.component.rest; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.JndiRegistry; + +public class FromRestGetContentTypeTest extends ContextTestSupport { + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry jndi = super.createRegistry(); + jndi.bind("dummy-rest", new DummyRestConsumerFactory()); + return jndi; + } + + public void testFromRestModelContentType() throws Exception { + Exchange out = template.request("seda:get-say-hello", new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + + } + }); + + assertNotNull(out); + assertEquals("{ \"name\" : \"Donald\" }", out.getOut().getBody()); + assertEquals("application/json", out.getOut().getHeader(Exchange.CONTENT_TYPE)); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + restConfiguration().host("localhost"); + + rest("/say/hello").produces("application/json") + .get().to("direct:hello"); + + from("direct:hello").setBody(constant("{ \"name\" : \"Donald\" }")); + + } + }; + } +}