Commit 7446235f authored by Phillip Webb's avatar Phillip Webb

Polish

parent c136054e
...@@ -30,6 +30,7 @@ import org.springframework.core.ResolvableType; ...@@ -30,6 +30,7 @@ import org.springframework.core.ResolvableType;
* *
* @param <H> The health indicator type * @param <H> The health indicator type
* @param <S> T he bean source type * @param <S> T he bean source type
* @author Stephane Nicoll
* @since 1.4.0 * @since 1.4.0
*/ */
public abstract class CompositeHealthIndicatorConfiguration<H extends HealthIndicator, S> { public abstract class CompositeHealthIndicatorConfiguration<H extends HealthIndicator, S> {
...@@ -61,8 +62,8 @@ public abstract class CompositeHealthIndicatorConfiguration<H extends HealthIndi ...@@ -61,8 +62,8 @@ public abstract class CompositeHealthIndicatorConfiguration<H extends HealthIndi
return indicatorClass.getConstructor(sourceClass).newInstance(source); return indicatorClass.getConstructor(sourceClass).newInstance(source);
} }
catch (Exception ex) { catch (Exception ex) {
throw new IllegalStateException("Unable to create indicator " throw new IllegalStateException("Unable to create indicator " + indicatorClass
+ indicatorClass + " for source " + sourceClass, ex); + " for source " + sourceClass, ex);
} }
} }
......
...@@ -43,14 +43,14 @@ class ElasticsearchHealthIndicatorConfiguration { ...@@ -43,14 +43,14 @@ class ElasticsearchHealthIndicatorConfiguration {
@ConditionalOnBean(Client.class) @ConditionalOnBean(Client.class)
@ConditionalOnEnabledHealthIndicator("elasticsearch") @ConditionalOnEnabledHealthIndicator("elasticsearch")
@EnableConfigurationProperties(ElasticsearchHealthIndicatorProperties.class) @EnableConfigurationProperties(ElasticsearchHealthIndicatorProperties.class)
static class SpringData extends static class ElasticsearchSpringDataHealthIndicatorConfiguration extends
CompositeHealthIndicatorConfiguration<ElasticsearchHealthIndicator, Client> { CompositeHealthIndicatorConfiguration<ElasticsearchHealthIndicator, Client> {
private final Map<String, Client> clients; private final Map<String, Client> clients;
private final ElasticsearchHealthIndicatorProperties properties; private final ElasticsearchHealthIndicatorProperties properties;
SpringData(Map<String, Client> clients, ElasticsearchSpringDataHealthIndicatorConfiguration(Map<String, Client> clients,
ElasticsearchHealthIndicatorProperties properties) { ElasticsearchHealthIndicatorProperties properties) {
this.clients = clients; this.clients = clients;
this.properties = properties; this.properties = properties;
...@@ -72,12 +72,12 @@ class ElasticsearchHealthIndicatorConfiguration { ...@@ -72,12 +72,12 @@ class ElasticsearchHealthIndicatorConfiguration {
@Configuration @Configuration
@ConditionalOnBean(JestClient.class) @ConditionalOnBean(JestClient.class)
@ConditionalOnEnabledHealthIndicator("elasticsearch") @ConditionalOnEnabledHealthIndicator("elasticsearch")
static class Jest extends static class ElasticsearchJestHealthIndicatorConfiguration extends
CompositeHealthIndicatorConfiguration<ElasticsearchJestHealthIndicator, JestClient> { CompositeHealthIndicatorConfiguration<ElasticsearchJestHealthIndicator, JestClient> {
private final Map<String, JestClient> clients; private final Map<String, JestClient> clients;
Jest(Map<String, JestClient> clients) { ElasticsearchJestHealthIndicatorConfiguration(Map<String, JestClient> clients) {
this.clients = clients; this.clients = clients;
} }
...@@ -88,9 +88,11 @@ class ElasticsearchHealthIndicatorConfiguration { ...@@ -88,9 +88,11 @@ class ElasticsearchHealthIndicatorConfiguration {
} }
@Override @Override
protected ElasticsearchJestHealthIndicator createHealthIndicator(JestClient client) { protected ElasticsearchJestHealthIndicator createHealthIndicator(
JestClient client) {
return new ElasticsearchJestHealthIndicator(client); return new ElasticsearchJestHealthIndicator(client);
} }
} }
} }
...@@ -98,8 +98,8 @@ import org.springframework.mail.javamail.JavaMailSenderImpl; ...@@ -98,8 +98,8 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
MongoDataAutoConfiguration.class, RabbitAutoConfiguration.class, MongoDataAutoConfiguration.class, RabbitAutoConfiguration.class,
RedisAutoConfiguration.class, SolrAutoConfiguration.class }) RedisAutoConfiguration.class, SolrAutoConfiguration.class })
@EnableConfigurationProperties({ HealthIndicatorProperties.class }) @EnableConfigurationProperties({ HealthIndicatorProperties.class })
@Import({ ElasticsearchHealthIndicatorConfiguration.SpringData.class, @Import({ ElasticsearchHealthIndicatorConfiguration.ElasticsearchSpringDataHealthIndicatorConfiguration.class,
ElasticsearchHealthIndicatorConfiguration.Jest.class }) ElasticsearchHealthIndicatorConfiguration.ElasticsearchJestHealthIndicatorConfiguration.class })
public class HealthIndicatorAutoConfiguration { public class HealthIndicatorAutoConfiguration {
private final HealthIndicatorProperties properties; private final HealthIndicatorProperties properties;
......
...@@ -70,4 +70,5 @@ public class ElasticsearchHealthIndicator extends AbstractHealthIndicator { ...@@ -70,4 +70,5 @@ public class ElasticsearchHealthIndicator extends AbstractHealthIndicator {
builder.withDetail("initializingShards", response.getInitializingShards()); builder.withDetail("initializingShards", response.getInitializingShards());
builder.withDetail("unassignedShards", response.getUnassignedShards()); builder.withDetail("unassignedShards", response.getUnassignedShards());
} }
} }
...@@ -59,7 +59,6 @@ public class ElasticsearchJestHealthIndicatorTests { ...@@ -59,7 +59,6 @@ public class ElasticsearchJestHealthIndicatorTests {
public void elasticSearchIsDown() throws IOException { public void elasticSearchIsDown() throws IOException {
given(this.jestClient.execute(any(Action.class))).willThrow( given(this.jestClient.execute(any(Action.class))).willThrow(
new CouldNotConnectException("http://localhost:9200", new IOException())); new CouldNotConnectException("http://localhost:9200", new IOException()));
Health health = this.healthIndicator.health(); Health health = this.healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN); assertThat(health.getStatus()).isEqualTo(Status.DOWN);
} }
...@@ -69,7 +68,6 @@ public class ElasticsearchJestHealthIndicatorTests { ...@@ -69,7 +68,6 @@ public class ElasticsearchJestHealthIndicatorTests {
public void elasticSearchIsOutOfService() throws IOException { public void elasticSearchIsOutOfService() throws IOException {
given(this.jestClient.execute(any(Action.class))) given(this.jestClient.execute(any(Action.class)))
.willReturn(createJestResult(4, 1)); .willReturn(createJestResult(4, 1));
Health health = this.healthIndicator.health(); Health health = this.healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE); assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
} }
...@@ -77,7 +75,6 @@ public class ElasticsearchJestHealthIndicatorTests { ...@@ -77,7 +75,6 @@ public class ElasticsearchJestHealthIndicatorTests {
private static JestResult createJestResult(int shards, int failedShards) { private static JestResult createJestResult(int shards, int failedShards) {
String json = String.format("{_shards: {\n" + "total: %s,\n" + "successful: %s,\n" String json = String.format("{_shards: {\n" + "total: %s,\n" + "successful: %s,\n"
+ "failed: %s\n" + "}}", shards, shards - failedShards, failedShards); + "failed: %s\n" + "}}", shards, shards - failedShards, failedShards);
SearchResult searchResult = new SearchResult(new Gson()); SearchResult searchResult = new SearchResult(new Gson());
searchResult.setJsonString(json); searchResult.setJsonString(json);
searchResult.setJsonObject(new JsonParser().parse(json).getAsJsonObject()); searchResult.setJsonObject(new JsonParser().parse(json).getAsJsonObject());
......
...@@ -48,7 +48,8 @@ public class JestAutoConfiguration { ...@@ -48,7 +48,8 @@ public class JestAutoConfiguration {
private final ObjectProvider<Gson> gsonProvider; private final ObjectProvider<Gson> gsonProvider;
public JestAutoConfiguration(JestProperties properties, ObjectProvider<Gson> gsonProvider) { public JestAutoConfiguration(JestProperties properties,
ObjectProvider<Gson> gsonProvider) {
this.properties = properties; this.properties = properties;
this.gsonProvider = gsonProvider; this.gsonProvider = gsonProvider;
} }
...@@ -62,8 +63,8 @@ public class JestAutoConfiguration { ...@@ -62,8 +63,8 @@ public class JestAutoConfiguration {
} }
protected HttpClientConfig createHttpClientConfig() { protected HttpClientConfig createHttpClientConfig() {
HttpClientConfig.Builder builder = new HttpClientConfig HttpClientConfig.Builder builder = new HttpClientConfig.Builder(
.Builder(this.properties.getUris()); this.properties.getUris());
if (StringUtils.hasText(this.properties.getUsername())) { if (StringUtils.hasText(this.properties.getUsername())) {
builder.defaultCredentials(this.properties.getUsername(), builder.defaultCredentials(this.properties.getUsername(),
this.properties.getPassword()); this.properties.getPassword());
...@@ -73,8 +74,7 @@ public class JestAutoConfiguration { ...@@ -73,8 +74,7 @@ public class JestAutoConfiguration {
builder.gson(gson); builder.gson(gson);
} }
return builder.connTimeout(this.properties.getConnectionTimeout()) return builder.connTimeout(this.properties.getConnectionTimeout())
.readTimeout(this.properties.getReadTimeout()) .readTimeout(this.properties.getReadTimeout()).build();
.build();
} }
} }
...@@ -132,7 +132,7 @@ class ArtemisConnectionFactoryFactory { ...@@ -132,7 +132,7 @@ class ArtemisConnectionFactoryFactory {
Constructor<T> constructor = factoryClass.getConstructor(boolean.class, Constructor<T> constructor = factoryClass.getConstructor(boolean.class,
TransportConfiguration[].class); TransportConfiguration[].class);
T connectionFactory = constructor.newInstance(false, T connectionFactory = constructor.newInstance(false,
new TransportConfiguration[] {transportConfiguration}); new TransportConfiguration[] { transportConfiguration });
String user = this.properties.getUser(); String user = this.properties.getUser();
if (StringUtils.hasText(user)) { if (StringUtils.hasText(user)) {
connectionFactory.setUser(user); connectionFactory.setUser(user);
......
...@@ -112,9 +112,10 @@ class HornetQConnectionFactoryFactory { ...@@ -112,9 +112,10 @@ class HornetQConnectionFactoryFactory {
this.properties.getEmbedded().generateTransportParameters()); this.properties.getEmbedded().generateTransportParameters());
ServerLocator serviceLocator = HornetQClient ServerLocator serviceLocator = HornetQClient
.createServerLocatorWithoutHA(transportConfiguration); .createServerLocatorWithoutHA(transportConfiguration);
Constructor<T> constructor = factoryClass.getDeclaredConstructor(HornetQProperties.class, Constructor<T> constructor = factoryClass
ServerLocator.class); .getDeclaredConstructor(HornetQProperties.class, ServerLocator.class);
return BeanUtils.instantiateClass(constructor, this.properties, serviceLocator); return BeanUtils.instantiateClass(constructor, this.properties,
serviceLocator);
} }
catch (NoClassDefFoundError ex) { catch (NoClassDefFoundError ex) {
throw new IllegalStateException("Unable to create InVM " throw new IllegalStateException("Unable to create InVM "
...@@ -130,8 +131,8 @@ class HornetQConnectionFactoryFactory { ...@@ -130,8 +131,8 @@ class HornetQConnectionFactoryFactory {
params.put(TransportConstants.PORT_PROP_NAME, this.properties.getPort()); params.put(TransportConstants.PORT_PROP_NAME, this.properties.getPort());
TransportConfiguration transportConfiguration = new TransportConfiguration( TransportConfiguration transportConfiguration = new TransportConfiguration(
NettyConnectorFactory.class.getName(), params); NettyConnectorFactory.class.getName(), params);
Constructor<T> constructor = factoryClass.getDeclaredConstructor(HornetQProperties.class, Constructor<T> constructor = factoryClass.getDeclaredConstructor(
boolean.class, TransportConfiguration[].class); HornetQProperties.class, boolean.class, TransportConfiguration[].class);
return BeanUtils.instantiateClass(constructor, this.properties, false, return BeanUtils.instantiateClass(constructor, this.properties, false,
new TransportConfiguration[] { transportConfiguration }); new TransportConfiguration[] { transportConfiguration });
} }
......
...@@ -46,7 +46,7 @@ class HornetQXAConnectionFactoryConfiguration { ...@@ -46,7 +46,7 @@ class HornetQXAConnectionFactoryConfiguration {
@Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" }) @Bean(name = { "jmsConnectionFactory", "xaJmsConnectionFactory" })
public ConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory, public ConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory,
HornetQProperties properties, XAConnectionFactoryWrapper wrapper) HornetQProperties properties, XAConnectionFactoryWrapper wrapper)
throws Exception { throws Exception {
return wrapper.wrapConnectionFactory( return wrapper.wrapConnectionFactory(
new HornetQConnectionFactoryFactory(beanFactory, properties) new HornetQConnectionFactoryFactory(beanFactory, properties)
.createConnectionFactory( .createConnectionFactory(
......
...@@ -47,6 +47,7 @@ class SpringBootHornetQConnectionFactory extends HornetQConnectionFactory { ...@@ -47,6 +47,7 @@ class SpringBootHornetQConnectionFactory extends HornetQConnectionFactory {
this.properties = properties; this.properties = properties;
} }
@Override
public Connection createConnection() throws JMSException { public Connection createConnection() throws JMSException {
String user = this.properties.getUser(); String user = this.properties.getUser();
if (StringUtils.hasText(user)) { if (StringUtils.hasText(user)) {
......
...@@ -47,6 +47,7 @@ class SpringBootHornetQXAConnectionFactory extends HornetQXAConnectionFactory { ...@@ -47,6 +47,7 @@ class SpringBootHornetQXAConnectionFactory extends HornetQXAConnectionFactory {
this.properties = properties; this.properties = properties;
} }
@Override
public Connection createConnection() throws JMSException { public Connection createConnection() throws JMSException {
String user = this.properties.getUser(); String user = this.properties.getUser();
if (StringUtils.hasText(user)) { if (StringUtils.hasText(user)) {
......
...@@ -209,7 +209,8 @@ public class MongoProperties { ...@@ -209,7 +209,8 @@ public class MongoProperties {
} }
String host = this.host == null ? "localhost" : this.host; String host = this.host == null ? "localhost" : this.host;
int port = determinePort(environment); int port = determinePort(environment);
return new MongoClient(Collections.singletonList(new ServerAddress(host, port)), return new MongoClient(
Collections.singletonList(new ServerAddress(host, port)),
credentials, options); credentials, options);
} }
// The options and credentials are in the URI // The options and credentials are in the URI
......
...@@ -226,14 +226,13 @@ public class WebMvcAutoConfiguration { ...@@ -226,14 +226,13 @@ public class WebMvcAutoConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale") @ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() { public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) { if (this.mvcProperties
.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale()); return new FixedLocaleResolver(this.mvcProperties.getLocale());
} }
else { AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver(); localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
localeResolver.setDefaultLocale(this.mvcProperties.getLocale()); return localeResolver;
return localeResolver;
}
} }
@Bean @Bean
......
...@@ -42,7 +42,8 @@ public class WebMvcProperties { ...@@ -42,7 +42,8 @@ public class WebMvcProperties {
private DefaultMessageCodesResolver.Format messageCodesResolverFormat; private DefaultMessageCodesResolver.Format messageCodesResolverFormat;
/** /**
* Locale to use. By default, this locale is overridden by the "Accept-Language" header. * Locale to use. By default, this locale is overridden by the "Accept-Language"
* header.
*/ */
private Locale locale; private Locale locale;
...@@ -261,8 +262,8 @@ public class WebMvcProperties { ...@@ -261,8 +262,8 @@ public class WebMvcProperties {
FIXED, FIXED,
/** /**
* Use the "Accept-Language" header or the configured locale if the header * Use the "Accept-Language" header or the configured locale if the header is not
* is not set. * set.
*/ */
ACCEPT_HEADER ACCEPT_HEADER
......
...@@ -92,7 +92,8 @@ public class MongoAutoConfigurationTests { ...@@ -92,7 +92,8 @@ public class MongoAutoConfigurationTests {
MongoClient mongo = this.context.getBean(MongoClient.class); MongoClient mongo = this.context.getBean(MongoClient.class);
MongoClientOptions options = mongo.getMongoClientOptions(); MongoClientOptions options = mongo.getMongoClientOptions();
assertThat(options.isSslEnabled()).isTrue(); assertThat(options.isSslEnabled()).isTrue();
assertThat(options.getSocketFactory()).isSameAs(this.context.getBean("mySocketFactory")); assertThat(options.getSocketFactory())
.isSameAs(this.context.getBean("mySocketFactory"));
} }
@Configuration @Configuration
...@@ -110,7 +111,8 @@ public class MongoAutoConfigurationTests { ...@@ -110,7 +111,8 @@ public class MongoAutoConfigurationTests {
@Bean @Bean
public MongoClientOptions mongoClientOptions() { public MongoClientOptions mongoClientOptions() {
return MongoClientOptions.builder().sslEnabled(true).socketFactory(mySocketFactory()).build(); return MongoClientOptions.builder().sslEnabled(true)
.socketFactory(mySocketFactory()).build();
} }
@Bean @Bean
......
...@@ -2637,20 +2637,21 @@ and http://hibernate.org/orm/documentation/[Hibernate] reference documentation. ...@@ -2637,20 +2637,21 @@ and http://hibernate.org/orm/documentation/[Hibernate] reference documentation.
[NOTE] [NOTE]
==== ====
As of Hibernate 5.2, the `hibernate-entitymanager` module has been merged in As of Hibernate 5.2, the `hibernate-entitymanager` module has been merged in
`hibernate-core`. If you need to downgrade, you'll have to add `hibernate-entitymanager` `hibernate-core`. If you need to downgrade, you'll need to directly add the
yourself, something like: dependency yourself, for example:
```xml [source,xml,indent=0]
<dependency> ----
<groupId>org.springframework.boot</groupId> <dependency>
<artifactId>spring-boot-starter-data-jpa</artifactId> <groupId>org.springframework.boot</groupId>
</dependency> <artifactId>spring-boot-starter-data-jpa</artifactId>
<dependency> </dependency>
<groupId>org.hibernate</groupId> <dependency>
<artifactId>hibernate-entitymanager</artifactId> <groupId>org.hibernate</groupId>
<version>${hibernate.version}</version> <artifactId>hibernate-entitymanager</artifactId>
</dependency> <version>${hibernate.version}</version>
``` </dependency>
----
As Hibernate does not bundle the `hibernate-entitymanager` and `hibernate-java8` As Hibernate does not bundle the `hibernate-entitymanager` and `hibernate-java8`
artifacts anymore, Spring Boot doesn't provide dependency management for them. artifacts anymore, Spring Boot doesn't provide dependency management for them.
...@@ -3364,6 +3365,7 @@ configured: ...@@ -3364,6 +3365,7 @@ configured:
To take full control over the registration, define a `JestClient` bean. To take full control over the registration, define a `JestClient` bean.
[[boot-features-connecting-to-elasticsearch]] [[boot-features-connecting-to-elasticsearch]]
[[boot-features-connecting-to-elasticsearch-spring-data]] [[boot-features-connecting-to-elasticsearch-spring-data]]
==== Connecting to Elasticsearch using Spring Data ==== Connecting to Elasticsearch using Spring Data
......
...@@ -19,7 +19,7 @@ package sample.jetty.jsp; ...@@ -19,7 +19,7 @@ package sample.jetty.jsp;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer; import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication @SpringBootApplication
public class SampleJettyJspApplication extends SpringBootServletInitializer { public class SampleJettyJspApplication extends SpringBootServletInitializer {
......
...@@ -172,12 +172,15 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor ...@@ -172,12 +172,15 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
Element returns = this.processingEnv.getTypeUtils() Element returns = this.processingEnv.getTypeUtils()
.asElement(element.getReturnType()); .asElement(element.getReturnType());
if (returns instanceof TypeElement) { if (returns instanceof TypeElement) {
ItemMetadata group = ItemMetadata.newGroup(prefix, this.typeUtils.getType(returns), ItemMetadata group = ItemMetadata.newGroup(prefix,
this.typeUtils.getType(returns),
this.typeUtils.getType(element.getEnclosingElement()), this.typeUtils.getType(element.getEnclosingElement()),
element.toString()); element.toString());
if (this.metadataCollector.hasSimilarGroup(group)) { if (this.metadataCollector.hasSimilarGroup(group)) {
this.processingEnv.getMessager().printMessage(Kind.ERROR, this.processingEnv.getMessager().printMessage(Kind.ERROR,
"Duplicate `@ConfigurationProperties` definition for prefix '" + prefix + "'", element); "Duplicate `@ConfigurationProperties` definition for prefix '"
+ prefix + "'",
element);
} }
else { else {
this.metadataCollector.add(group); this.metadataCollector.add(group);
......
...@@ -19,8 +19,7 @@ package org.springframework.boot.configurationsample.specific; ...@@ -19,8 +19,7 @@ package org.springframework.boot.configurationsample.specific;
import org.springframework.boot.configurationsample.ConfigurationProperties; import org.springframework.boot.configurationsample.ConfigurationProperties;
/** /**
* Test that the same type can be registered several times if the prefix is * Test that the same type can be registered several times if the prefix is different.
* different.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
......
...@@ -31,13 +31,19 @@ import org.eclipse.jetty.webapp.WebAppContext; ...@@ -31,13 +31,19 @@ import org.eclipse.jetty.webapp.WebAppContext;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
/** /**
* Jetty {@link AbstractLifeCycle} to initialize jasper. * Jetty {@link AbstractLifeCycle} to initialize Jasper.
* *
* @author Vladimir Tsanev * @author Vladimir Tsanev
* @author Phillip Webb
*/ */
public class JasperInitializer extends AbstractLifeCycle { class JasperInitializer extends AbstractLifeCycle {
private static final String[] INITIALIZER_CLASSES = {
"org.eclipse.jetty.apache.jsp.JettyJasperInitializer",
"org.apache.jasper.servlet.JasperInitializer" };
private final WebAppContext context; private final WebAppContext context;
private final ServletContainerInitializer initializer; private final ServletContainerInitializer initializer;
JasperInitializer(WebAppContext context) { JasperInitializer(WebAppContext context) {
...@@ -45,24 +51,17 @@ public class JasperInitializer extends AbstractLifeCycle { ...@@ -45,24 +51,17 @@ public class JasperInitializer extends AbstractLifeCycle {
this.initializer = newInitializer(); this.initializer = newInitializer();
} }
private static ServletContainerInitializer newInitializer() { private ServletContainerInitializer newInitializer() {
try { for (String className : INITIALIZER_CLASSES) {
try { try {
return (ServletContainerInitializer) ClassUtils Class<?> initializerClass = ClassUtils.forName(className, null);
.forName("org.eclipse.jetty.apache.jsp.JettyJasperInitializer", return (ServletContainerInitializer) initializerClass.newInstance();
null)
.newInstance();
} }
catch (Exception ex) { catch (Exception ex) {
// try the original initializer // Ignore
return (ServletContainerInitializer) ClassUtils
.forName("org.apache.jasper.servlet.JasperInitializer", null)
.newInstance();
} }
} }
catch (Exception ex) { return null;
return null;
}
} }
@Override @Override
...@@ -71,22 +70,14 @@ public class JasperInitializer extends AbstractLifeCycle { ...@@ -71,22 +70,14 @@ public class JasperInitializer extends AbstractLifeCycle {
return; return;
} }
try { try {
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() { URL.setURLStreamHandlerFactory(new WarUrlStreamHandlerFactory());
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("war".equals(protocol)) {
return new WarUrlStreamHandler();
}
return null;
}
});
} }
catch (Error ex) { catch (Error ex) {
// Ignore // Ignore
} }
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.context.getClassLoader());
try { try {
Thread.currentThread().setContextClassLoader(this.context.getClassLoader());
try { try {
setExtendedListenerTypes(true); setExtendedListenerTypes(true);
this.initializer.onStartup(null, this.context.getServletContext()); this.initializer.onStartup(null, this.context.getServletContext());
...@@ -109,23 +100,36 @@ public class JasperInitializer extends AbstractLifeCycle { ...@@ -109,23 +100,36 @@ public class JasperInitializer extends AbstractLifeCycle {
} }
} }
/**
* {@link URLStreamHandlerFactory} to support {@literal war} protocol.
*/
private static class WarUrlStreamHandlerFactory implements URLStreamHandlerFactory {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("war".equals(protocol)) {
return new WarUrlStreamHandler();
}
return null;
}
}
/** /**
* {@link URLStreamHandler} for {@literal war} protocol compatible with jasper's * {@link URLStreamHandler} for {@literal war} protocol compatible with jasper's
* {@link URL urls} produced by * {@link URL urls} produced by
* {@link org.apache.tomcat.util.scan.JarFactory#getJarEntryURL(URL, String)}. * {@link org.apache.tomcat.util.scan.JarFactory#getJarEntryURL(URL, String)}.
*/ */
static class WarUrlStreamHandler extends URLStreamHandler { private static class WarUrlStreamHandler extends URLStreamHandler {
@Override @Override
protected void parseURL(URL u, String spec, int start, int limit) { protected void parseURL(URL u, String spec, int start, int limit) {
String path = "jar:" + spec.substring("war:".length()); String path = "jar:" + spec.substring("war:".length());
int separator = path.indexOf("*/"); int separator = path.indexOf("*/");
if (separator >= 0) { if (separator >= 0) {
path = path.substring(0, separator) + "!/" path = path.substring(0, separator) + "!/"
+ path.substring(separator + 2); + path.substring(separator + 2);
} }
setURL(u, u.getProtocol(), "", -1, null, null, path, null, null); setURL(u, u.getProtocol(), "", -1, null, null, path, null, null);
} }
...@@ -133,12 +137,13 @@ public class JasperInitializer extends AbstractLifeCycle { ...@@ -133,12 +137,13 @@ public class JasperInitializer extends AbstractLifeCycle {
protected URLConnection openConnection(URL u) throws IOException { protected URLConnection openConnection(URL u) throws IOException {
return new WarURLConnection(u); return new WarURLConnection(u);
} }
} }
/** /**
* {@link URLConnection} to support {@literal war} protocol. * {@link URLConnection} to support {@literal war} protocol.
*/ */
static class WarURLConnection extends URLConnection { private static class WarURLConnection extends URLConnection {
private final URLConnection connection; private final URLConnection connection;
...@@ -160,6 +165,7 @@ public class JasperInitializer extends AbstractLifeCycle { ...@@ -160,6 +165,7 @@ public class JasperInitializer extends AbstractLifeCycle {
connect(); connect();
return this.connection.getInputStream(); return this.connection.getInputStream();
} }
} }
} }
/*
* 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.context.embedded.tomcat;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.security.KeyStore;
import org.springframework.boot.context.embedded.SslStoreProvider;
/**
* A {@link URLStreamHandlerFactory} that provides a {@link URLStreamHandler} for
* accessing an {@link SslStoreProvider}'s key store and trust store from a URL.
*
* @author Andy Wilkinson
*/
class SslStoreProviderUrlStreamHandlerFactory implements URLStreamHandlerFactory {
private static final String PROTOCOL = "springbootssl";
private static final String KEY_STORE_PATH = "keyStore";
static final String KEY_STORE_URL = PROTOCOL + ":" + KEY_STORE_PATH;
private static final String TRUST_STORE_PATH = "trustStore";
static final String TRUST_STORE_URL = PROTOCOL + ":" + TRUST_STORE_PATH;
private final SslStoreProvider sslStoreProvider;
SslStoreProviderUrlStreamHandlerFactory(SslStoreProvider sslStoreProvider) {
this.sslStoreProvider = sslStoreProvider;
}
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if (PROTOCOL.equals(protocol)) {
return new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL url) throws IOException {
try {
if (KEY_STORE_PATH.equals(url.getPath())) {
return new KeyStoreUrlConnection(url,
SslStoreProviderUrlStreamHandlerFactory.this.sslStoreProvider
.getKeyStore());
}
if (TRUST_STORE_PATH.equals(url.getPath())) {
return new KeyStoreUrlConnection(url,
SslStoreProviderUrlStreamHandlerFactory.this.sslStoreProvider
.getTrustStore());
}
}
catch (Exception ex) {
throw new IOException(ex);
}
throw new IOException("Invalid path: " + url.getPath());
}
};
}
return null;
}
private static final class KeyStoreUrlConnection extends URLConnection {
private final KeyStore keyStore;
private KeyStoreUrlConnection(URL url, KeyStore keyStore) {
super(url);
this.keyStore = keyStore;
}
@Override
public void connect() throws IOException {
}
@Override
public InputStream getInputStream() throws IOException {
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
this.keyStore.store(stream, new char[0]);
return new ByteArrayInputStream(stream.toByteArray());
}
catch (Exception ex) {
throw new IOException(ex);
}
}
}
}
...@@ -16,19 +16,11 @@ ...@@ -16,19 +16,11 @@
package org.springframework.boot.context.embedded.tomcat; package org.springframework.boot.context.embedded.tomcat;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.security.KeyStore;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
...@@ -63,7 +55,6 @@ import org.apache.coyote.http11.AbstractHttp11Protocol; ...@@ -63,7 +55,6 @@ import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.apache.coyote.http11.Http11NioProtocol; import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.tomcat.util.net.SSLHostConfig; import org.apache.tomcat.util.net.SSLHostConfig;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.Compression; import org.springframework.boot.context.embedded.Compression;
import org.springframework.boot.context.embedded.EmbeddedServletContainer; import org.springframework.boot.context.embedded.EmbeddedServletContainer;
...@@ -79,7 +70,6 @@ import org.springframework.context.ResourceLoaderAware; ...@@ -79,7 +70,6 @@ import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
import org.springframework.util.StreamUtils; import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -702,158 +692,6 @@ public class TomcatEmbeddedServletContainerFactory ...@@ -702,158 +692,6 @@ public class TomcatEmbeddedServletContainerFactory
return this.uriEncoding; return this.uriEncoding;
} }
/**
* A {@link URLStreamHandlerFactory} that provides a {@link URLStreamHandler} for
* accessing an {@link SslStoreProvider}'s key store and trust store from a URL.
*/
private static final class SslStoreProviderUrlStreamHandlerFactory
implements URLStreamHandlerFactory {
private static final String PROTOCOL = "springbootssl";
private static final String KEY_STORE_PATH = "keyStore";
private static final String KEY_STORE_URL = PROTOCOL + ":" + KEY_STORE_PATH;
private static final String TRUST_STORE_PATH = "trustStore";
private static final String TRUST_STORE_URL = PROTOCOL + ":" + TRUST_STORE_PATH;
private final SslStoreProvider sslStoreProvider;
private SslStoreProviderUrlStreamHandlerFactory(
SslStoreProvider sslStoreProvider) {
this.sslStoreProvider = sslStoreProvider;
}
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if (PROTOCOL.equals(protocol)) {
return new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL url) throws IOException {
try {
if (KEY_STORE_PATH.equals(url.getPath())) {
return new KeyStoreUrlConnection(url,
SslStoreProviderUrlStreamHandlerFactory.this.sslStoreProvider
.getKeyStore());
}
if (TRUST_STORE_PATH.equals(url.getPath())) {
return new KeyStoreUrlConnection(url,
SslStoreProviderUrlStreamHandlerFactory.this.sslStoreProvider
.getTrustStore());
}
}
catch (Exception ex) {
throw new IOException(ex);
}
throw new IOException("Invalid path: " + url.getPath());
}
};
}
return null;
}
private static final class KeyStoreUrlConnection extends URLConnection {
private final KeyStore keyStore;
private KeyStoreUrlConnection(URL url, KeyStore keyStore) {
super(url);
this.keyStore = keyStore;
}
@Override
public void connect() throws IOException {
}
@Override
public InputStream getInputStream() throws IOException {
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
this.keyStore.store(stream, new char[0]);
return new ByteArrayInputStream(stream.toByteArray());
}
catch (Exception ex) {
throw new IOException(ex);
}
}
}
}
private static class TomcatErrorPage {
private static final String ERROR_PAGE_CLASS = "org.apache.tomcat.util.descriptor.web.ErrorPage";
private static final String LEGACY_ERROR_PAGE_CLASS = "org.apache.catalina.deploy.ErrorPage";
private final String location;
private final String exceptionType;
private final int errorCode;
private final Object nativePage;
TomcatErrorPage(ErrorPage errorPage) {
this.location = errorPage.getPath();
this.exceptionType = errorPage.getExceptionName();
this.errorCode = errorPage.getStatusCode();
this.nativePage = createNativePage(errorPage);
}
private Object createNativePage(ErrorPage errorPage) {
Object nativePage = null;
try {
if (ClassUtils.isPresent(ERROR_PAGE_CLASS, null)) {
nativePage = BeanUtils
.instantiate(ClassUtils.forName(ERROR_PAGE_CLASS, null));
}
else if (ClassUtils.isPresent(LEGACY_ERROR_PAGE_CLASS, null)) {
nativePage = BeanUtils.instantiate(
ClassUtils.forName(LEGACY_ERROR_PAGE_CLASS, null));
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
catch (LinkageError ex) {
// Swallow and continue
}
return nativePage;
}
public void addToContext(Context context) {
Assert.state(this.nativePage != null,
"Neither Tomcat 7 nor 8 detected so no native error page exists");
if (ClassUtils.isPresent(ERROR_PAGE_CLASS, null)) {
org.apache.tomcat.util.descriptor.web.ErrorPage errorPage = (org.apache.tomcat.util.descriptor.web.ErrorPage) this.nativePage;
errorPage.setLocation(this.location);
errorPage.setErrorCode(this.errorCode);
errorPage.setExceptionType(this.exceptionType);
context.addErrorPage(errorPage);
}
else {
callMethod(this.nativePage, "setLocation", this.location, String.class);
callMethod(this.nativePage, "setErrorCode", this.errorCode, int.class);
callMethod(this.nativePage, "setExceptionType", this.exceptionType,
String.class);
callMethod(context, "addErrorPage", this.nativePage,
this.nativePage.getClass());
}
}
private void callMethod(Object target, String name, Object value, Class<?> type) {
Method method = ReflectionUtils.findMethod(target.getClass(), name, type);
ReflectionUtils.invokeMethod(method, target, value);
}
}
/** /**
* {@link LifecycleListener} that stores an empty merged web.xml. This is critical for * {@link LifecycleListener} that stores an empty merged web.xml. This is critical for
* Jasper to prevent warnings about missing web.xml files and to enable EL. * Jasper to prevent warnings about missing web.xml files and to enable EL.
......
/*
* 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.context.embedded.tomcat;
import java.lang.reflect.Method;
import org.apache.catalina.Context;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* Tomcat specific management for an {@link ErrorPage}.
*
* @author Dave Syer
* @author Phillip Webb
*/
class TomcatErrorPage {
private static final String ERROR_PAGE_CLASS = "org.apache.tomcat.util.descriptor.web.ErrorPage";
private static final String LEGACY_ERROR_PAGE_CLASS = "org.apache.catalina.deploy.ErrorPage";
private final String location;
private final String exceptionType;
private final int errorCode;
private final Object nativePage;
TomcatErrorPage(ErrorPage errorPage) {
this.location = errorPage.getPath();
this.exceptionType = errorPage.getExceptionName();
this.errorCode = errorPage.getStatusCode();
this.nativePage = createNativePage(errorPage);
}
private Object createNativePage(ErrorPage errorPage) {
Object nativePage = null;
try {
if (ClassUtils.isPresent(ERROR_PAGE_CLASS, null)) {
nativePage = BeanUtils
.instantiate(ClassUtils.forName(ERROR_PAGE_CLASS, null));
}
else if (ClassUtils.isPresent(LEGACY_ERROR_PAGE_CLASS, null)) {
nativePage = BeanUtils
.instantiate(ClassUtils.forName(LEGACY_ERROR_PAGE_CLASS, null));
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
catch (LinkageError ex) {
// Swallow and continue
}
return nativePage;
}
public void addToContext(Context context) {
Assert.state(this.nativePage != null,
"Neither Tomcat 7 nor 8 detected so no native error page exists");
if (ClassUtils.isPresent(ERROR_PAGE_CLASS, null)) {
org.apache.tomcat.util.descriptor.web.ErrorPage errorPage = (org.apache.tomcat.util.descriptor.web.ErrorPage) this.nativePage;
errorPage.setLocation(this.location);
errorPage.setErrorCode(this.errorCode);
errorPage.setExceptionType(this.exceptionType);
context.addErrorPage(errorPage);
}
else {
callMethod(this.nativePage, "setLocation", this.location, String.class);
callMethod(this.nativePage, "setErrorCode", this.errorCode, int.class);
callMethod(this.nativePage, "setExceptionType", this.exceptionType,
String.class);
callMethod(context, "addErrorPage", this.nativePage,
this.nativePage.getClass());
}
}
private void callMethod(Object target, String name, Object value, Class<?> type) {
Method method = ReflectionUtils.findMethod(target.getClass(), name, type);
ReflectionUtils.invokeMethod(method, target, value);
}
}
...@@ -33,10 +33,9 @@ import com.google.gson.reflect.TypeToken; ...@@ -33,10 +33,9 @@ import com.google.gson.reflect.TypeToken;
*/ */
public class GsonJsonParser implements JsonParser { public class GsonJsonParser implements JsonParser {
private static final TypeToken<List<Object>> LIST_TYPE = new TypeToken<List<Object>>() { private static final TypeToken<?> MAP_TYPE = new MapTypeToken();
};
private static final TypeToken<Map<String, Object>> MAP_TYPE = new TypeToken<Map<String, Object>>() { private static final TypeToken<?> LIST_TYPE = new ListTypeToken();
};
private Gson gson = new GsonBuilder().create(); private Gson gson = new GsonBuilder().create();
...@@ -62,4 +61,12 @@ public class GsonJsonParser implements JsonParser { ...@@ -62,4 +61,12 @@ public class GsonJsonParser implements JsonParser {
throw new IllegalArgumentException("Cannot parse JSON"); throw new IllegalArgumentException("Cannot parse JSON");
} }
private static final class MapTypeToken extends TypeToken<Map<String, Object>> {
}
private static final class ListTypeToken extends TypeToken<List<Object>> {
}
} }
...@@ -30,10 +30,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; ...@@ -30,10 +30,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
*/ */
public class JacksonJsonParser implements JsonParser { public class JacksonJsonParser implements JsonParser {
private static final TypeReference<List<Object>> LIST_TYPE = new TypeReference<List<Object>>() { private static final TypeReference<?> MAP_TYPE = new MapTypeReference();
};
private static final TypeReference<Map<String, Object>> MAP_TYPE = new TypeReference<Map<String, Object>>() { private static final TypeReference<?> LIST_TYPE = new ListTypeReference();
};
private final ObjectMapper objectMapper = new ObjectMapper(); private final ObjectMapper objectMapper = new ObjectMapper();
...@@ -57,4 +56,12 @@ public class JacksonJsonParser implements JsonParser { ...@@ -57,4 +56,12 @@ public class JacksonJsonParser implements JsonParser {
} }
} }
private static class MapTypeReference extends TypeReference<Map<String, Object>> {
};
private static class ListTypeReference extends TypeReference<List<Object>> {
};
} }
...@@ -79,12 +79,10 @@ public class TestEntityScanTests { ...@@ -79,12 +79,10 @@ public class TestEntityScanTests {
@Test @Test
public void valueAndBasePackagesThrows() throws Exception { public void valueAndBasePackagesThrows() throws Exception {
this.thrown.expect(AnnotationConfigurationException.class); this.thrown.expect(AnnotationConfigurationException.class);
this.thrown.expectMessage(allOf( this.thrown.expectMessage(allOf(containsString("'value'"),
containsString("'value'"), containsString("'basePackages'"), containsString("com.mycorp.entity"),
containsString("'basePackages'"),
containsString("com.mycorp.entity"),
containsString("com.mycorp"))); containsString("com.mycorp")));
new AnnotationConfigApplicationContext(ValueAndBasePackages.class); this.context = new AnnotationConfigApplicationContext(ValueAndBasePackages.class);
} }
@Test @Test
......
...@@ -78,12 +78,10 @@ public class ServletComponentScanRegistrarTests { ...@@ -78,12 +78,10 @@ public class ServletComponentScanRegistrarTests {
@Test @Test
public void packagesConfiguredWithBothValueAndBasePackages() { public void packagesConfiguredWithBothValueAndBasePackages() {
this.thrown.expect(AnnotationConfigurationException.class); this.thrown.expect(AnnotationConfigurationException.class);
this.thrown.expectMessage(allOf( this.thrown.expectMessage(allOf(containsString("'value'"),
containsString("'value'"), containsString("'basePackages'"), containsString("com.example.foo"),
containsString("'basePackages'"),
containsString("com.example.foo"),
containsString("com.example.bar"))); containsString("com.example.bar")));
new AnnotationConfigApplicationContext(ValueAndBasePackages.class); this.context = new AnnotationConfigApplicationContext(ValueAndBasePackages.class);
} }
@Test @Test
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment