Skip to content

Commit e33221a

Browse files
committed
Configure existing Jersey servlet registration created by the SCI
When a Jersey app is deployed to a standalone container, Jersey’s ServletContainerInitializer will run and register a servlet for a class annotated with @ApplicationPath. If Jersey’s ServletContainerInitializer runs before Spring’s, this servlet will take precedence over the servlet registered by JerseyAutoConfiguration and will therefore not be configured with any init parameters specified using spring.jersey.init For the case where Jersey’s SCI runs first, this commit updates JerseyAutoConfiguration to examine the servlet context for an existing registration of Jersey’s servlet (Jersey names the registration using the fully-qualified name of the ResourceConfig subclass). If a registration is found its init parameters are configured using the configuration provided by spring.jersey.init. For the case where Spring’s SCI runs first, this commit updates JerseyAutoConfiguration so that it names its registration using the fully-qualified name of the ResourceConfig sub-class. This allows Jersey’s SCI to find the existing registration rather than attempting to configure its own. Closes gh-2471
1 parent 2039ed4 commit e33221a

File tree

2 files changed

+152
-3
lines changed

2 files changed

+152
-3
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2015 the original author or authors.
2+
* Copyright 2012-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,8 +24,12 @@
2424
import javax.servlet.DispatcherType;
2525
import javax.servlet.ServletContext;
2626
import javax.servlet.ServletException;
27+
import javax.servlet.ServletRegistration;
2728
import javax.ws.rs.ApplicationPath;
2829

30+
import org.apache.commons.logging.Log;
31+
import org.apache.commons.logging.LogFactory;
32+
import org.glassfish.jersey.CommonProperties;
2933
import org.glassfish.jersey.server.ResourceConfig;
3034
import org.glassfish.jersey.servlet.ServletContainer;
3135
import org.glassfish.jersey.servlet.ServletProperties;
@@ -49,8 +53,10 @@
4953
import org.springframework.core.Ordered;
5054
import org.springframework.core.annotation.AnnotationUtils;
5155
import org.springframework.core.annotation.Order;
56+
import org.springframework.util.ClassUtils;
5257
import org.springframework.util.StringUtils;
5358
import org.springframework.web.WebApplicationInitializer;
59+
import org.springframework.web.context.ServletContextAware;
5460
import org.springframework.web.filter.RequestContextFilter;
5561

5662
/**
@@ -68,7 +74,9 @@
6874
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
6975
@AutoConfigureBefore(DispatcherServletAutoConfiguration.class)
7076
@EnableConfigurationProperties(JerseyProperties.class)
71-
public class JerseyAutoConfiguration {
77+
public class JerseyAutoConfiguration implements ServletContextAware {
78+
79+
private static final Log logger = LogFactory.getLog(JerseyAutoConfiguration.class);
7280

7381
@Autowired
7482
private JerseyProperties jersey;
@@ -129,10 +137,14 @@ public ServletRegistrationBean jerseyServletRegistration() {
129137
ServletRegistrationBean registration = new ServletRegistrationBean(
130138
new ServletContainer(this.config), this.path);
131139
addInitParameters(registration);
132-
registration.setName("jerseyServlet");
140+
registration.setName(getServletRegistrationName());
133141
return registration;
134142
}
135143

144+
private String getServletRegistrationName() {
145+
return ClassUtils.getUserClass(this.config.getClass()).getName();
146+
}
147+
136148
private void addInitParameters(RegistrationBean registration) {
137149
for (Entry<String, String> entry : this.jersey.getInit().entrySet()) {
138150
registration.addInitParameter(entry.getKey(), entry.getValue());
@@ -154,6 +166,23 @@ private static String parseApplicationPath(String applicationPath) {
154166
return applicationPath.equals("/") ? "/*" : applicationPath + "/*";
155167
}
156168

169+
@Override
170+
public void setServletContext(ServletContext servletContext) {
171+
String servletRegistrationName = getServletRegistrationName();
172+
ServletRegistration registration = servletContext
173+
.getServletRegistration(servletRegistrationName);
174+
if (registration != null) {
175+
if (logger.isInfoEnabled()) {
176+
logger.info("Configuring existing registration for Jersey servlet '"
177+
+ servletRegistrationName + "'");
178+
}
179+
registration.setInitParameters(this.jersey.getInit());
180+
registration.setInitParameter(
181+
CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE,
182+
Boolean.TRUE.toString());
183+
}
184+
}
185+
157186
@Order(Ordered.HIGHEST_PRECEDENCE)
158187
public static final class JerseyWebApplicationInitializer
159188
implements WebApplicationInitializer {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright 2012-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.jersey;
18+
19+
import javax.ws.rs.GET;
20+
import javax.ws.rs.Path;
21+
22+
import org.apache.catalina.Context;
23+
import org.apache.catalina.Wrapper;
24+
import org.glassfish.jersey.server.ResourceConfig;
25+
import org.glassfish.jersey.servlet.ServletContainer;
26+
import org.junit.ClassRule;
27+
import org.junit.Test;
28+
import org.junit.runner.RunWith;
29+
30+
import org.springframework.beans.factory.annotation.Value;
31+
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
32+
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfigurationServletContainerTests.Application;
33+
import org.springframework.boot.autoconfigure.test.ImportAutoConfiguration;
34+
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
35+
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;
36+
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
37+
import org.springframework.boot.test.IntegrationTest;
38+
import org.springframework.boot.test.OutputCapture;
39+
import org.springframework.boot.test.SpringApplicationConfiguration;
40+
import org.springframework.context.annotation.Bean;
41+
import org.springframework.context.annotation.Configuration;
42+
import org.springframework.context.annotation.Import;
43+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
44+
import org.springframework.test.context.web.WebAppConfiguration;
45+
46+
import static org.hamcrest.Matchers.containsString;
47+
import static org.junit.Assert.assertThat;
48+
49+
/**
50+
* Tests that verify the behavior when deployed to a Servlet container where Jersey may
51+
* have already initialized itself.
52+
*
53+
* @author Andy Wilkinson
54+
*/
55+
@RunWith(SpringJUnit4ClassRunner.class)
56+
@SpringApplicationConfiguration(Application.class)
57+
@IntegrationTest("server.port=0")
58+
@WebAppConfiguration
59+
public class JerseyAutoConfigurationServletContainerTests {
60+
61+
@ClassRule
62+
public static OutputCapture output = new OutputCapture();
63+
64+
@Value("${local.server.port}")
65+
private int port;
66+
67+
@Test
68+
public void existingJerseyServletIsAmended() {
69+
assertThat(output.toString(),
70+
containsString("Configuring existing registration for Jersey servlet"));
71+
assertThat(output.toString(), containsString(
72+
"Servlet " + Application.class.getName() + " was not registered"));
73+
}
74+
75+
@ImportAutoConfiguration({ EmbeddedServletContainerAutoConfiguration.class,
76+
ServerPropertiesAutoConfiguration.class, JerseyAutoConfiguration.class,
77+
PropertyPlaceholderAutoConfiguration.class })
78+
@Import(ContainerConfiguration.class)
79+
@Path("/hello")
80+
public static class Application extends ResourceConfig {
81+
82+
@Value("${message:World}")
83+
private String msg;
84+
85+
public Application() {
86+
register(Application.class);
87+
}
88+
89+
@GET
90+
public String message() {
91+
return "Hello " + this.msg;
92+
}
93+
94+
}
95+
96+
@Configuration
97+
public static class ContainerConfiguration {
98+
99+
@Bean
100+
public TomcatEmbeddedServletContainerFactory tomcat() {
101+
return new TomcatEmbeddedServletContainerFactory() {
102+
103+
@Override
104+
protected void postProcessContext(Context context) {
105+
Wrapper jerseyServlet = context.createWrapper();
106+
String servletName = Application.class.getName();
107+
jerseyServlet.setName(servletName);
108+
jerseyServlet.setServletClass(ServletContainer.class.getName());
109+
jerseyServlet.setServlet(new ServletContainer());
110+
jerseyServlet.setOverridable(false);
111+
context.addChild(jerseyServlet);
112+
context.addServletMapping("/*", servletName);
113+
}
114+
115+
};
116+
}
117+
118+
}
119+
120+
}

0 commit comments

Comments
 (0)