From 0c00508b3cdec4d30641dd26d8503299e0391fd3 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 11 Sep 2018 14:21:56 -0700 Subject: [PATCH] Register ApplicationConversionService for context Update `SpringApplication` to automatically register the shared `ApplicationConversionService` instance with the `BeanFactory` and `Environment`. Closes gh-12148 --- .../boot/SpringApplication.java | 22 +++++++++++++++++- .../builder/SpringApplicationBuilder.java | 15 ++++++++++++ .../convert/ApplicationConversionService.java | 2 +- .../boot/SpringApplicationTests.java | 23 +++++++++++++++++++ .../simple/service/HelloWorldService.java | 13 +++++++++-- .../simple/SampleSimpleApplicationTests.java | 6 ++--- 6 files changed, 74 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index 3c17d435404..d8f95d516ca 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -45,6 +45,7 @@ import org.springframework.boot.Banner.Mode; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; +import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.boot.web.reactive.context.StandardReactiveWebEnvironment; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; @@ -214,6 +215,8 @@ public class SpringApplication { private boolean addCommandLineProperties = true; + private boolean addConversionService = true; + private Banner banner; private ResourceLoader resourceLoader; @@ -397,7 +400,6 @@ public class SpringApplication { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } - // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); @@ -503,6 +505,10 @@ public class SpringApplication { */ protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { + if (this.addConversionService) { + environment.setConversionService( + ApplicationConversionService.getSharedInstance()); + } configurePropertySources(environment, args); configureProfiles(environment, args); } @@ -644,6 +650,10 @@ public class SpringApplication { .setClassLoader(this.resourceLoader.getClassLoader()); } } + if (this.addConversionService) { + context.getBeanFactory().setConversionService( + ApplicationConversionService.getSharedInstance()); + } } /** @@ -1046,6 +1056,16 @@ public class SpringApplication { this.addCommandLineProperties = addCommandLineProperties; } + /** + * Sets if the {@link ApplicationConversionService} should be added to the application + * context's {@link Environment}. + * @param addConversionService if the application conversion service should be added + * @since 2.1.0 + */ + public void setAddConversionService(boolean addConversionService) { + this.addConversionService = addConversionService; + } + /** * Set default environment properties which will be used in addition to those in the * existing {@link Environment}. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java index e05f8868af2..50615b90b03 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java @@ -31,11 +31,13 @@ import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.boot.Banner; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; +import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.util.StringUtils; @@ -370,6 +372,19 @@ public class SpringApplicationBuilder { return this; } + /** + * Flag to indicate if the {@link ApplicationConversionService} should be added to the + * application context's {@link Environment}. + * @param addConversionService if the conversion service should be added. + * @return the current builder + * @since 2.1.0 + */ + public SpringApplicationBuilder setAddConversionService( + boolean addConversionService) { + this.application.setAddConversionService(addConversionService); + return this; + } + /** * Default properties for the environment in the form {@code key=value} or * {@code key:value}. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java index 83ad9a07ded..33aaab3a24a 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java @@ -57,7 +57,7 @@ public class ApplicationConversionService extends FormattingConversionService { * building it once needed. * @return the shared {@code ConversionService} instance (never {@code null}) */ - public static ConversionService getSharedInstance() { + public static ApplicationConversionService getSharedInstance() { ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance; if (sharedInstance == null) { synchronized (ApplicationConversionService.class) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index cb227433307..8fd562e5f94 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -56,6 +56,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.boot.context.event.SpringApplicationEvent; +import org.springframework.boot.convert.ApplicationConversionService; import org.springframework.boot.testsupport.rule.OutputCapture; import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; @@ -597,6 +598,28 @@ public class SpringApplicationTests { matchingPropertySource(PropertySource.class, "commandLineArgs")); } + @Test + public void contextUsesApplicationConversionService() { + SpringApplication application = new SpringApplication(ExampleConfig.class); + application.setWebApplicationType(WebApplicationType.NONE); + this.context = application.run(); + assertThat(this.context.getBeanFactory().getConversionService()) + .isInstanceOf(ApplicationConversionService.class); + assertThat(this.context.getEnvironment().getConversionService()) + .isInstanceOf(ApplicationConversionService.class); + } + + @Test + public void contextWhenHasAddConversionServiceFalseUsesRegularConversionService() { + SpringApplication application = new SpringApplication(ExampleConfig.class); + application.setWebApplicationType(WebApplicationType.NONE); + application.setAddConversionService(false); + this.context = application.run(); + assertThat(this.context.getBeanFactory().getConversionService()).isNull(); + assertThat(this.context.getEnvironment().getConversionService()) + .isNotInstanceOf(ApplicationConversionService.class); + } + @Test public void runCommandLineRunnersAndApplicationRunners() { SpringApplication application = new SpringApplication(CommandLineRunConfig.class); diff --git a/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java b/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java index 751a5cff474..69ea7065dd7 100644 --- a/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java +++ b/spring-boot-samples/spring-boot-sample-simple/src/main/java/sample/simple/service/HelloWorldService.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2018 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,6 +16,8 @@ package sample.simple.service; +import java.time.Duration; + import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -25,8 +27,15 @@ public class HelloWorldService { @Value("${name:World}") private String name; + @Value("${duration:10s}") + private Duration duration; + public String getHelloMessage() { - return "Hello " + this.name; + return "Hello " + this.name + " for " + this.duration.getSeconds() + " seconds"; + } + + public Duration getDuration() { + return this.duration; } } diff --git a/spring-boot-samples/spring-boot-sample-simple/src/test/java/sample/simple/SampleSimpleApplicationTests.java b/spring-boot-samples/spring-boot-sample-simple/src/test/java/sample/simple/SampleSimpleApplicationTests.java index 4b70473be40..aeae9823104 100644 --- a/spring-boot-samples/spring-boot-sample-simple/src/test/java/sample/simple/SampleSimpleApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-simple/src/test/java/sample/simple/SampleSimpleApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -62,9 +62,9 @@ public class SampleSimpleApplicationTests { @Test public void testCommandLineOverrides() throws Exception { - SampleSimpleApplication.main(new String[] { "--name=Gordon" }); + SampleSimpleApplication.main(new String[] { "--name=Gordon", "--duration=1m" }); String output = this.outputCapture.toString(); - assertThat(output).contains("Hello Gordon"); + assertThat(output).contains("Hello Gordon for 60 seconds"); } }