From 396cf76ef51b33af091efd7e32cdd55fcd21e280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 15 Oct 2015 16:10:30 -0500 Subject: [PATCH 1/2] Add spring.jersey.path property Provide a property to customize the application path that serves as the base URI for a JAX-RS compliant application. If both `spring.jersey.path` and an `@ApplicationPath` are present, the property takes precedence. Closes gh-4201 --- .../jersey/JerseyAutoConfiguration.java | 25 ++++- .../jersey/JerseyProperties.java | 14 +++ ...figurationWithoutApplicationPathTests.java | 103 ++++++++++++++++++ 3 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationWithoutApplicationPathTests.java diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java index b7697b0422..fbe2b3ce0b 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java @@ -48,6 +48,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.util.StringUtils; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.filter.RequestContextFilter; @@ -56,6 +57,7 @@ import org.springframework.web.filter.RequestContextFilter; * * @author Dave Syer * @author Andy Wilkinson + * @author Eddú Meléndez */ @Configuration @ConditionalOnClass(name = { "org.glassfish.jersey.server.spring.SpringComponentProvider", @@ -77,8 +79,13 @@ public class JerseyAutoConfiguration implements WebApplicationInitializer { @PostConstruct public void path() { - this.path = findPath(AnnotationUtils.findAnnotation(this.config.getClass(), - ApplicationPath.class)); + if (StringUtils.hasLength(this.jersey.getPath())) { + this.path = parsePath(this.jersey.getPath()); + } + else { + this.path = findPath(AnnotationUtils.findAnnotation(this.config.getClass(), + ApplicationPath.class)); + } } @Bean @@ -144,9 +151,15 @@ public class JerseyAutoConfiguration implements WebApplicationInitializer { return "/*"; } String path = annotation.value(); - if (!path.startsWith("/")) { - path = "/" + path; - } - return path.equals("/") ? "/*" : path + "/*"; + + return parsePath(path); } + + private static String parsePath(String applicationPath) { + if (!applicationPath.startsWith("/")) { + applicationPath = "/" + applicationPath; + } + return applicationPath.equals("/") ? "/*" : applicationPath + "/*"; + } + } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyProperties.java index 4778342703..1a81cfcf47 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyProperties.java @@ -25,6 +25,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * {@link ConfigurationProperties} for Jersey. * * @author Dave Syer + * @author Eddú Meléndez * @since 1.2.0 */ @ConfigurationProperties("spring.jersey") @@ -42,6 +43,11 @@ public class JerseyProperties { private Filter filter = new Filter(); + /** + * Path at which the application will be available. + */ + private String path; + public Filter getFilter() { return this.filter; } @@ -66,6 +72,14 @@ public class JerseyProperties { this.init = init; } + public String getPath() { + return this.path; + } + + public void setPath(String path) { + this.path = path; + } + public enum Type { SERVLET, FILTER } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationWithoutApplicationPathTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationWithoutApplicationPathTests.java new file mode 100644 index 0000000000..17f449960f --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationWithoutApplicationPathTests.java @@ -0,0 +1,103 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed 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.springframework.boot.autoconfigure.jersey; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +import org.glassfish.jersey.server.ResourceConfig; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfigurationCustomServletPathTests.Application; +import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; +import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration; +import org.springframework.boot.test.IntegrationTest; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.boot.test.TestRestTemplate; +import org.springframework.context.annotation.Import; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.web.client.RestTemplate; + +import static org.junit.Assert.assertEquals; + +/** + * Tests for {@link JerseyAutoConfiguration} when using custom application path. + * + * @author Eddú Meléndez + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(Application.class) +@IntegrationTest({ "server.port=0", "spring.jersey.path=/rest" }) +@WebAppConfiguration +public class JerseyAutoConfigurationWithoutApplicationPathTests { + + @Value("${local.server.port}") + private int port; + + private RestTemplate restTemplate = new TestRestTemplate(); + + @Test + public void contextLoads() { + ResponseEntity entity = this.restTemplate.getForEntity( + "http://localhost:" + this.port + "/rest/hello", String.class); + assertEquals(HttpStatus.OK, entity.getStatusCode()); + } + + @MinimalWebConfiguration + @Path("/hello") + public static class Application extends ResourceConfig { + + @Value("${message:World}") + private String msg; + + @GET + public String message() { + return "Hello " + this.msg; + } + + public Application() { + register(Application.class); + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + } + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @Documented + @Import({ EmbeddedServletContainerAutoConfiguration.class, + ServerPropertiesAutoConfiguration.class, JerseyAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class }) + protected @interface MinimalWebConfiguration { + } + +} From bc0eb996ffb830d78309c2acb9044a14201a2081 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 20 Oct 2015 11:35:35 +0200 Subject: [PATCH 2/2] Polish contribution Closes gh-4202 --- .../jersey/JerseyAutoConfiguration.java | 14 ++++++-------- .../autoconfigure/jersey/JerseyProperties.java | 13 +++++++------ ...toConfigurationWithoutApplicationPathTests.java | 5 +++-- .../asciidoc/appendix-application-properties.adoc | 1 + 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java index fbe2b3ce0b..cabb7ace0d 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java @@ -79,11 +79,11 @@ public class JerseyAutoConfiguration implements WebApplicationInitializer { @PostConstruct public void path() { - if (StringUtils.hasLength(this.jersey.getPath())) { - this.path = parsePath(this.jersey.getPath()); + if (StringUtils.hasLength(this.jersey.getApplicationPath())) { + this.path = parseApplicationPath(this.jersey.getApplicationPath()); } else { - this.path = findPath(AnnotationUtils.findAnnotation(this.config.getClass(), + this.path = findApplicationPath(AnnotationUtils.findAnnotation(this.config.getClass(), ApplicationPath.class)); } } @@ -145,17 +145,15 @@ public class JerseyAutoConfiguration implements WebApplicationInitializer { servletContext.setInitParameter("contextConfigLocation", ""); } - private static String findPath(ApplicationPath annotation) { + private static String findApplicationPath(ApplicationPath annotation) { // Jersey doesn't like to be the default servlet, so map to /* as a fallback if (annotation == null) { return "/*"; } - String path = annotation.value(); - - return parsePath(path); + return parseApplicationPath(annotation.value()); } - private static String parsePath(String applicationPath) { + private static String parseApplicationPath(String applicationPath) { if (!applicationPath.startsWith("/")) { applicationPath = "/" + applicationPath; } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyProperties.java index 1a81cfcf47..1bfcf2f026 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyProperties.java @@ -44,9 +44,10 @@ public class JerseyProperties { private Filter filter = new Filter(); /** - * Path at which the application will be available. + * Path that serves as the base URI for the application. Overrides + * the value of "@ApplicationPath" if specified. */ - private String path; + private String applicationPath; public Filter getFilter() { return this.filter; @@ -72,12 +73,12 @@ public class JerseyProperties { this.init = init; } - public String getPath() { - return this.path; + public String getApplicationPath() { + return this.applicationPath; } - public void setPath(String path) { - this.path = path; + public void setApplicationPath(String applicationPath) { + this.applicationPath = applicationPath; } public enum Type { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationWithoutApplicationPathTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationWithoutApplicationPathTests.java index 17f449960f..f28645ba34 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationWithoutApplicationPathTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationWithoutApplicationPathTests.java @@ -28,6 +28,7 @@ import javax.ws.rs.Path; import org.glassfish.jersey.server.ResourceConfig; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; @@ -53,7 +54,7 @@ import static org.junit.Assert.assertEquals; */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(Application.class) -@IntegrationTest({ "server.port=0", "spring.jersey.path=/rest" }) +@IntegrationTest({ "server.port=0", "spring.jersey.application-path=/api" }) @WebAppConfiguration public class JerseyAutoConfigurationWithoutApplicationPathTests { @@ -65,7 +66,7 @@ public class JerseyAutoConfigurationWithoutApplicationPathTests { @Test public void contextLoads() { ResponseEntity entity = this.restTemplate.getForEntity( - "http://localhost:" + this.port + "/rest/hello", String.class); + "http://localhost:" + this.port + "/api/hello", String.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); } diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index c64e6c6938..bee30dea65 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -282,6 +282,7 @@ content into your application; rather pick only the properties that you need. spring.mustache.view-names= # whitelist of view names that can be resolved # JERSEY ({sc-spring-boot-autoconfigure}}/jersey/JerseyProperties.{sc-ext}[JerseyProperties]) + spring.jersey.application-path # path that serves as the base URI for the application spring.jersey.type=servlet # servlet or filter spring.jersey.init= # init params spring.jersey.filter.order=