This commit is contained in:
Phillip Webb 2014-05-15 09:15:35 +01:00
parent 158b6a5c07
commit 01fcf61140
15 changed files with 170 additions and 131 deletions

View File

@ -153,14 +153,12 @@ public class DataSourceAutoConfiguration {
@ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX) @ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX)
@Bean @Bean
public DataSource dataSource() { public DataSource dataSource() {
// @formatter:off
DataSourceBuilder factory = DataSourceBuilder DataSourceBuilder factory = DataSourceBuilder
.create(this.properties.getClassLoader()) .create(this.properties.getClassLoader())
.driverClassName(this.properties.getDriverClassName()) .driverClassName(this.properties.getDriverClassName())
.url(this.properties.getUrl()) .url(this.properties.getUrl())
.username(this.properties.getUsername()) .username(this.properties.getUsername())
.password(this.properties.getPassword()); .password(this.properties.getPassword());
// @formatter:on
return factory.build(); return factory.build();
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -37,6 +37,7 @@ import org.springframework.util.ClassUtils;
* <code>@ConfigurationProperties</code>. * <code>@ConfigurationProperties</code>.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.1.0
*/ */
public class DataSourceBuilder { public class DataSourceBuilder {

View File

@ -26,6 +26,7 @@ import org.springframework.util.StringUtils;
* Base class for configuration of a database pool. * Base class for configuration of a database pool.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.1.0
*/ */
@ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX) @ConfigurationProperties(prefix = DataSourceAutoConfiguration.CONFIGURATION_PREFIX)
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean { public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -36,6 +36,7 @@ import org.springframework.util.ClassUtils;
* <code>@Bean</code> definition. * <code>@Bean</code> definition.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.1.0
*/ */
public class EntityManagerFactoryBuilder { public class EntityManagerFactoryBuilder {
@ -48,7 +49,6 @@ public class EntityManagerFactoryBuilder {
/** /**
* Create a new instance passing in the common pieces that will be shared if multiple * Create a new instance passing in the common pieces that will be shared if multiple
* EntityManagerFactory instances are created. * EntityManagerFactory instances are created.
*
* @param jpaVendorAdapter a vendor adapter * @param jpaVendorAdapter a vendor adapter
* @param properties common configuration options, including generic map for JPA * @param properties common configuration options, including generic map for JPA
* vendor properties * vendor properties
@ -68,8 +68,6 @@ public class EntityManagerFactoryBuilder {
/** /**
* A fluent builder for a LocalContainerEntityManagerFactoryBean. * A fluent builder for a LocalContainerEntityManagerFactoryBean.
*
* @author Dave Syer
*/ */
public class Builder { public class Builder {
@ -85,7 +83,6 @@ public class EntityManagerFactoryBuilder {
/** /**
* The names of packages to scan for <code>@Entity</code> annotations. * The names of packages to scan for <code>@Entity</code> annotations.
*
* @param packagesToScan packages to scan * @param packagesToScan packages to scan
* @return the builder for fluent usage * @return the builder for fluent usage
*/ */
@ -97,7 +94,6 @@ public class EntityManagerFactoryBuilder {
/** /**
* The classes whose packages should be scanned for <code>@Entity</code> * The classes whose packages should be scanned for <code>@Entity</code>
* annotations. * annotations.
*
* @param basePackageClasses the classes to use * @param basePackageClasses the classes to use
* @return the builder for fluent usage * @return the builder for fluent usage
*/ */
@ -114,7 +110,6 @@ public class EntityManagerFactoryBuilder {
* The name of the persistence unit. If only building one EntityManagerFactory you * The name of the persistence unit. If only building one EntityManagerFactory you
* can omit this, but if there are more than one in the same application you * can omit this, but if there are more than one in the same application you
* should give them distinct names. * should give them distinct names.
*
* @param persistenceUnit the name of the persistence unit * @param persistenceUnit the name of the persistence unit
* @return the builder for fluent usage * @return the builder for fluent usage
*/ */
@ -127,7 +122,6 @@ public class EntityManagerFactoryBuilder {
* Generic properties for standard JPA or vendor-specific configuration. These * Generic properties for standard JPA or vendor-specific configuration. These
* properties override any values provided in the {@link JpaProperties} used to * properties override any values provided in the {@link JpaProperties} used to
* create the builder. * create the builder.
*
* @param properties the properties to use * @param properties the properties to use
* @return the builder for fluent usage * @return the builder for fluent usage
*/ */

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -30,6 +30,7 @@ import org.springframework.orm.jpa.vendor.Database;
* External configuration properties for a JPA EntityManagerFactory created by Spring. * External configuration properties for a JPA EntityManagerFactory created by Spring.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.1.0
*/ */
@ConfigurationProperties(prefix = "spring.jpa") @ConfigurationProperties(prefix = "spring.jpa")
public class JpaProperties { public class JpaProperties {

View File

@ -39,7 +39,7 @@ import redis.clients.jedis.JedisPoolConfig;
/** /**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Redis support. * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Redis support.
* *
* @author Dave Syer * @author Dave Syer
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Christian Dupuis * @author Christian Dupuis
@ -80,13 +80,7 @@ public class RedisAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
RedisConnectionFactory redisConnectionFactory() throws UnknownHostException { RedisConnectionFactory redisConnectionFactory() throws UnknownHostException {
JedisConnectionFactory factory = null; JedisConnectionFactory factory = createJedisConnectionFactory();
if (this.properties.getPool() == null) {
factory = new JedisConnectionFactory();
}
else {
factory = new JedisConnectionFactory(jedisPoolConfig());
}
factory.setHostName(this.properties.getHost()); factory.setHostName(this.properties.getHost());
factory.setPort(this.properties.getPort()); factory.setPort(this.properties.getPort());
if (this.properties.getPassword() != null) { if (this.properties.getPassword() != null) {
@ -95,6 +89,13 @@ public class RedisAutoConfiguration {
return factory; return factory;
} }
private JedisConnectionFactory createJedisConnectionFactory() {
if (this.properties.getPool() != null) {
return new JedisConnectionFactory(jedisPoolConfig());
}
return new JedisConnectionFactory();
}
private JedisPoolConfig jedisPoolConfig() { private JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig config = new JedisPoolConfig(); JedisPoolConfig config = new JedisPoolConfig();
RedisProperties.Pool props = this.properties.getPool(); RedisProperties.Pool props = this.properties.getPool();

View File

@ -48,9 +48,11 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
/** /**
* Test that a {@link DataSource} can be exposed as JSON for actuator endpoints.
*
* @author Dave Syer * @author Dave Syer
*/ */
public class JsonSerializationTests { public class DataSourceJsonSerializationTests {
@Test @Test
public void serializerFactory() throws Exception { public void serializerFactory() throws Exception {
@ -69,7 +71,6 @@ public class JsonSerializationTests {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(DataSource.class, DataSourceJson.class); mapper.addMixInAnnotations(DataSource.class, DataSourceJson.class);
String value = mapper.writeValueAsString(dataSource); String value = mapper.writeValueAsString(dataSource);
System.err.println(value);
assertTrue(value.contains("\"url\":")); assertTrue(value.contains("\"url\":"));
assertEquals(1, StringUtils.countOccurrencesOf(value, "\"url\"")); assertEquals(1, StringUtils.countOccurrencesOf(value, "\"url\""));
} }

View File

@ -28,6 +28,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
/** /**
* Tests for {@link RedisAutoConfiguration}.
*
* @author Dave Syer * @author Dave Syer
* @author Christian Dupuis * @author Christian Dupuis
*/ */

View File

@ -298,7 +298,7 @@ to specify profile-specific values.
[[howto-discover-build-in-options-for-external-properties]] [[howto-discover-build-in-options-for-external-properties]]
=== Discover built-in options for external properties === Discover built-in options for external properties
Spring Boot binds external properties from `application.properties` (or `.yml`) (and Spring Boot binds external properties from `application.properties` (or `.yml`) (and
other places) into an application at runtime. There is not (and technically cannot be) other places) into an application at runtime. There is not (and technically cannot be)
an exhaustive list of all supported properties in a single location because contributions an exhaustive list of all supported properties in a single location because contributions
can come from additional jar files on your classpath. can come from additional jar files on your classpath.
@ -739,7 +739,7 @@ exposed in the `MultipartProperties` class. If you want to specify that files be
unlimited, for example, set the `multipart.maxFileSize` property to `-1`. unlimited, for example, set the `multipart.maxFileSize` property to `-1`.
The multipart support is helpful when you want to receive multipart encoded file data as The multipart support is helpful when you want to receive multipart encoded file data as
a `@RequestParam`-annotated parameter of type `MultipartFile` in a Spring MVC controller a `@RequestParam`-annotated parameter of type `MultipartFile` in a Spring MVC controller
handler method. handler method.
See the {sc-spring-boot-autoconfigure}/web/MultipartAutoConfiguration.{sc-ext}[`MultipartAutoConfiguration`] s See the {sc-spring-boot-autoconfigure}/web/MultipartAutoConfiguration.{sc-ext}[`MultipartAutoConfiguration`] s
@ -769,7 +769,7 @@ configuration in your hands.
[[howto-customize-view-resolvers]] [[howto-customize-view-resolvers]]
=== Customize ViewResolvers === Customize ViewResolvers
A `ViewResolver` is a core component of Spring MVC, translating view names in A `ViewResolver` is a core component of Spring MVC, translating view names in
`@Controller` to actual `View` implementations. Note that `ViewResolvers` are mainly `@Controller` to actual `View` implementations. Note that `ViewResolvers` are mainly
used in UI applications, rather than REST-style services (a `View` is not used to render used in UI applications, rather than REST-style services (a `View` is not used to render
a `@ResponseBody`). There are many implementations of `ViewResolver` to choose from, and a `@ResponseBody`). There are many implementations of `ViewResolver` to choose from, and
Spring on its own is not opinionated about which ones you should use. Spring Boot, on the Spring on its own is not opinionated about which ones you should use. Spring Boot, on the
@ -833,7 +833,7 @@ Spring Boot has no mandatory logging dependence, except for the `commons-logging
which there are many implementations to choose from. To use http://logback.qos.ch[Logback] which there are many implementations to choose from. To use http://logback.qos.ch[Logback]
you need to include it, and some bindings for `commons-logging` on the classpath. The you need to include it, and some bindings for `commons-logging` on the classpath. The
simplest way to do that is through the starter poms which all depend on simplest way to do that is through the starter poms which all depend on
`spring-boot-starter-logging`. For a web application you only need `spring-boot-starter-logging`. For a web application you only need
`spring-boot-starter-web` since it depends transitively on the logging starter. `spring-boot-starter-web` since it depends transitively on the logging starter.
For example, using Maven: For example, using Maven:
@ -894,7 +894,7 @@ requires some jiggling with excludes, e.g. in Maven:
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>
@ -925,57 +925,58 @@ action.
[[howto-configure-a-datasource]] [[howto-configure-a-datasource]]
=== Configure a DataSource === Configure a DataSource
To override the default settings just define a `@Bean` of your own of type `DataSource`. To override the default settings just define a `@Bean` of your own of type `DataSource`.
Spring Boot provides a utility builder class `DataSourceBuilder` that can be used Spring Boot provides a utility builder class `DataSourceBuilder` that can be used
to create one of the standard ones (if it is on the classpath), or you can just create to create one of the standard ones (if it is on the classpath), or you can just create
your own, and bind it to a set of `Environment` properties e.g. your own, and bind it to a set of `Environment` properties e.g.
[source,java,indent=0,subs="verbatim,quotes,attributes"] [source,java,indent=0,subs="verbatim,quotes,attributes"]
---- ----
@Bean @Bean
@ConfigurationProperties(prefix="datasource.mine") @ConfigurationProperties(prefix="datasource.mine")
public DataSource dataSource() { public DataSource dataSource() {
return new FancyDataSource(); return new FancyDataSource();
} }
---- ----
[source,properties,indent=0] [source,properties,indent=0]
---- ----
datasource.mine.jdbcUrl=jdbc:h2:mem:mydb datasource.mine.jdbcUrl=jdbc:h2:mem:mydb
datasource.mine.user=sa datasource.mine.user=sa
datasource.mine.poolSize=30 datasource.mine.poolSize=30
---- ----
See '<<spring-boot-features.adoc#boot-features-configure-datasource>>' in the See '<<spring-boot-features.adoc#boot-features-configure-datasource>>' in the
``Spring Boot features'' section and the ``Spring Boot features'' section and the
{sc-spring-boot-autoconfigure}/jdbc/DataSourceAutoConfiguration.{sc-ext}[`DataSourceAutoConfiguration`] {sc-spring-boot-autoconfigure}/jdbc/DataSourceAutoConfiguration.{sc-ext}[`DataSourceAutoConfiguration`]
class for more details. class for more details.
[[howto-two-datasources]] [[howto-two-datasources]]
=== Configure Two DataSources === Configure Two DataSources
Creating more than one data source works the same as creating the first one. Creating more than one data source works the same as creating the first one. You might
You might want to mark one of them as `@Primary` if you are using the default want to mark one of them as `@Primary` if you are using the default auto-configuration for
auto-configuration for JDBC or JPA (then that one will be picked up by any JDBC or JPA (then that one will be picked up by any `@Autowired` injections).
`@Autowired` injections).
[source,java,indent=0,subs="verbatim,quotes,attributes"] [source,java,indent=0,subs="verbatim,quotes,attributes"]
---- ----
@Bean @Bean
@Primary @Primary
@ConfigurationProperties(prefix="datasource.primary") @ConfigurationProperties(prefix="datasource.primary")
public DataSource primaryDataSource() { public DataSource primaryDataSource() {
return new FancyDataSource(); return new FancyDataSource();
} }
@Bean @Bean
@ConfigurationProperties(prefix="datasource.secondary") @ConfigurationProperties(prefix="datasource.secondary")
public DataSource secondaryDataSource() { public DataSource secondaryDataSource() {
return new FancyDataSource(); return new FancyDataSource();
} }
---- ----
[[howto-use-spring-data-repositories]] [[howto-use-spring-data-repositories]]
=== Use Spring Data repositories === Use Spring Data repositories
Spring Data can create implementations for you of `@Repository` interfaces of various Spring Data can create implementations for you of `@Repository` interfaces of various
@ -1030,7 +1031,7 @@ configuration properties. The most common options to set are:
---- ----
(Because of relaxed data binding hyphens or underscores should work equally well as (Because of relaxed data binding hyphens or underscores should work equally well as
property keys.) The `ddl-auto` setting is a special case in that it has different property keys.) The `ddl-auto` setting is a special case in that it has different
defaults depending on whether you are using an embedded database (`create-drop`) or not defaults depending on whether you are using an embedded database (`create-drop`) or not
(`none`). In addition all properties in `spring.jpa.properties.*` are passed through as (`none`). In addition all properties in `spring.jpa.properties.*` are passed through as
normal JPA properties (with the prefix stripped) when the local `EntityManagerFactory` is normal JPA properties (with the prefix stripped) when the local `EntityManagerFactory` is
@ -1041,22 +1042,24 @@ and {sc-spring-boot-autoconfigure}/orm/jpa/JpaBaseConfiguration.{sc-ext}[`JpaBas
for more details. for more details.
[[howto-use-custom-entity-manager]] [[howto-use-custom-entity-manager]]
=== Use a custom EntityManagerFactory === Use a custom EntityManagerFactory
To take full control of the configuration of the `EntityManagerFactory`, you need to add To take full control of the configuration of the `EntityManagerFactory`, you need to add
a `@Bean` named "entityManagerFactory". Spring Boot auto-configuration switches off its entity manager a `@Bean` named "entityManagerFactory". Spring Boot auto-configuration switches off its
based on the presence of a bean of that type. entity manager based on the presence of a bean of that type.
[[howto-use-two-entity-managers]] [[howto-use-two-entity-managers]]
=== Use Two EntityManagers === Use Two EntityManagers
Even if the default `EntityManagerFactory` works fine, you will need Even if the default `EntityManagerFactory` works fine, you will need to define a new one
to define a new one because otherwise the presence of the second bean because otherwise the presence of the second bean of that type will switch off the
of that type will switch off the default. To make it easy to do that default. To make it easy to do that you can use the convenient `EntityManagerBuilder`
you can use the convenient `EntityManagerBuilder` provided by Spring provided by Spring Boot, or if you prefer you can just use the
Boot, or if you prefer you can just use the
`LocalContainerEntityManagerFactoryBean` directly from Spring ORM. `LocalContainerEntityManagerFactoryBean` directly from Spring ORM.
Example: Example:
[source,java,indent=0,subs="verbatim,quotes,attributes"] [source,java,indent=0,subs="verbatim,quotes,attributes"]
@ -1069,8 +1072,8 @@ Example:
return builder return builder
.dataSource(customerDataSource()) .dataSource(customerDataSource())
.packages(Customer.class) .packages(Customer.class)
.persistenceUnit("customers") .persistenceUnit("customers")
.build(); .build();
} }
@Bean @Bean
@ -1079,19 +1082,19 @@ Example:
return builder return builder
.dataSource(orderDataSource()) .dataSource(orderDataSource())
.packages(Order.class) .packages(Order.class)
.persistenceUnit("orders") .persistenceUnit("orders")
.build(); .build();
} }
---- ----
The configuration above almost works on its own. To complete the The configuration above almost works on its own. To complete the picture you need to
picture you need to configure `TransactionManagers` for the two configure `TransactionManagers` for the two `EntityManagers` as well. One of them could
`EntityManagers` as well. One of them could be picked up by the be picked up by the default `JpaTransactionManager` in Spring Boot if you mark it as
default `JpaTransactionManager` in Spring Boot if you mark it as `@Primary`. The other would have to be explicitly injected into a new instance. Or you
`@Primary`. The other would have to be explicitly injected into a new might be able to use a JTA transaction manager spanning both.
instance. Or you might be able to use a JTA transaction manager
spanning both.
[[howto-use-traditional-persistence-xml]] [[howto-use-traditional-persistence-xml]]
=== Use a traditional persistence.xml === Use a traditional persistence.xml
@ -1312,7 +1315,7 @@ use this in a webapp is to inject it into a void method in a
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication() auth.inMemoryAuthentication()
.withUser("barry").password("password").roles("USER"); // ... etc. .withUser("barry").password("password").roles("USER"); // ... etc.
} }
// ... other stuff for application security // ... other stuff for application security
@ -1330,7 +1333,7 @@ is a useful template to follow.
[[howto-enable-https]] [[howto-enable-https]]
=== Enable HTTPS when running behind a proxy server === Enable HTTPS when running behind a proxy server
Ensuring that all your main endpoints are only available over HTTPS is an important Ensuring that all your main endpoints are only available over HTTPS is an important
chore for any application. If you are using Tomcat as a servlet container, then chore for any application. If you are using Tomcat as a servlet container, then
Spring Boot will add Tomcat's own `RemoteIpValve` automatically if it detects some Spring Boot will add Tomcat's own `RemoteIpValve` automatically if it detects some
environment settings, and you should be able to rely on the `HttpServletRequest` to environment settings, and you should be able to rely on the `HttpServletRequest` to
report whether it is secure or not (even downstream of a proxy server that handles the report whether it is secure or not (even downstream of a proxy server that handles the
@ -1573,7 +1576,7 @@ For a non-web application it should be easy (throw away the code that creates yo
`ApplicationContext` and replace it with calls to `SpringApplication` or `ApplicationContext` and replace it with calls to `SpringApplication` or
`SpringApplicationBuilder`). Spring MVC web applications are generally amenable to first `SpringApplicationBuilder`). Spring MVC web applications are generally amenable to first
creating a deployable war application, and then migrating it later to an executable war creating a deployable war application, and then migrating it later to an executable war
and/or jar. Useful reading is in the http://spring.io/guides/gs/convert-jar-to-war/[Getting and/or jar. Useful reading is in the http://spring.io/guides/gs/convert-jar-to-war/[Getting
Started Guide on Converting a jar to a war]. Started Guide on Converting a jar to a war].
Create a deployable war by extending `SpringBootServletInitializer` (e.g. in a class Create a deployable war by extending `SpringBootServletInitializer` (e.g. in a class

View File

@ -44,7 +44,7 @@ dependencies {
compile("org.springframework.boot:spring-boot-starter-security") compile("org.springframework.boot:spring-boot-starter-security")
compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-starter-web")
compile("com.h2database:h2") compile("com.h2database:h2")
testCompile("org.springframework.boot:spring-boot-starter-test") testCompile("org.springframework.boot:spring-boot-starter-test")
insecure configurations.runtime insecure configurations.runtime

View File

@ -110,7 +110,7 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
@Override @Override
public void execute() throws MojoExecutionException, MojoFailureException { public void execute() throws MojoExecutionException, MojoFailureException {
if (project.getPackaging().equals("pom")) { if (this.project.getPackaging().equals("pom")) {
getLog().debug("repackage goal could not be applied to pom project."); getLog().debug("repackage goal could not be applied to pom project.");
return; return;
} }

View File

@ -0,0 +1,55 @@
/*
* Copyright 2012-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.maven;
import org.codehaus.plexus.util.cli.CommandLineUtils;
/**
* Parse and expose arguments specified as {@link RunMojo} parameters.
*
* @author Stephane Nicoll
* @since 1.1.0
*/
class RunArguments {
private static final String[] NO_ARGS = {};
private final String[] args;
public RunArguments(String arguments) {
this.args = parseArgs(arguments);
}
private String[] parseArgs(String arguments) {
if (arguments == null || arguments.trim().isEmpty()) {
return NO_ARGS;
}
try {
arguments = arguments.replace('\n', ' ').replace('\t', ' ');
return CommandLineUtils.translateCommandline(arguments);
}
catch (Exception ex) {
throw new IllegalArgumentException("Failed to parse arguments [" + arguments
+ "]", ex);
}
}
public String[] asArray() {
return this.args;
}
}

View File

@ -39,8 +39,6 @@ import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter; import org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter;
import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts; import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.springframework.boot.loader.tools.FileUtils; import org.springframework.boot.loader.tools.FileUtils;
import org.springframework.boot.loader.tools.JavaExecutable; import org.springframework.boot.loader.tools.JavaExecutable;
import org.springframework.boot.loader.tools.MainClassFinder; import org.springframework.boot.loader.tools.MainClassFinder;
@ -91,9 +89,8 @@ public class RunMojo extends AbstractDependencyFilterMojo {
private Boolean noverify; private Boolean noverify;
/** /**
* JVM arguments that should be associated with the forked process used * JVM arguments that should be associated with the forked process used to run the
* to run the application. On command line, make sure to wrap multiple * application. On command line, make sure to wrap multiple values between quotes.
* values between quotes.
* @since 1.1 * @since 1.1
*/ */
@Parameter(property = "run.jvmArguments") @Parameter(property = "run.jvmArguments")
@ -176,15 +173,23 @@ public class RunMojo extends AbstractDependencyFilterMojo {
} }
} }
private void addJvmArgs(List<String> args) { private void addAgents(List<String> args) {
String[] jvmArgs = parseArgs(this.jvmArguments); findAgent();
Collections.addAll(args, jvmArgs); if (this.agent != null) {
logArguments("JVM argument(s): ", jvmArgs); getLog().info("Attaching agents: " + Arrays.asList(this.agent));
for (File agent : this.agent) {
args.add("-javaagent:" + agent);
}
}
if (this.noverify) {
args.add("-noverify");
}
} }
private void addArgs(List<String> args) { private void addJvmArgs(List<String> args) {
Collections.addAll(args, this.arguments); RunArguments jvmArguments = new RunArguments(this.jvmArguments);
logArguments("Application argument(s): ", this.arguments); Collections.addAll(args, jvmArguments.asArray());
logArguments("JVM argument(s): ", jvmArguments.asArray());
} }
private void addClasspath(List<String> args) throws MojoExecutionException { private void addClasspath(List<String> args) throws MojoExecutionException {
@ -203,17 +208,9 @@ public class RunMojo extends AbstractDependencyFilterMojo {
} }
} }
private void addAgents(List<String> args) { private void addArgs(List<String> args) {
findAgent(); Collections.addAll(args, this.arguments);
if (this.agent != null) { logArguments("Application argument(s): ", this.arguments);
getLog().info("Attaching agents: " + Arrays.asList(this.agent));
for (File agent : this.agent) {
args.add("-javaagent:" + agent);
}
}
if (this.noverify) {
args.add("-noverify");
}
} }
private final String getStartClass() throws MojoExecutionException { private final String getStartClass() throws MojoExecutionException {
@ -292,28 +289,6 @@ public class RunMojo extends AbstractDependencyFilterMojo {
getLog().debug(sb.toString().trim()); getLog().debug(sb.toString().trim());
} }
/**
* Parse the arguments parameters and return individual arguments.
*
* @param arguments the arguments line to parse
* @return the individual arguments
*/
static String[] parseArgs(String arguments) {
if (arguments == null || arguments.trim().isEmpty()) {
return new String[]{};
}
String args = arguments.replace('\n', ' ');
args = args.replace('\t', ' ');
try {
return CommandLineUtils.translateCommandline(args);
}
catch (Exception e) {
throw new IllegalArgumentException("Failed to parse arguments [" + arguments + "]", e);
}
}
private static class TestArtifactFilter extends AbstractArtifactFeatureFilter { private static class TestArtifactFilter extends AbstractArtifactFeatureFilter {
public TestArtifactFilter() { public TestArtifactFilter() {
super("", Artifact.SCOPE_TEST); super("", Artifact.SCOPE_TEST);

View File

@ -16,41 +16,44 @@
package org.springframework.boot.maven; package org.springframework.boot.maven;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/** /**
* * Tests for {@link RunArguments}.
*
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
public class RunMojoTests { public class RunArgumentsTests {
@Test @Test
public void parseNull() { public void parseNull() {
String[] args = RunMojo.parseArgs(null); String[] args = parseArgs(null);
assertNotNull(args); assertNotNull(args);
assertEquals(0, args.length); assertEquals(0, args.length);
} }
@Test @Test
public void parseEmpty() { public void parseEmpty() {
String[] args = RunMojo.parseArgs(" "); String[] args = parseArgs(" ");
assertNotNull(args); assertNotNull(args);
assertEquals(0, args.length); assertEquals(0, args.length);
} }
@Test @Test
public void parseDebugFlags() { public void parseDebugFlags() {
String[] args = RunMojo.parseArgs("-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"); String[] args = parseArgs("-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005");
assertEquals(2, args.length); assertEquals(2, args.length);
assertEquals("-Xdebug", args[0]); assertEquals("-Xdebug", args[0]);
assertEquals("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005", args[1]); assertEquals("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005",
args[1]);
} }
@Test @Test
public void parseWithExtraSpaces() { public void parseWithExtraSpaces() {
String[] args = RunMojo.parseArgs(" -Dfoo=bar -Dfoo2=bar2 "); String[] args = parseArgs(" -Dfoo=bar -Dfoo2=bar2 ");
assertEquals(2, args.length); assertEquals(2, args.length);
assertEquals("-Dfoo=bar", args[0]); assertEquals("-Dfoo=bar", args[0]);
assertEquals("-Dfoo2=bar2", args[1]); assertEquals("-Dfoo2=bar2", args[1]);
@ -58,8 +61,7 @@ public class RunMojoTests {
@Test @Test
public void parseWithNewLinesAndTabs() { public void parseWithNewLinesAndTabs() {
String[] args = RunMojo.parseArgs(" -Dfoo=bar \n" + String[] args = parseArgs(" -Dfoo=bar \n" + "\t\t -Dfoo2=bar2 ");
"\t\t -Dfoo2=bar2 ");
assertEquals(2, args.length); assertEquals(2, args.length);
assertEquals("-Dfoo=bar", args[0]); assertEquals("-Dfoo=bar", args[0]);
assertEquals("-Dfoo2=bar2", args[1]); assertEquals("-Dfoo2=bar2", args[1]);
@ -67,9 +69,13 @@ public class RunMojoTests {
@Test @Test
public void quoteHandledProperly() { public void quoteHandledProperly() {
String[] args = RunMojo.parseArgs("-Dvalue=\"My Value\" "); String[] args = parseArgs("-Dvalue=\"My Value\" ");
assertEquals(1, args.length); assertEquals(1, args.length);
assertEquals("-Dvalue=My Value", args[0]); assertEquals("-Dvalue=My Value", args[0]);
} }
private String[] parseArgs(String args) {
return new RunArguments(args).asArray();
}
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,10 +31,11 @@ import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.MethodCallback; import org.springframework.util.ReflectionUtils.MethodCallback;
/** /**
* Utility class to memoize <code>@Bean</code> definition meta data during initialization * Utility class to memorize <code>@Bean</code> definition meta data during initialization
* of the bean factory. * of the bean factory.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.1.0
*/ */
public class ConfigurationBeanFactoryMetaData implements BeanFactoryPostProcessor { public class ConfigurationBeanFactoryMetaData implements BeanFactoryPostProcessor {