Browse Source

Merge pull request #4188 from eddumelendez/gh-4131

* pr/4188:
  Polish contribution
  Add support of Jackson in Jersey
pull/3499/head
Stephane Nicoll 10 years ago
parent
commit
b896de404e
  1. 5
      spring-boot-autoconfigure/pom.xml
  2. 59
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfiguration.java
  3. 36
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jersey/ResourceConfigCustomizer.java
  4. 136
      spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationCustomObjectMapperProviderTests.java
  5. 135
      spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationObjectMapperProviderTests.java
  6. 3
      spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

5
spring-boot-autoconfigure/pom.xml

@ -130,6 +130,11 @@ @@ -130,6 +130,11 @@
<artifactId>jersey-spring3</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>

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

@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jersey; @@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jersey;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
@ -26,15 +27,21 @@ import javax.servlet.ServletContext; @@ -26,15 +27,21 @@ import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.ServletProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -42,7 +49,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -42,7 +49,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.embedded.RegistrationBean;
@ -51,6 +60,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties @@ -51,6 +60,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.util.ClassUtils;
@ -73,6 +83,7 @@ import org.springframework.web.filter.RequestContextFilter; @@ -73,6 +83,7 @@ import org.springframework.web.filter.RequestContextFilter;
@ConditionalOnWebApplication
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@AutoConfigureBefore(DispatcherServletAutoConfiguration.class)
@AutoConfigureAfter(JacksonAutoConfiguration.class)
@EnableConfigurationProperties(JerseyProperties.class)
public class JerseyAutoConfiguration implements ServletContextAware {
@ -84,10 +95,18 @@ public class JerseyAutoConfiguration implements ServletContextAware { @@ -84,10 +95,18 @@ public class JerseyAutoConfiguration implements ServletContextAware {
@Autowired
private ResourceConfig config;
@Autowired(required = false)
private List<ResourceConfigCustomizer> customizers;
private String path;
@PostConstruct
public void path() {
resolveApplicationPath();
customize();
}
private void resolveApplicationPath() {
if (StringUtils.hasLength(this.jersey.getApplicationPath())) {
this.path = parseApplicationPath(this.jersey.getApplicationPath());
}
@ -97,6 +116,15 @@ public class JerseyAutoConfiguration implements ServletContextAware { @@ -97,6 +116,15 @@ public class JerseyAutoConfiguration implements ServletContextAware {
}
}
private void customize() {
if (this.customizers != null) {
AnnotationAwareOrderComparator.sort(this.customizers);
for (ResourceConfigCustomizer customizer : this.customizers) {
customizer.customize(this.config);
}
}
}
@Bean
@ConditionalOnMissingBean
public FilterRegistrationBean requestContextFilter() {
@ -193,6 +221,37 @@ public class JerseyAutoConfiguration implements ServletContextAware { @@ -193,6 +221,37 @@ public class JerseyAutoConfiguration implements ServletContextAware {
// will try and register a ContextLoaderListener which we don't need
servletContext.setInitParameter("contextConfigLocation", "<NONE>");
}
}
@ConditionalOnClass(JacksonFeature.class)
@ConditionalOnSingleCandidate(ObjectMapper.class)
@Configuration
static class JacksonResourceConfigCustomizer {
@Bean
public ResourceConfigCustomizer resourceConfigCustomizer() {
return new ResourceConfigCustomizer() {
@Override
public void customize(ResourceConfig config) {
config.register(JacksonFeature.class);
config.register(ObjectMapperContextResolver.class);
}
};
}
@Provider
static class ObjectMapperContextResolver
implements ContextResolver<ObjectMapper> {
@Autowired
private ObjectMapper objectMapper;
@Override
public ObjectMapper getContext(Class<?> type) {
return this.objectMapper;
}
}
}

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

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
/*
* 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 org.glassfish.jersey.server.ResourceConfig;
/**
* Callback interface that can be implemented by beans wishing to customize Jersey's
* {@link ResourceConfig} before it is used.
*
* @author Eddú Meléndez
* @since 1.4.0
*/
public interface ResourceConfigCustomizer {
/**
* Customize the resource config.
* @param config the {@link ResourceConfig} to customize
*/
void customize(ResourceConfig config);
}

136
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationCustomObjectMapperProviderTests.java

@ -0,0 +1,136 @@ @@ -0,0 +1,136 @@
/*
* 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 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.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfigurationObjectMapperProviderTests.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.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
@IntegrationTest({ "server.port=0", "spring.jackson.serialization-inclusion=non_null" })
@WebAppConfiguration
public class JerseyAutoConfigurationCustomObjectMapperProviderTests {
@Value("${local.server.port}")
private int port;
private RestTemplate restTemplate = new TestRestTemplate();
@Test
public void contextLoads() {
ResponseEntity<String> response = this.restTemplate.getForEntity(
"http://localhost:" + this.port + "/rest/message", String.class);
assertThat(HttpStatus.OK).isEqualTo(response.getStatusCode());
assertThat("{\"subject\":\"Jersey\"}").isEqualTo(response.getBody());
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/message")
public static class Application extends ResourceConfig {
@GET
public Message message() {
return new Message("Jersey", null);
}
public Application() {
register(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
public static class Message {
private String subject;
private String body;
public Message() {
}
public Message(String subject, String body) {
this.subject = subject;
this.body = body;
}
public String getSubject() {
return this.subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return this.body;
}
public void setBody(String body) {
this.body = body;
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ EmbeddedServletContainerAutoConfiguration.class,
JacksonAutoConfiguration.class, ServerPropertiesAutoConfiguration.class,
JerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

135
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationObjectMapperProviderTests.java

@ -0,0 +1,135 @@ @@ -0,0 +1,135 @@
/*
* 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 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.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfigurationObjectMapperProviderTests.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.assertj.core.api.Assertions.assertThat;
/**
* @author Eddú Meléndez
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
@IntegrationTest("server.port=0")
@WebAppConfiguration
public class JerseyAutoConfigurationObjectMapperProviderTests {
@Value("${local.server.port}")
private int port;
private RestTemplate restTemplate = new TestRestTemplate();
@Test
public void contextLoads() {
ResponseEntity<String> response = this.restTemplate.getForEntity(
"http://localhost:" + this.port + "/rest/message", String.class);
assertThat(HttpStatus.OK).isEqualTo(response.getStatusCode());
assertThat("{\"subject\":\"Jersey\",\"body\":null}").isEqualTo(response.getBody());
}
@MinimalWebConfiguration
@ApplicationPath("/rest")
@Path("/message")
public static class Application extends ResourceConfig {
@GET
public Message message() {
return new Message("Jersey", null);
}
public Application() {
register(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
public static class Message {
private String subject;
private String body;
public Message() {
}
public Message(String subject, String body) {
this.subject = subject;
this.body = body;
}
public String getSubject() {
return this.subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return this.body;
}
public void setBody(String body) {
this.body = body;
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ EmbeddedServletContainerAutoConfiguration.class,
JacksonAutoConfiguration.class, ServerPropertiesAutoConfiguration.class,
JerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration {
}
}

3
spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

@ -1754,6 +1754,9 @@ all the endpoints: @@ -1754,6 +1754,9 @@ all the endpoints:
}
----
You can also register an arbitrary number of beans implementing `ResourceConfigCustomizer`
for more advanced customizations.
All the registered endpoints should be `@Components` with HTTP resource annotations
(`@GET` etc.), e.g.

Loading…
Cancel
Save