This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new 0201758 CAMEL-12841: camel-restdsl-swagger:generate - Special case for Spring Boot with servlet component to generate CamelRestController support class to allow using root context-path and spring boot health check/actuators at the same time. 0201758 is described below commit 020175876ce3ea58744fafcd0d273ea856d79878 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Oct 2 13:36:59 2018 +0200 CAMEL-12841: camel-restdsl-swagger:generate - Special case for Spring Boot with servlet component to generate CamelRestController support class to allow using root context-path and spring boot health check/actuators at the same time. --- .../main/docs/camel-restdsl-swagger-plugin.adoc | 7 ++ .../generator/swagger/AbstractGenerateMojo.java | 52 +++++++++- .../maven/generator/swagger/GenerateMojo.java | 28 +++++- .../camel/generator/swagger/RestDslGenerator.java | 20 ++++ .../swagger/RestDslSourceCodeGenerator.java | 6 +- .../generator/swagger/RestDslXmlGenerator.java | 3 + .../SpringBootProjectSourceCodeGenerator.java | 106 +++++++++++++++++++++ .../PathSpringBootProjectSourceGeneratorTest.java | 46 +++++++++ .../generator/swagger/RestDslGeneratorTest.java | 2 +- .../generator/swagger/RestDslXmlGeneratorTest.java | 2 +- .../test/resources/SpringBootRestController.txt | 24 +++++ .../resources/SwaggerPetstoreWithRestComponent.txt | 2 +- .../SwaggerPetstoreWithRestComponentXml.txt | 2 +- 13 files changed, 291 insertions(+), 9 deletions(-) diff --git a/tooling/maven/camel-restdsl-swagger-plugin/src/main/docs/camel-restdsl-swagger-plugin.adoc b/tooling/maven/camel-restdsl-swagger-plugin/src/main/docs/camel-restdsl-swagger-plugin.adoc index f8f3ded..8f89e62 100644 --- a/tooling/maven/camel-restdsl-swagger-plugin/src/main/docs/camel-restdsl-swagger-plugin.adoc +++ b/tooling/maven/camel-restdsl-swagger-plugin/src/main/docs/camel-restdsl-swagger-plugin.adoc @@ -69,6 +69,13 @@ in the `<configuration>` tag. | `restConfiguration` | `true` | Whether to include generation of the rest configuration with detected rest component to be used. | |======================================== +=== Spring Boot Project with Servlet component + +If the Maven project is a Spring Boot project and `restConfiguration` is enabled and the servlet component +is being used as REST component, then this plugin will +autodetect the package name where the `@SpringBootApplication` main class is located, and use the same +package name for generating Rest DSL source code and a needed `CamelRestController` support class. + == camel-restdsl-swagger:generate-with-dto Works as `generate` goal but also generates DTO model classes by automatic executing diff --git a/tooling/maven/camel-restdsl-swagger-plugin/src/main/java/org/apache/camel/maven/generator/swagger/AbstractGenerateMojo.java b/tooling/maven/camel-restdsl-swagger-plugin/src/main/java/org/apache/camel/maven/generator/swagger/AbstractGenerateMojo.java index bde21a3..8dbbde7 100644 --- a/tooling/maven/camel-restdsl-swagger-plugin/src/main/java/org/apache/camel/maven/generator/swagger/AbstractGenerateMojo.java +++ b/tooling/maven/camel-restdsl-swagger-plugin/src/main/java/org/apache/camel/maven/generator/swagger/AbstractGenerateMojo.java @@ -17,16 +17,20 @@ package org.apache.camel.maven.generator.swagger; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import org.apache.camel.generator.swagger.DestinationGenerator; +import org.apache.camel.util.IOHelper; import org.apache.camel.util.ObjectHelper; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Dependency; @@ -204,8 +208,54 @@ abstract class AbstractGenerateMojo extends AbstractMojo { protected String detectCamelVersionFromClasspath() { return mavenProject.getDependencies().stream().filter( - d -> "org.apache.camel".equals(d.getGroupId()) && ObjectHelper.isNotEmpty(d.getVersion())) + d -> "org.apache.camel".equals(d.getGroupId()) && ObjectHelper.isNotEmpty(d.getVersion())) .findFirst().map(Dependency::getVersion).orElse(null); } + protected String detectSpringBootMainPackage() throws IOException { + for (String src : mavenProject.getCompileSourceRoots()) { + String d = findSpringSpringBootPackage(new File(src)); + if (d != null) { + return d; + } + } + return null; + } + + protected String findSpringSpringBootPackage(File dir) throws IOException { + File[] files = dir.listFiles(); + if (files != null) { + for (File file : files) { + if (file.getName().endsWith(".java")) { + String content = IOHelper.loadText(new FileInputStream(file)); + if (content.contains("@SpringBootApplication")) { + return grabPackageName(content); + } + } else if (file.isDirectory()) { + String packageName = findSpringSpringBootPackage(file); + if (packageName != null) { + return packageName; + } + } + } + } + return null; + } + + protected String grabPackageName(String content) { + String[] lines = content.split("\\n"); + for (String line : lines) { + line = line.trim(); + if (line.startsWith("package ")) { + line = line.substring(8); + line = line.trim(); + if (line.endsWith(";")) { + line = line.substring(0, line.length() - 1); + } + return line; + } + } + return null; + } + } diff --git a/tooling/maven/camel-restdsl-swagger-plugin/src/main/java/org/apache/camel/maven/generator/swagger/GenerateMojo.java b/tooling/maven/camel-restdsl-swagger-plugin/src/main/java/org/apache/camel/maven/generator/swagger/GenerateMojo.java index d8e62ed..33e0173 100644 --- a/tooling/maven/camel-restdsl-swagger-plugin/src/main/java/org/apache/camel/maven/generator/swagger/GenerateMojo.java +++ b/tooling/maven/camel-restdsl-swagger-plugin/src/main/java/org/apache/camel/maven/generator/swagger/GenerateMojo.java @@ -25,6 +25,7 @@ import io.swagger.parser.SwaggerParser; import org.apache.camel.generator.swagger.DestinationGenerator; import org.apache.camel.generator.swagger.RestDslGenerator; import org.apache.camel.generator.swagger.RestDslSourceCodeGenerator; +import org.apache.camel.generator.swagger.SpringBootProjectSourceCodeGenerator; import org.apache.camel.util.ObjectHelper; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; @@ -87,12 +88,16 @@ public class GenerateMojo extends AbstractGenerateMojo { generator.withDestinationGenerator(destinationGeneratorObject); } + final Path outputPath = new File(outputDirectory).toPath(); + if (restConfiguration) { String comp = detectRestComponentFromClasspath(); if (comp != null) { getLog().info("Detected Camel Rest component from classpath: " + comp); generator.withRestComponent(comp); } else { + comp = "servlet"; + // is it spring boot? String aid = "camel-servlet"; if (detectSpringBootFromClasspath()) { @@ -113,14 +118,32 @@ public class GenerateMojo extends AbstractGenerateMojo { generator.withRestComponent("servlet"); } + + // if its a spring boot project and we use servlet then we should generate additional source code + if (detectSpringBootFromClasspath() && "servlet".equals(comp)) { + try { + String pName = detectSpringBootMainPackage(); + if (pName != null) { + packageName = pName; + generator.withPackageName(packageName); + getLog().info("Detected @SpringBootApplication, and will be using its package name: " + packageName); + } + getLog().info("Generating Camel Rest Controller source with package name " + packageName + " in source directory: " + outputPath); + SpringBootProjectSourceCodeGenerator.generator().withPackageName(packageName).generate(outputPath); + // the Camel Rest Controller allows to use root as context-path + generator.withRestContextPath("/"); + } catch (final IOException e) { + throw new MojoExecutionException( + "Unable to generate Camel Rest Controller source due " + e.getMessage(), e); + } + } } if (detectSpringBootFromClasspath()) { generator.asSpringComponent(); + generator.asSpringBootProject(); } - final Path outputPath = new File(outputDirectory).toPath(); - try { getLog().info("Generating Camel DSL source in directory: " + outputPath); generator.generate(outputPath); @@ -130,5 +153,4 @@ public class GenerateMojo extends AbstractGenerateMojo { } } - } diff --git a/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslGenerator.java b/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslGenerator.java index cc21ec6..a96f2aa 100644 --- a/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslGenerator.java +++ b/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslGenerator.java @@ -35,7 +35,9 @@ public abstract class RestDslGenerator<G> { DestinationGenerator destinationGenerator = new DirectToOperationId(); OperationFilter filter = new OperationFilter(); String restComponent; + String restContextPath; boolean springComponent; + boolean springBootProject; RestDslGenerator(final Swagger swagger) { this.swagger = notNull(swagger, "swagger"); @@ -82,6 +84,15 @@ public abstract class RestDslGenerator<G> { return that; } + public G withRestContextPath(String contextPath) { + this.restContextPath = contextPath; + + @SuppressWarnings("unchecked") + final G that = (G) this; + + return that; + } + public G asSpringComponent() { this.springComponent = true; @@ -91,6 +102,15 @@ public abstract class RestDslGenerator<G> { return that; } + public G asSpringBootProject() { + this.springBootProject = true; + + @SuppressWarnings("unchecked") + final G that = (G) this; + + return that; + } + public static RestDslSourceCodeGenerator<Appendable> toAppendable(final Swagger swagger) { return new AppendableGenerator(swagger); } diff --git a/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslSourceCodeGenerator.java b/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslSourceCodeGenerator.java index c534e66..953c445 100644 --- a/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslSourceCodeGenerator.java +++ b/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslSourceCodeGenerator.java @@ -104,7 +104,11 @@ public abstract class RestDslSourceCodeGenerator<T> extends RestDslGenerator<Res if (restComponent != null) { configure.addCode("\n"); - configure.addCode("restConfiguration().component(\"" + restComponent + "\");\n\n"); + configure.addCode("restConfiguration().component(\"" + restComponent + "\")"); + if (restContextPath != null) { + configure.addCode(".contextPath(\"" + restContextPath + "\")"); + } + configure.addCode(";\n\n"); } final PathVisitor<MethodSpec> restDslStatement = new PathVisitor<>(emitter, filter, destinationGenerator()); diff --git a/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslXmlGenerator.java b/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslXmlGenerator.java index d57d340..cf74fd3 100644 --- a/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslXmlGenerator.java +++ b/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/RestDslXmlGenerator.java @@ -52,6 +52,9 @@ public class RestDslXmlGenerator extends RestDslGenerator<RestDslXmlGenerator> { if (restComponent != null) { String extra = "<restConfiguration component=\"" + restComponent + "\"/>"; + if (restContextPath != null) { + extra = "<restConfiguration component=\"" + restComponent + "\" contextPath=\"" + restContextPath + "\"/>"; + } xml = xml.replaceFirst("<rest>", extra + "\n <rest>"); } diff --git a/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/SpringBootProjectSourceCodeGenerator.java b/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/SpringBootProjectSourceCodeGenerator.java new file mode 100644 index 0000000..44a184d --- /dev/null +++ b/tooling/swagger-rest-dsl-generator/src/main/java/org/apache/camel/generator/swagger/SpringBootProjectSourceCodeGenerator.java @@ -0,0 +1,106 @@ +/** + * 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.generator.swagger; + +import java.io.IOException; +import java.nio.file.Path; +import javax.annotation.Generated; +import javax.lang.model.element.Modifier; + +import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.TypeSpec; +import org.apache.camel.util.ObjectHelper; + +import static org.apache.camel.util.StringHelper.notEmpty; + +public class SpringBootProjectSourceCodeGenerator { + + private static final String DEFAULT_INDENT = " "; + + private String indent = DEFAULT_INDENT; + + private String packageName; + + public void generate(Path destination) throws IOException { + final JavaFile javaFile = generateSourceCode(); + + javaFile.writeTo(destination); + } + + public SpringBootProjectSourceCodeGenerator withIndent(final String indent) { + this.indent = ObjectHelper.notNull(indent, "indent"); + return this; + } + + public SpringBootProjectSourceCodeGenerator withPackageName(final String packageName) { + notEmpty(packageName, "packageName"); + this.packageName = packageName; + return this; + } + + JavaFile generateSourceCode() { + notEmpty(packageName, "packageName"); + + final MethodSpec methodSpec = generateRestMethod(); + + final String classNameToUse = "CamelRestController"; + + final AnnotationSpec.Builder generatedAnnotation = AnnotationSpec.builder(Generated.class).addMember("value", + "$S", getClass().getName()); + final AnnotationSpec.Builder restAnnotation = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.RestController")); + + TypeSpec.Builder builder = TypeSpec.classBuilder(classNameToUse) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL).addMethod(methodSpec) + .addAnnotation(generatedAnnotation.build()) + .addAnnotation(restAnnotation.build()) + .addJavadoc("Forward requests to the Camel servlet so it can service REST requests.\n"); + TypeSpec generatedRestController = builder.build(); + + return JavaFile.builder(packageName, generatedRestController).indent(indent).build(); + } + + MethodSpec generateRestMethod() { + ClassName req = ClassName.bestGuess("javax.servlet.http.HttpServletRequest"); + ClassName res = ClassName.bestGuess("javax.servlet.http.HttpServletResponse"); + + final AnnotationSpec.Builder reqAnnotation = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.RequestMapping")) + .addMember("value", "\"/**\""); + + final MethodSpec.Builder forward = MethodSpec.methodBuilder("camelServlet").addModifiers(Modifier.PUBLIC) + .addParameter(req, "request") + .addParameter(res, "response") + .addAnnotation(reqAnnotation.build()) + .returns(void.class); + + forward.addCode("try {\n"); + forward.addCode(" String path = request.getRequestURI();\n"); + forward.addCode(" request.getServletContext().getRequestDispatcher(\"/camel/\" + path).forward(request, response);\n"); + forward.addCode("} catch (Exception e) {\n"); + forward.addCode(" response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\n"); + forward.addCode("}\n"); + + return forward.build(); + } + + public static SpringBootProjectSourceCodeGenerator generator() { + return new SpringBootProjectSourceCodeGenerator(); + } + +} diff --git a/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/PathSpringBootProjectSourceGeneratorTest.java b/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/PathSpringBootProjectSourceGeneratorTest.java new file mode 100644 index 0000000..2d57a1f --- /dev/null +++ b/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/PathSpringBootProjectSourceGeneratorTest.java @@ -0,0 +1,46 @@ +/** + * 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.generator.swagger; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PathSpringBootProjectSourceGeneratorTest { + + @Test + public void shouldGenerateSourceCodeWithDefaults() throws IOException, URISyntaxException { + Path path = new File("target/generated-sources").toPath(); + SpringBootProjectSourceCodeGenerator.generator().withPackageName("com.foo").generate(path); + final String generatedContent = new String(Files.readAllBytes(Paths.get("target/generated-sources/com/foo/CamelRestController.java")), StandardCharsets.UTF_8); + + final URI file = PathSpringBootProjectSourceGeneratorTest.class.getResource("/SpringBootRestController.txt").toURI(); + final String expectedContent = new String(Files.readAllBytes(Paths.get(file)), StandardCharsets.UTF_8); + + assertThat(generatedContent).isEqualTo(expectedContent); + } + +} diff --git a/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/RestDslGeneratorTest.java b/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/RestDslGeneratorTest.java index c8dcc09..579b242 100644 --- a/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/RestDslGeneratorTest.java +++ b/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/RestDslGeneratorTest.java @@ -65,7 +65,7 @@ public class RestDslGeneratorTest { public void shouldGenerateSourceCodeWithRestComponent() throws IOException, URISyntaxException { final StringBuilder code = new StringBuilder(); - RestDslGenerator.toAppendable(swagger).withGeneratedTime(generated).withRestComponent("servlet").generate(code); + RestDslGenerator.toAppendable(swagger).withGeneratedTime(generated).withRestComponent("servlet").withRestContextPath("/").generate(code); final URI file = RestDslGeneratorTest.class.getResource("/SwaggerPetstoreWithRestComponent.txt").toURI(); final String expectedContent = new String(Files.readAllBytes(Paths.get(file)), StandardCharsets.UTF_8); diff --git a/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/RestDslXmlGeneratorTest.java b/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/RestDslXmlGeneratorTest.java index 2e45203..4ad6718 100644 --- a/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/RestDslXmlGeneratorTest.java +++ b/tooling/swagger-rest-dsl-generator/src/test/java/org/apache/camel/generator/swagger/RestDslXmlGeneratorTest.java @@ -67,7 +67,7 @@ public class RestDslXmlGeneratorTest { public void shouldGenerateXmlWithRestComponent() throws Exception { final CamelContext context = new DefaultCamelContext(); - final String xml = RestDslGenerator.toXml(swagger).withRestComponent("servlet").generate(context); + final String xml = RestDslGenerator.toXml(swagger).withRestComponent("servlet").withRestContextPath("/foo").generate(context); final URI file = RestDslGeneratorTest.class.getResource("/SwaggerPetstoreWithRestComponentXml.txt").toURI(); final String expectedContent = new String(Files.readAllBytes(Paths.get(file)), StandardCharsets.UTF_8); diff --git a/tooling/swagger-rest-dsl-generator/src/test/resources/SpringBootRestController.txt b/tooling/swagger-rest-dsl-generator/src/test/resources/SpringBootRestController.txt new file mode 100644 index 0000000..0a54740 --- /dev/null +++ b/tooling/swagger-rest-dsl-generator/src/test/resources/SpringBootRestController.txt @@ -0,0 +1,24 @@ +package com.foo; + +import javax.annotation.Generated; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Forward requests to the Camel servlet so it can service REST requests. + */ +@Generated("org.apache.camel.generator.swagger.SpringBootProjectSourceCodeGenerator") +@RestController +public final class CamelRestController { + @RequestMapping("/**") + public void camelServlet(HttpServletRequest request, HttpServletResponse response) { + try { + String path = request.getRequestURI(); + request.getServletContext().getRequestDispatcher("/camel/" + path).forward(request, response); + } catch (Exception e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/tooling/swagger-rest-dsl-generator/src/test/resources/SwaggerPetstoreWithRestComponent.txt b/tooling/swagger-rest-dsl-generator/src/test/resources/SwaggerPetstoreWithRestComponent.txt index 6ccda76..fbe598b 100644 --- a/tooling/swagger-rest-dsl-generator/src/test/resources/SwaggerPetstoreWithRestComponent.txt +++ b/tooling/swagger-rest-dsl-generator/src/test/resources/SwaggerPetstoreWithRestComponent.txt @@ -15,7 +15,7 @@ public final class SwaggerPetstore extends RouteBuilder { */ public void configure() { - restConfiguration().component("servlet"); + restConfiguration().component("servlet").contextPath("/"); rest() .put("/pet") diff --git a/tooling/swagger-rest-dsl-generator/src/test/resources/SwaggerPetstoreWithRestComponentXml.txt b/tooling/swagger-rest-dsl-generator/src/test/resources/SwaggerPetstoreWithRestComponentXml.txt index bcc5cd5..85bec26 100644 --- a/tooling/swagger-rest-dsl-generator/src/test/resources/SwaggerPetstoreWithRestComponentXml.txt +++ b/tooling/swagger-rest-dsl-generator/src/test/resources/SwaggerPetstoreWithRestComponentXml.txt @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <rests xmlns="http://camel.apache.org/schema/spring"> - <restConfiguration component="servlet"/> + <restConfiguration component="servlet" contextPath="/foo"/> <rest> <put consumes="application/json,application/xml" id="updatePet" produces="application/xml,application/json" uri="/pet"> <param description="Pet object that needs to be added to the store" name="body" required="true" type="body"/>