From 62eb01f0b8c69ba844cb57a6969609b3c1922c96 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 6 Oct 2014 12:03:51 -0700 Subject: [PATCH] Polish --- .../MetricRepositoryAutoConfiguration.java | 2 +- .../RichGaugeReaderPublicMetrics.java | 18 ++-- .../boot/actuate/metrics/rich/RichGauge.java | 5 ++ .../jackson/JacksonAutoConfiguration.java | 89 ++++++++++--------- .../jersey/JerseyAutoConfiguration.java | 14 +-- .../jta/JndiJtaConfiguration.java | 4 +- .../jpa/HibernateJpaAutoConfiguration.java | 58 ++++++------ ...ttpMessageConvertersAutoConfiguration.java | 2 +- .../JacksonAutoConfigurationTests.java | 2 +- ...oConfigurationCustomServletPathTests.java} | 26 +++--- ...ConfigurationDefaultServletPathTests.java} | 21 +++-- .../main/asciidoc/spring-boot-features.adoc | 55 ++++++------ .../spring-boot-sample-jersey/pom.xml | 26 +++--- .../src/main/java/sample/jersey/Endpoint.java | 8 +- .../main/java/sample/jersey/JerseyConfig.java | 2 +- .../jersey/SampleJerseyApplication.java | 6 +- .../jersey/SampleJerseyApplicationTests.java | 16 ++-- .../spring-boot-sample-jersey1/pom.xml | 25 +++--- .../jersey1/SampleJersey1Application.java | 63 ++++++++----- .../SampleJersey1ApplicationTests.java | 27 ++++-- 20 files changed, 257 insertions(+), 212 deletions(-) rename spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/{CustomServletPathTests.java => JerseyAutoConfigurationCustomServletPathTests.java} (85%) rename spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/{DefaultServletPathTests.java => JerseyAutoConfigurationDefaultServletPathTests.java} (85%) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java index 041386d047..c1e9112f74 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricRepositoryAutoConfiguration.java @@ -73,7 +73,7 @@ import com.codahale.metrics.MetricRegistry; * In addition if Codahale's metrics library is on the classpath a {@link MetricRegistry} * will be created and wired up to the counter and gauge services in addition to the basic * repository. Users can create Codahale metrics by prefixing their metric names with the - * appropriate type (e.g. "histogram.*", "meter.*") and sending them to the standard + * appropriate type (e.g. "histogram.*", "meter.*") and sending them to the standard * GaugeService or CounterService. *

*

diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RichGaugeReaderPublicMetrics.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RichGaugeReaderPublicMetrics.java index a644e2926d..ad05ffeabb 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RichGaugeReaderPublicMetrics.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RichGaugeReaderPublicMetrics.java @@ -49,18 +49,14 @@ public class RichGaugeReaderPublicMetrics implements PublicMetrics { return result; } - private List> convert(RichGauge richGauge) { + private List> convert(RichGauge gauge) { List> result = new ArrayList>(6); - - result.add(new Metric(richGauge.getName() + RichGauge.AVG, richGauge - .getAverage())); - result.add(new Metric(richGauge.getName() + RichGauge.VAL, richGauge.getValue())); - result.add(new Metric(richGauge.getName() + RichGauge.MIN, richGauge.getMin())); - result.add(new Metric(richGauge.getName() + RichGauge.MAX, richGauge.getMax())); - result.add(new Metric(richGauge.getName() + RichGauge.ALPHA, richGauge - .getAlpha())); - result.add(new Metric(richGauge.getName() + RichGauge.COUNT, richGauge.getCount())); - + result.add(new Metric(gauge.getName() + RichGauge.AVG, gauge.getAverage())); + result.add(new Metric(gauge.getName() + RichGauge.VAL, gauge.getValue())); + result.add(new Metric(gauge.getName() + RichGauge.MIN, gauge.getMin())); + result.add(new Metric(gauge.getName() + RichGauge.MAX, gauge.getMax())); + result.add(new Metric(gauge.getName() + RichGauge.ALPHA, gauge.getAlpha())); + result.add(new Metric(gauge.getName() + RichGauge.COUNT, gauge.getCount())); return result; } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/RichGauge.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/RichGauge.java index c5677fd8e3..2a44c9f45e 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/RichGauge.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/rich/RichGauge.java @@ -32,10 +32,15 @@ import org.springframework.util.Assert; public final class RichGauge { public static final String COUNT = ".count"; + public static final String MAX = ".max"; + public static final String MIN = ".min"; + public static final String AVG = ".avg"; + public static final String ALPHA = ".alpha"; + public static final String VAL = ".val"; private final String name; diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java index 6301babf85..b49834e928 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java @@ -37,6 +37,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -56,8 +57,8 @@ import com.fasterxml.jackson.databind.SerializationFeature; * * @author Oliver Gierke * @author Andy Wilkinson - * @author Sebastien Deleuze * @author Marcel Overdijk + * @author Sebastien Deleuze * @since 1.1.0 */ @Configuration @@ -99,29 +100,25 @@ public class JacksonAutoConfiguration { static class JacksonObjectMapperBuilderAutoConfiguration { @Autowired - private HttpMapperProperties httpMapperProperties = new HttpMapperProperties(); + private JacksonProperties jacksonProperties; @Autowired - private JacksonProperties jacksonProperties = new JacksonProperties(); + private HttpMapperProperties httpMapperProperties; @Bean @ConditionalOnMissingBean(Jackson2ObjectMapperBuilder.class) public Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); - if (this.httpMapperProperties.isJsonSortKeys()) { builder.featuresToEnable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS); } - configureFeatures(builder, this.jacksonProperties.getDeserialization()); configureFeatures(builder, this.jacksonProperties.getSerialization()); configureFeatures(builder, this.jacksonProperties.getMapper()); configureFeatures(builder, this.jacksonProperties.getParser()); configureFeatures(builder, this.jacksonProperties.getGenerator()); - configureDateFormat(builder); configurePropertyNamingStrategy(builder); - return builder; } @@ -137,53 +134,57 @@ public class JacksonAutoConfiguration { } } + private void configureDateFormat(Jackson2ObjectMapperBuilder builder) { + // We support a fully qualified class name extending DateFormat or a date + // pattern string value + String dateFormat = this.jacksonProperties.getDateFormat(); + if (dateFormat != null) { + try { + Class dateFormatClass = ClassUtils.forName(dateFormat, null); + builder.dateFormat((DateFormat) BeanUtils + .instantiateClass(dateFormatClass)); + } + catch (ClassNotFoundException ex) { + builder.dateFormat(new SimpleDateFormat(dateFormat)); + } + } + } + private void configurePropertyNamingStrategy(Jackson2ObjectMapperBuilder builder) { // We support a fully qualified class name extending Jackson's // PropertyNamingStrategy or a string value corresponding to the constant // names in PropertyNamingStrategy which hold default provided implementations - String propertyNamingStrategy = this.jacksonProperties - .getPropertyNamingStrategy(); - if (propertyNamingStrategy != null) { + String strategy = this.jacksonProperties.getPropertyNamingStrategy(); + if (strategy != null) { try { - Class clazz = ClassUtils.forName(propertyNamingStrategy, null); - builder.propertyNamingStrategy((PropertyNamingStrategy) BeanUtils - .instantiateClass(clazz)); + configurePropertyNamingStrategyClass(builder, + ClassUtils.forName(strategy, null)); } - catch (ClassNotFoundException e) { - // Find the field (this way we automatically support new constants - // that may be added by Jackson in the future) - Field field = ReflectionUtils.findField(PropertyNamingStrategy.class, - propertyNamingStrategy, PropertyNamingStrategy.class); - if (field != null) { - try { - builder.propertyNamingStrategy((PropertyNamingStrategy) field - .get(null)); - } - catch (Exception ex) { - throw new IllegalStateException(ex); - } - } - else { - throw new IllegalArgumentException("Constant named '" - + propertyNamingStrategy + "' not found on " - + PropertyNamingStrategy.class.getName()); - } + catch (ClassNotFoundException ex) { + configurePropertyNamingStrategyField(builder, strategy); } } } - private void configureDateFormat(Jackson2ObjectMapperBuilder builder) { - // We support a fully qualified class name extending DateFormat or a date - // pattern string value - String dateFormat = this.jacksonProperties.getDateFormat(); - if (dateFormat != null) { - try { - Class clazz = ClassUtils.forName(dateFormat, null); - builder.dateFormat((DateFormat) BeanUtils.instantiateClass(clazz)); - } - catch (ClassNotFoundException e) { - builder.dateFormat(new SimpleDateFormat(dateFormat)); - } + private void configurePropertyNamingStrategyClass( + Jackson2ObjectMapperBuilder builder, Class propertyNamingStrategyClass) { + builder.propertyNamingStrategy((PropertyNamingStrategy) BeanUtils + .instantiateClass(propertyNamingStrategyClass)); + } + + private void configurePropertyNamingStrategyField( + Jackson2ObjectMapperBuilder builder, String fieldName) { + // Find the field (this way we automatically support new constants + // that may be added by Jackson in the future) + Field field = ReflectionUtils.findField(PropertyNamingStrategy.class, + fieldName, PropertyNamingStrategy.class); + Assert.notNull(field, "Constant named '" + fieldName + "' not found on " + + PropertyNamingStrategy.class.getName()); + try { + builder.propertyNamingStrategy((PropertyNamingStrategy) field.get(null)); + } + catch (Exception ex) { + throw new IllegalStateException(ex); } } 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 352fe7796d..55bbd92d87 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-2013 the original author or authors. + * 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. @@ -29,6 +29,7 @@ import org.glassfish.jersey.servlet.ServletProperties; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; 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.ConditionalOnMissingBean; @@ -44,8 +45,9 @@ import org.springframework.web.WebApplicationInitializer; import org.springframework.web.filter.RequestContextFilter; /** + * {@link EnableAutoConfiguration Auto-configuration} for Jersey. + * * @author Dave Syer - * */ @Configuration @ConditionalOnClass({ SpringComponentProvider.class, ServletRegistration.class }) @@ -65,7 +67,7 @@ public class JerseyAutoConfiguration implements WebApplicationInitializer { @PostConstruct public void path() { - path = findPath(AnnotationUtils.findAnnotation(config.getClass(), + this.path = findPath(AnnotationUtils.findAnnotation(this.config.getClass(), ApplicationPath.class)); } @@ -78,9 +80,9 @@ public class JerseyAutoConfiguration implements WebApplicationInitializer { @Bean @ConditionalOnMissingBean(name = "jerseyServletRegistration") public ServletRegistrationBean jerseyServletRegistration() { - Class configType = config.getClass(); + Class configType = this.config.getClass(); ServletRegistrationBean registration = new ServletRegistrationBean( - new ServletContainer(), path); + new ServletContainer(), this.path); registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, configType.getName()); registration.setName("jerseyServlet"); @@ -100,7 +102,7 @@ public class JerseyAutoConfiguration implements WebApplicationInitializer { return "/*"; } String path = annotation.value(); - return path.isEmpty() || path.equals("/") ? "/*" : path + "/*"; + return ((path.isEmpty() || path.equals("/")) ? "/*" : path + "/*"); } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JndiJtaConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JndiJtaConfiguration.java index e4bd00f980..24809c208b 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JndiJtaConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JndiJtaConfiguration.java @@ -29,6 +29,7 @@ import org.springframework.transaction.jta.JtaTransactionManager; * JTA Configuration for a JNDI-managed {@link JtaTransactionManager}. * * @author Phillip Webb + * @author Stephane Nicoll * @since 1.2.0 */ @Configuration @@ -41,8 +42,7 @@ class JndiJtaConfiguration { @Bean public JtaTransactionManager transactionManager() { - JtaTransactionManagerFactoryBean factoryBean = new JtaTransactionManagerFactoryBean(); - return factoryBean.getObject(); + return new JtaTransactionManagerFactoryBean().getObject(); } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java index c6b8cbe501..a82f332fc3 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.java @@ -22,8 +22,6 @@ import java.util.Map; import javax.persistence.EntityManager; import javax.sql.DataSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -37,6 +35,8 @@ import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform; import org.springframework.context.annotation.ConditionContext; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; @@ -50,6 +50,7 @@ import org.springframework.util.ClassUtils; * * @author Phillip Webb * @author Josh Long + * @author Manuel Doninger */ @Configuration @ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, @@ -60,8 +61,12 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { private static final String JTA_PLATFORM = "hibernate.transaction.jta.platform"; - private static final Logger logger = LoggerFactory - .getLogger(HibernateJpaAutoConfiguration.class); + /** + * {@code NoJtaPlatform} implementations for various Hibernate versions. + */ + private static final String NO_JTA_PLATFORM_CLASSES[] = { + "org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform", + "org.hibernate.service.jta.platform.internal.NoJtaPlatform" }; @Autowired private JpaProperties properties; @@ -84,38 +89,35 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration { @Override protected void customizeVendorProperties(Map vendorProperties) { super.customizeVendorProperties(vendorProperties); + if (!vendorProperties.containsKey(JTA_PLATFORM)) { + dunno(vendorProperties); + } + } - String HIBERNATE43_NOJTAPLATFORM_CLASS = "org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform"; - String HIBERNATE42_NOJTAPLATFORM_CLASS = "org.hibernate.service.jta.platform.internal.NoJtaPlatform"; + private void dunno(Map vendorProperties) throws LinkageError { + JtaTransactionManager jtaTransactionManager = getJtaTransactionManager(); + if (jtaTransactionManager != null) { + vendorProperties.put(JTA_PLATFORM, new SpringJtaPlatform( + jtaTransactionManager)); + } + else { + vendorProperties.put(JTA_PLATFORM, getNoJtaPlatformManager()); + } + } - if (!vendorProperties.containsKey(JTA_PLATFORM)) { - JtaTransactionManager jtaTransactionManager = getJtaTransactionManager(); + private Object getNoJtaPlatformManager() { + for (String noJtaPlatformClass : NO_JTA_PLATFORM_CLASSES) { try { - if (jtaTransactionManager != null) { - vendorProperties.put(JTA_PLATFORM, new SpringJtaPlatform( - jtaTransactionManager)); - } - else { - Object jtaPlatform = null; - if (ClassUtils.isPresent(HIBERNATE43_NOJTAPLATFORM_CLASS, null)) { - jtaPlatform = ClassUtils.forName(HIBERNATE43_NOJTAPLATFORM_CLASS, - null).newInstance(); - } - else if (ClassUtils.isPresent(HIBERNATE42_NOJTAPLATFORM_CLASS, null)) { - jtaPlatform = ClassUtils.forName(HIBERNATE42_NOJTAPLATFORM_CLASS, - null).newInstance(); - } - if (jtaPlatform != null) { - vendorProperties.put(JTA_PLATFORM, jtaPlatform); - } - } + return Class.forName(noJtaPlatformClass).newInstance(); } - catch (Exception e) { - logger.error("Could not configure the JTA platform", e); + catch (Exception ex) { + // Continue searching } } + throw new IllegalStateException("Could not configure JTA platform"); } + @Order(Ordered.HIGHEST_PRECEDENCE + 20) static class HibernateEntityManagerCondition extends SpringBootCondition { private static String[] CLASS_NAMES = { diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfiguration.java index 23827a2a4f..d4a2171505 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfiguration.java @@ -45,8 +45,8 @@ import com.google.gson.Gson; * @author Piotr Maj * @author Oliver Gierke * @author David Liu - * @author Sebastien Deleuze * @author Andy Wilkinson + * @author Sebastien Deleuze */ @Configuration @ConditionalOnClass(HttpMessageConverter.class) diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java index af34adacaf..335dc2828e 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java @@ -60,9 +60,9 @@ import static org.mockito.Mockito.verify; * * @author Dave Syer * @author Oliver Gierke - * @author Sebastien Deleuze * @author Andy Wilkinson * @author Marcel Overdijk + * @author Sebastien Deleuze */ public class JacksonAutoConfigurationTests { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/CustomServletPathTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationCustomServletPathTests.java similarity index 85% rename from spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/CustomServletPathTests.java rename to spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationCustomServletPathTests.java index fc89d520c6..ba900509fd 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/CustomServletPathTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationCustomServletPathTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * 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. @@ -16,8 +16,6 @@ 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; @@ -34,7 +32,7 @@ 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.CustomServletPathTests.Application; +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; @@ -47,20 +45,28 @@ 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 servlet paths. + * + * @author Dave Syer + */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @IntegrationTest("server.port=0") @WebAppConfiguration -public class CustomServletPathTests { - +public class JerseyAutoConfigurationCustomServletPathTests { + @Value("${local.server.port}") private int port; - + private RestTemplate restTemplate = new TestRestTemplate(); @Test public void contextLoads() { - ResponseEntity entity = restTemplate.getForEntity("http://localhost:" + port + "/rest/hello", String.class); + ResponseEntity entity = this.restTemplate.getForEntity( + "http://localhost:" + this.port + "/rest/hello", String.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); } @@ -71,10 +77,10 @@ public class CustomServletPathTests { @Value("${message:World}") private String msg; - + @GET public String message() { - return "Hello " + msg; + return "Hello " + this.msg; } public Application() { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/DefaultServletPathTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationDefaultServletPathTests.java similarity index 85% rename from spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/DefaultServletPathTests.java rename to spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationDefaultServletPathTests.java index bcabf6f6ba..1a78baac97 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/DefaultServletPathTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jersey/JerseyAutoConfigurationDefaultServletPathTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * 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. @@ -16,8 +16,6 @@ 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; @@ -33,7 +31,7 @@ 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.DefaultServletPathTests.Application; +import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfigurationDefaultServletPathTests.Application; import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration; import org.springframework.boot.test.IntegrationTest; @@ -46,11 +44,18 @@ 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 default servlet paths. + * + * @author Dave Syer + */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @IntegrationTest("server.port=0") @WebAppConfiguration -public class DefaultServletPathTests { +public class JerseyAutoConfigurationDefaultServletPathTests { @Value("${local.server.port}") private int port; @@ -59,8 +64,8 @@ public class DefaultServletPathTests { @Test public void contextLoads() { - ResponseEntity entity = restTemplate.getForEntity("http://localhost:" - + port + "/hello", String.class); + ResponseEntity entity = this.restTemplate.getForEntity( + "http://localhost:" + this.port + "/hello", String.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); } @@ -77,7 +82,7 @@ public class DefaultServletPathTests { @GET public String message() { - return "Hello " + msg; + return "Hello " + this.msg; } public static void main(String[] args) { diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 21984975e0..cf64672e46 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -1031,59 +1031,60 @@ upon successful completion of a servlet's service method. You should disable th behaviour by setting `com.ibm.ws.webcontainer.invokeFlushAfterService` to `false` + [[boot-features-jersey]] === JAX-RS and Jersey If you prefer the JAX-RS programming model for REST endpoints you can use one of the available implementations instead of Spring MVC. Jersey 1.x and Apache Celtix work -quite well out of the box if you just register their `Servlet` or `Filter` as a +quite well out of the box if you just register their `Servlet` or `Filter` as a `@Bean` in your application context. Jersey 2.x has some native Spring support so we also provide autoconfiguration support for it in Spring Boot together with a starter. -To get started with Jersey 2.x just include the `spring-boot-starter-jersey` as a dependency -and then you need one `@Bean` of type `ResourceConfig` in which you register all the -endpoints: +To get started with Jersey 2.x just include the `spring-boot-starter-jersey` as a +dependency and then you need one `@Bean` of type `ResourceConfig` in which you register +all the endpoints: -[source,java] +[source,java,indent=0,subs="verbatim,quotes,attributes"] ---- -@Component -public class JerseyConfig extends ResourceConfig { - - public JerseyConfig() { - register(Endpoint.class); + @Component + public class JerseyConfig extends ResourceConfig { + public JerseyConfig() { + register(Endpoint.class); + } } - -} ---- -All the registered endpoints should be `@Components` with HTTP resource annotations (`@GET` etc.), e.g. +All the registered endpoints should be `@Components` with HTTP resource annotations +(`@GET` etc.), e.g. -[source,java] +[source,java,indent=0,subs="verbatim,quotes,attributes"] ---- -@Component -@Path("/hello") -public class Endpoint { + @Component + @Path("/hello") + public class Endpoint { - @GET - public String message() { - return "Hello"; - } + @GET + public String message() { + return "Hello"; + } -} + } ---- -Since the `Endpoint` is a Spring `@Component` its lifecycle -is managed by Spring and you can `@Autowired` dependencies and inject -external configuration with `@Value`. The Jersey servlet will be -registered and mapped to "/\*" by default. You can change the mapping +Since the `Endpoint` is a Spring `@Component` its lifecycle is managed by Spring and you +can `@Autowired` dependencies and inject external configuration with `@Value`. The Jersey +servlet will be registered and mapped to ``/\*'' by default. You can change the mapping by adding `@ApplicationPath` to your `ResourceConfig`. There is a {github-code}/spring-boot-samples/spring-boot-sample-jersey[Jersey sample] so -you can see how to set things up. There is also a {github-code}/spring-boot-samples/spring-boot-sample-jersey1[Jersey 1.x sample]. +you can see how to set things up. There is also a {github-code}/spring-boot-samples/spring-boot-sample-jersey1[Jersey 1.x sample]. Note that in the Jersey 1.x sample that the spring-boot maven plugin has been configured to unpack some Jersey jars so they can be scanned by the JAX-RS implementation (the sample asks for them to be scanned in its `Filter` registration. + + [[boot-features-embedded-container]] === Embedded servlet container support Spring Boot includes support for embedded Tomcat and Jetty servers. Most developers will diff --git a/spring-boot-samples/spring-boot-sample-jersey/pom.xml b/spring-boot-samples/spring-boot-sample-jersey/pom.xml index b77538862c..fe5a7242df 100644 --- a/spring-boot-samples/spring-boot-sample-jersey/pom.xml +++ b/spring-boot-samples/spring-boot-sample-jersey/pom.xml @@ -1,22 +1,24 @@ - + 4.0.0 - - spring-boot-sample-jersey - 1.0.0.BUILD-SNAPSHOT - war - - spring-boot-sample-jersey - Spring Boot Jersey sample project - org.springframework.boot spring-boot-samples 1.2.0.BUILD-SNAPSHOT - + spring-boot-sample-jersey + war + Spring Boot Jersey Sample + Spring Boot Jersey Sample + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + org.springframework.boot @@ -28,7 +30,6 @@ test - @@ -37,5 +38,4 @@ - diff --git a/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/Endpoint.java b/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/Endpoint.java index 8bdc7bdb35..bcf89564ec 100644 --- a/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/Endpoint.java +++ b/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/Endpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * 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. @@ -22,10 +22,6 @@ import javax.ws.rs.Path; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -/** - * @author Dave Syer - * - */ @Component @Path("/hello") public class Endpoint { @@ -35,7 +31,7 @@ public class Endpoint { @GET public String message() { - return "Hello " + msg; + return "Hello " + this.msg; } } diff --git a/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/JerseyConfig.java b/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/JerseyConfig.java index f9299d825b..85c763f7b1 100644 --- a/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/JerseyConfig.java +++ b/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/JerseyConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * 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. diff --git a/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/SampleJerseyApplication.java b/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/SampleJerseyApplication.java index 982795fde2..e96c67bbc8 100644 --- a/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/SampleJerseyApplication.java +++ b/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/SampleJerseyApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * 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. @@ -31,8 +31,8 @@ public class SampleJerseyApplication extends SpringBootServletInitializer { } public static void main(String[] args) { - new SampleJerseyApplication().configure(new SpringApplicationBuilder(SampleJerseyApplication.class)).run( - args); + new SampleJerseyApplication().configure( + new SpringApplicationBuilder(SampleJerseyApplication.class)).run(args); } } diff --git a/spring-boot-samples/spring-boot-sample-jersey/src/test/java/sample/jersey/SampleJerseyApplicationTests.java b/spring-boot-samples/spring-boot-sample-jersey/src/test/java/sample/jersey/SampleJerseyApplicationTests.java index d09f48f93d..2902f7c924 100644 --- a/spring-boot-samples/spring-boot-sample-jersey/src/test/java/sample/jersey/SampleJerseyApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-jersey/src/test/java/sample/jersey/SampleJerseyApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * 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. @@ -16,8 +16,6 @@ package sample.jersey; -import static org.junit.Assert.assertEquals; - import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Value; @@ -30,21 +28,23 @@ 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; + @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = SampleJerseyApplication.class) @IntegrationTest("server.port=0") @WebAppConfiguration public class SampleJerseyApplicationTests { - + @Value("${local.server.port}") private int port; - - private RestTemplate restTemplate =new TestRestTemplate(); + + private RestTemplate restTemplate = new TestRestTemplate(); @Test public void contextLoads() { - ResponseEntity entity = restTemplate.getForEntity("http://localhost:" - + port + "/hello", String.class); + ResponseEntity entity = this.restTemplate.getForEntity( + "http://localhost:" + this.port + "/hello", String.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); } diff --git a/spring-boot-samples/spring-boot-sample-jersey1/pom.xml b/spring-boot-samples/spring-boot-sample-jersey1/pom.xml index feab018075..3ff2593da9 100644 --- a/spring-boot-samples/spring-boot-sample-jersey1/pom.xml +++ b/spring-boot-samples/spring-boot-sample-jersey1/pom.xml @@ -1,22 +1,23 @@ - + 4.0.0 - - spring-boot-sample-jersey1 - 0.0.1-SNAPSHOT - jar - - spring-boot-sample-jersey1 - Spring Boot Sample with Jersey 1.x - org.springframework.boot spring-boot-samples 1.2.0.BUILD-SNAPSHOT - + spring-boot-sample-jersey1 + Spring Boot Jersey 1 Sample + Spring Boot Jersey 1 Sample + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + org.springframework.boot @@ -41,7 +42,6 @@ test - @@ -66,5 +66,4 @@ - diff --git a/spring-boot-samples/spring-boot-sample-jersey1/src/main/java/sample/jersey1/SampleJersey1Application.java b/spring-boot-samples/spring-boot-sample-jersey1/src/main/java/sample/jersey1/SampleJersey1Application.java index 975150193b..4dccc77529 100644 --- a/spring-boot-samples/spring-boot-sample-jersey1/src/main/java/sample/jersey1/SampleJersey1Application.java +++ b/spring-boot-samples/spring-boot-sample-jersey1/src/main/java/sample/jersey1/SampleJersey1Application.java @@ -1,3 +1,19 @@ +/* + * 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 sample.jersey1; import javax.ws.rs.GET; @@ -20,28 +36,29 @@ import com.sun.jersey.spi.container.servlet.ServletContainer; @Path("/") public class SampleJersey1Application { - public static void main(String[] args) { - new SpringApplicationBuilder(SampleJersey1Application.class).web(true).run(args); - } - - @GET - @Produces("text/plain") - public String hello() { - return "Hello World"; - } - - @Bean - // Not needed if Spring Web MVC is also present on claspath - public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() { - return new TomcatEmbeddedServletContainerFactory(); - } - - @Bean - public FilterRegistrationBean jersey() { - FilterRegistrationBean bean = new FilterRegistrationBean(); - bean.setFilter(new ServletContainer()); - bean.addInitParameter("com.sun.jersey.config.property.packages", "com.sun.jersey;sample.jersey1"); + @GET + @Produces("text/plain") + public String hello() { + return "Hello World"; + } + + @Bean + // Not needed if Spring Web MVC is also present on claspath + public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() { + return new TomcatEmbeddedServletContainerFactory(); + } + + @Bean + public FilterRegistrationBean jersey() { + FilterRegistrationBean bean = new FilterRegistrationBean(); + bean.setFilter(new ServletContainer()); + bean.addInitParameter("com.sun.jersey.config.property.packages", + "com.sun.jersey;sample.jersey1"); return bean; - } - + } + + public static void main(String[] args) { + new SpringApplicationBuilder(SampleJersey1Application.class).web(true).run(args); + } + } diff --git a/spring-boot-samples/spring-boot-sample-jersey1/src/test/java/sample/jersey1/SampleJersey1ApplicationTests.java b/spring-boot-samples/spring-boot-sample-jersey1/src/test/java/sample/jersey1/SampleJersey1ApplicationTests.java index bcaccc23e3..67e32d5235 100644 --- a/spring-boot-samples/spring-boot-sample-jersey1/src/test/java/sample/jersey1/SampleJersey1ApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-jersey1/src/test/java/sample/jersey1/SampleJersey1ApplicationTests.java @@ -1,30 +1,45 @@ -package sample.jersey1; +/* + * 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. + */ -import static org.junit.Assert.assertEquals; +package sample.jersey1; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.IntegrationTest; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.boot.test.TestRestTemplate; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; -import sample.jersey1.SampleJersey1Application; +import static org.junit.Assert.assertEquals; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = SampleJersey1Application.class) @WebAppConfiguration @IntegrationTest("server.port:0") public class SampleJersey1ApplicationTests { - + @Value("${local.server.port}") private int port; @Test public void contextLoads() { - assertEquals("Hello World", new TestRestTemplate().getForObject("http://localhost:" + port + "/", String.class)); + assertEquals("Hello World", new TestRestTemplate().getForObject( + "http://localhost:" + this.port + "/", String.class)); } }