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 09386849b2..3c30ecdb71 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 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. @@ -24,8 +24,12 @@ import javax.annotation.PostConstruct; import javax.servlet.DispatcherType; import javax.servlet.ServletContext; import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; import javax.ws.rs.ApplicationPath; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.glassfish.jersey.CommonProperties; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; import org.glassfish.jersey.servlet.ServletProperties; @@ -49,8 +53,10 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.Order; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.web.WebApplicationInitializer; +import org.springframework.web.context.ServletContextAware; import org.springframework.web.filter.RequestContextFilter; /** @@ -68,7 +74,9 @@ import org.springframework.web.filter.RequestContextFilter; @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @AutoConfigureBefore(DispatcherServletAutoConfiguration.class) @EnableConfigurationProperties(JerseyProperties.class) -public class JerseyAutoConfiguration { +public class JerseyAutoConfiguration implements ServletContextAware { + + private static final Log logger = LogFactory.getLog(JerseyAutoConfiguration.class); @Autowired private JerseyProperties jersey; @@ -129,10 +137,14 @@ public class JerseyAutoConfiguration { ServletRegistrationBean registration = new ServletRegistrationBean( new ServletContainer(this.config), this.path); addInitParameters(registration); - registration.setName("jerseyServlet"); + registration.setName(getServletRegistrationName()); return registration; } + private String getServletRegistrationName() { + return ClassUtils.getUserClass(this.config.getClass()).getName(); + } + private void addInitParameters(RegistrationBean registration) { for (Entry entry : this.jersey.getInit().entrySet()) { registration.addInitParameter(entry.getKey(), entry.getValue()); @@ -154,6 +166,23 @@ public class JerseyAutoConfiguration { return applicationPath.equals("/") ? "/*" : applicationPath + "/*"; } + @Override + public void setServletContext(ServletContext servletContext) { + String servletRegistrationName = getServletRegistrationName(); + ServletRegistration registration = servletContext + .getServletRegistration(servletRegistrationName); + if (registration != null) { + if (logger.isInfoEnabled()) { + logger.info("Configuring existing registration for Jersey servlet '" + + servletRegistrationName + "'"); + } + registration.setInitParameters(this.jersey.getInit()); + registration.setInitParameter( + CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, + Boolean.TRUE.toString()); + } + } + @Order(Ordered.HIGHEST_PRECEDENCE) public static final class JerseyWebApplicationInitializer implements WebApplicationInitializer { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationServletContainerTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationServletContainerTests.java new file mode 100644 index 0000000000..2dbc32c38b --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationServletContainerTests.java @@ -0,0 +1,120 @@ +/* + * Copyright 2012-2016 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 javax.ws.rs.GET; +import javax.ws.rs.Path; + +import org.apache.catalina.Context; +import org.apache.catalina.Wrapper; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.servlet.ServletContainer; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfigurationServletContainerTests.Application; +import org.springframework.boot.autoconfigure.test.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; +import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration; +import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.boot.test.IntegrationTest; +import org.springframework.boot.test.OutputCapture; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertThat; + +/** + * Tests that verify the behavior when deployed to a Servlet container where Jersey may + * have already initialized itself. + * + * @author Andy Wilkinson + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(Application.class) +@IntegrationTest("server.port=0") +@WebAppConfiguration +public class JerseyAutoConfigurationServletContainerTests { + + @ClassRule + public static OutputCapture output = new OutputCapture(); + + @Value("${local.server.port}") + private int port; + + @Test + public void existingJerseyServletIsAmended() { + assertThat(output.toString(), + containsString("Configuring existing registration for Jersey servlet")); + assertThat(output.toString(), containsString( + "Servlet " + Application.class.getName() + " was not registered")); + } + + @ImportAutoConfiguration({ EmbeddedServletContainerAutoConfiguration.class, + ServerPropertiesAutoConfiguration.class, JerseyAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class }) + @Import(ContainerConfiguration.class) + @Path("/hello") + public static class Application extends ResourceConfig { + + @Value("${message:World}") + private String msg; + + public Application() { + register(Application.class); + } + + @GET + public String message() { + return "Hello " + this.msg; + } + + } + + @Configuration + public static class ContainerConfiguration { + + @Bean + public TomcatEmbeddedServletContainerFactory tomcat() { + return new TomcatEmbeddedServletContainerFactory() { + + @Override + protected void postProcessContext(Context context) { + Wrapper jerseyServlet = context.createWrapper(); + String servletName = Application.class.getName(); + jerseyServlet.setName(servletName); + jerseyServlet.setServletClass(ServletContainer.class.getName()); + jerseyServlet.setServlet(new ServletContainer()); + jerseyServlet.setOverridable(false); + context.addChild(jerseyServlet); + context.addServletMapping("/*", servletName); + } + + }; + } + + } + +}