From 3a4f1f6f39380a0624e50a7d64b034dd2ef4b363 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 3 Nov 2014 10:56:30 +0000 Subject: [PATCH] Attempt to get Jersey working as filter --- .../jersey/JerseyAutoConfiguration.java | 39 ++++++- .../jersey/JerseyProperties.java | 65 +++++++++++ .../JerseyAutoConfigurationFilterTests.java | 105 ++++++++++++++++++ 3 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyProperties.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationFilterTests.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 caf5edf94d..ee6141a668 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 @@ -16,11 +16,16 @@ package org.springframework.boot.autoconfigure.jersey; +import java.util.Arrays; +import java.util.EnumSet; + import javax.annotation.PostConstruct; +import javax.servlet.DispatcherType; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.ws.rs.ApplicationPath; +import org.glassfish.jersey.CommonProperties; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; import org.glassfish.jersey.servlet.ServletProperties; @@ -30,10 +35,13 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; +import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.springframework.boot.context.embedded.ServletRegistrationBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; @@ -56,8 +64,12 @@ import org.springframework.web.filter.RequestContextFilter; @ConditionalOnWebApplication @Order(Ordered.HIGHEST_PRECEDENCE) @AutoConfigureBefore(DispatcherServletAutoConfiguration.class) +@EnableConfigurationProperties(JerseyProperties.class) public class JerseyAutoConfiguration implements WebApplicationInitializer { + @Autowired + private JerseyProperties jersey; + @Autowired private ListableBeanFactory context; @@ -74,18 +86,41 @@ public class JerseyAutoConfiguration implements WebApplicationInitializer { @Bean @ConditionalOnMissingBean - public RequestContextFilter requestContextFilter() { - return new RequestContextFilter(); + public FilterRegistrationBean requestContextFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new RequestContextFilter()); + registration.setOrder(jersey.getFilter().getOrder()-1); + registration.setName("requestContextFilter"); + return registration; } + @Bean + @ConditionalOnMissingBean(name = "jerseyFilterRegistration") + @ConditionalOnExpression("'${spring.jersey.type:servlet}' == 'filter'") + public FilterRegistrationBean jerseyFilterRegistration() { + Class configType = this.config.getClass(); + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new ServletContainer()); + registration.setUrlPatterns(Arrays.asList(this.path)); + registration.setOrder(jersey.getFilter().getOrder()); + registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, + configType.getName()); + registration.addInitParameter(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true"); + registration.setName("jerseyFilter"); + registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class)); + return registration; + } + @Bean @ConditionalOnMissingBean(name = "jerseyServletRegistration") + @ConditionalOnExpression("'${spring.jersey.type:servlet}' == 'servlet'") public ServletRegistrationBean jerseyServletRegistration() { Class configType = this.config.getClass(); ServletRegistrationBean registration = new ServletRegistrationBean( new ServletContainer(), this.path); registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, configType.getName()); + registration.addInitParameter(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true"); registration.setName("jerseyServlet"); return registration; } 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 new file mode 100644 index 0000000000..7a6daf98d4 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyProperties.java @@ -0,0 +1,65 @@ +/* + * Copyright 2013-2104 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 org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Dave Syer + * + */ +@ConfigurationProperties("spring.jersey") +public class JerseyProperties { + + public enum Type { + servlet, filter; + } + + private Type type = Type.servlet; + + private Filter filter = new Filter(); + + public Filter getFilter() { + return filter; + } + + public void setFilter(Filter filter) { + this.filter = filter; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public static class Filter { + + private int order; + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationFilterTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationFilterTests.java new file mode 100644 index 0000000000..bf7374c78b --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationFilterTests.java @@ -0,0 +1,105 @@ +/* + * Copyright 2012-2014 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 static org.junit.Assert.assertEquals; + +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.ApplicationPath; +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.JerseyAutoConfigurationFilterTests.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; + +/** + * Tests for {@link JerseyAutoConfiguration} when using custom servlet paths. + * + * @author Dave Syer + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = Application.class) +@IntegrationTest({ "server.port=0", "spring.jersey.type=filter" }) +@WebAppConfiguration +public class JerseyAutoConfigurationFilterTests { + + @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 + @ApplicationPath("/rest") + @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 static @interface MinimalWebConfiguration { + } + +}