Skip to content

Commit 0f642df

Browse files
committed
Merge pull request #17064 from nosan
* pr/17064: Polish "Add Printer and Parser beans to conversion service" Add Printer and Parser beans to conversion service Closes gh-17064
2 parents 30cfe7b + 9db2031 commit 0f642df

File tree

6 files changed

+325
-36
lines changed

6 files changed

+325
-36
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.boot.autoconfigure.web.reactive;
1818

1919
import java.time.Duration;
20-
import java.util.Collection;
2120

2221
import org.apache.commons.logging.Log;
2322
import org.apache.commons.logging.LogFactory;
@@ -38,15 +37,13 @@
3837
import org.springframework.boot.autoconfigure.web.ResourceProperties;
3938
import org.springframework.boot.autoconfigure.web.format.WebConversionService;
4039
import org.springframework.boot.context.properties.EnableConfigurationProperties;
40+
import org.springframework.boot.convert.ApplicationConversionService;
4141
import org.springframework.boot.web.codec.CodecCustomizer;
4242
import org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter;
4343
import org.springframework.context.annotation.Bean;
4444
import org.springframework.context.annotation.Configuration;
4545
import org.springframework.context.annotation.Import;
4646
import org.springframework.core.Ordered;
47-
import org.springframework.core.convert.converter.Converter;
48-
import org.springframework.core.convert.converter.GenericConverter;
49-
import org.springframework.format.Formatter;
5047
import org.springframework.format.FormatterRegistry;
5148
import org.springframework.format.support.FormattingConversionService;
5249
import org.springframework.http.codec.ServerCodecConfigurer;
@@ -176,26 +173,13 @@ public void configureViewResolvers(ViewResolverRegistry registry) {
176173

177174
@Override
178175
public void addFormatters(FormatterRegistry registry) {
179-
for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
180-
registry.addConverter(converter);
181-
}
182-
for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
183-
registry.addConverter(converter);
184-
}
185-
for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
186-
registry.addFormatter(formatter);
187-
}
188-
}
189-
190-
private <T> Collection<T> getBeansOfType(Class<T> type) {
191-
return this.beanFactory.getBeansOfType(type).values();
176+
ApplicationConversionService.addBeans(registry, this.beanFactory);
192177
}
193178

194179
private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
195180
if (this.resourceHandlerRegistrationCustomizer != null) {
196181
this.resourceHandlerRegistrationCustomizer.customize(registration);
197182
}
198-
199183
}
200184

201185
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.time.Duration;
2020
import java.util.ArrayList;
2121
import java.util.Arrays;
22-
import java.util.Collection;
2322
import java.util.Collections;
2423
import java.util.List;
2524
import java.util.ListIterator;
@@ -55,6 +54,7 @@
5554
import org.springframework.boot.autoconfigure.web.ResourceProperties.Strategy;
5655
import org.springframework.boot.autoconfigure.web.format.WebConversionService;
5756
import org.springframework.boot.context.properties.EnableConfigurationProperties;
57+
import org.springframework.boot.convert.ApplicationConversionService;
5858
import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter;
5959
import org.springframework.boot.web.servlet.filter.OrderedHiddenHttpMethodFilter;
6060
import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter;
@@ -66,13 +66,10 @@
6666
import org.springframework.context.annotation.Primary;
6767
import org.springframework.core.Ordered;
6868
import org.springframework.core.annotation.Order;
69-
import org.springframework.core.convert.converter.Converter;
70-
import org.springframework.core.convert.converter.GenericConverter;
7169
import org.springframework.core.io.ClassPathResource;
7270
import org.springframework.core.io.Resource;
7371
import org.springframework.core.io.ResourceLoader;
7472
import org.springframework.core.task.AsyncTaskExecutor;
75-
import org.springframework.format.Formatter;
7673
import org.springframework.format.FormatterRegistry;
7774
import org.springframework.format.support.FormattingConversionService;
7875
import org.springframework.http.CacheControl;
@@ -298,19 +295,7 @@ public MessageCodesResolver getMessageCodesResolver() {
298295

299296
@Override
300297
public void addFormatters(FormatterRegistry registry) {
301-
for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
302-
registry.addConverter(converter);
303-
}
304-
for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
305-
registry.addConverter(converter);
306-
}
307-
for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
308-
registry.addFormatter(formatter);
309-
}
310-
}
311-
312-
private <T> Collection<T> getBeansOfType(Class<T> type) {
313-
return this.beanFactory.getBeansOfType(type).values();
298+
ApplicationConversionService.addBeans(registry, this.beanFactory);
314299
}
315300

316301
@Override

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Collections;
2020
import java.util.Date;
2121
import java.util.List;
22+
import java.util.Locale;
2223
import java.util.Map;
2324
import java.util.concurrent.TimeUnit;
2425

@@ -40,7 +41,10 @@
4041
import org.springframework.context.annotation.Import;
4142
import org.springframework.core.Ordered;
4243
import org.springframework.core.annotation.Order;
44+
import org.springframework.core.convert.ConversionService;
4345
import org.springframework.core.io.ClassPathResource;
46+
import org.springframework.format.Parser;
47+
import org.springframework.format.Printer;
4448
import org.springframework.format.support.FormattingConversionService;
4549
import org.springframework.http.CacheControl;
4650
import org.springframework.http.codec.ServerCodecConfigurer;
@@ -373,6 +377,16 @@ void cacheControl() {
373377
Assertions.setExtractBareNamePropertyMethods(true);
374378
}
375379

380+
@Test
381+
void customPrinterAndParserShouldBeRegisteredAsConverters() {
382+
this.contextRunner.withUserConfiguration(ParserConfiguration.class, PrinterConfiguration.class)
383+
.run((context) -> {
384+
ConversionService service = context.getBean(ConversionService.class);
385+
assertThat(service.convert(new Example("spring", new Date()), String.class)).isEqualTo("spring");
386+
assertThat(service.convert("boot", Example.class)).extracting(Example::getName).isEqualTo("boot");
387+
});
388+
}
389+
376390
private Map<PathPattern, Object> getHandlerMap(ApplicationContext context) {
377391
HandlerMapping mapping = context.getBean("resourceHandlerMapping", HandlerMapping.class);
378392
if (mapping instanceof SimpleUrlHandlerMapping) {
@@ -545,4 +559,56 @@ private static class MyRequestMappingHandlerMapping extends RequestMappingHandle
545559

546560
}
547561

562+
@Configuration(proxyBeanMethods = false)
563+
static class PrinterConfiguration {
564+
565+
@Bean
566+
public Printer<Example> examplePrinter() {
567+
return new ExamplePrinter();
568+
}
569+
570+
}
571+
572+
@Configuration(proxyBeanMethods = false)
573+
static class ParserConfiguration {
574+
575+
@Bean
576+
public Parser<Example> exampleParser() {
577+
return new ExampleParser();
578+
}
579+
580+
}
581+
582+
static final class Example {
583+
584+
private final String name;
585+
586+
private Example(String name, Date date) {
587+
this.name = name;
588+
}
589+
590+
public String getName() {
591+
return this.name;
592+
}
593+
594+
}
595+
596+
private static class ExamplePrinter implements Printer<Example> {
597+
598+
@Override
599+
public String print(Example example, Locale locale) {
600+
return example.getName();
601+
}
602+
603+
}
604+
605+
private static class ExampleParser implements Parser<Example> {
606+
607+
@Override
608+
public Example parse(String source, Locale locale) {
609+
return new Example(source, new Date());
610+
}
611+
612+
}
613+
548614
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
import org.springframework.core.io.ClassPathResource;
5757
import org.springframework.core.io.Resource;
5858
import org.springframework.core.task.AsyncTaskExecutor;
59+
import org.springframework.format.Parser;
60+
import org.springframework.format.Printer;
5961
import org.springframework.format.support.FormattingConversionService;
6062
import org.springframework.http.CacheControl;
6163
import org.springframework.http.HttpHeaders;
@@ -773,6 +775,16 @@ void whenUserDefinesARequestContextFilterRegistrationTheAutoConfiguredFilterBack
773775
});
774776
}
775777

778+
@Test
779+
void customPrinterAndParserShouldBeRegisteredAsConverters() {
780+
this.contextRunner.withUserConfiguration(ParserConfiguration.class, PrinterConfiguration.class)
781+
.run((context) -> {
782+
ConversionService service = context.getBean(ConversionService.class);
783+
assertThat(service.convert(new Example("spring", new Date()), String.class)).isEqualTo("spring");
784+
assertThat(service.convert("boot", Example.class)).extracting(Example::getName).isEqualTo("boot");
785+
});
786+
}
787+
776788
private void assertCacheControl(AssertableWebApplicationContext context) {
777789
Map<String, Object> handlerMap = getHandlerMap(context.getBean("resourceHandlerMapping", HandlerMapping.class));
778790
assertThat(handlerMap).hasSize(2);
@@ -1093,4 +1105,56 @@ public FilterRegistrationBean<RequestContextFilter> customRequestContextFilterRe
10931105

10941106
}
10951107

1108+
@Configuration(proxyBeanMethods = false)
1109+
static class PrinterConfiguration {
1110+
1111+
@Bean
1112+
public Printer<Example> examplePrinter() {
1113+
return new ExamplePrinter();
1114+
}
1115+
1116+
}
1117+
1118+
@Configuration(proxyBeanMethods = false)
1119+
static class ParserConfiguration {
1120+
1121+
@Bean
1122+
public Parser<Example> exampleParser() {
1123+
return new ExampleParser();
1124+
}
1125+
1126+
}
1127+
1128+
static final class Example {
1129+
1130+
private final String name;
1131+
1132+
private Example(String name, Date date) {
1133+
this.name = name;
1134+
}
1135+
1136+
public String getName() {
1137+
return this.name;
1138+
}
1139+
1140+
}
1141+
1142+
private static class ExamplePrinter implements Printer<Example> {
1143+
1144+
@Override
1145+
public String print(Example example, Locale locale) {
1146+
return example.getName();
1147+
}
1148+
1149+
}
1150+
1151+
private static class ExampleParser implements Parser<Example> {
1152+
1153+
@Override
1154+
public Example parse(String source, Locale locale) {
1155+
return new Example(source, new Date());
1156+
}
1157+
1158+
}
1159+
10961160
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,11 +16,20 @@
1616

1717
package org.springframework.boot.convert;
1818

19+
import java.util.LinkedHashSet;
20+
import java.util.Set;
21+
22+
import org.springframework.beans.factory.ListableBeanFactory;
1923
import org.springframework.core.convert.ConversionService;
24+
import org.springframework.core.convert.converter.Converter;
2025
import org.springframework.core.convert.converter.ConverterRegistry;
26+
import org.springframework.core.convert.converter.GenericConverter;
2127
import org.springframework.core.convert.support.ConfigurableConversionService;
2228
import org.springframework.core.convert.support.DefaultConversionService;
29+
import org.springframework.format.Formatter;
2330
import org.springframework.format.FormatterRegistry;
31+
import org.springframework.format.Parser;
32+
import org.springframework.format.Printer;
2433
import org.springframework.format.support.DefaultFormattingConversionService;
2534
import org.springframework.format.support.FormattingConversionService;
2635
import org.springframework.util.StringValueResolver;
@@ -134,4 +143,36 @@ public static void addApplicationFormatters(FormatterRegistry registry) {
134143
registry.addFormatter(new IsoOffsetFormatter());
135144
}
136145

146+
/**
147+
* Add {@link GenericConverter}, {@link Converter}, {@link Printer}, {@link Parser}
148+
* and {@link Formatter} beans from the specified context.
149+
* @param registry the service to register beans with
150+
* @param beanFactory the bean factory to get the beans from
151+
* @since 2.2.0
152+
*/
153+
public static void addBeans(FormatterRegistry registry, ListableBeanFactory beanFactory) {
154+
Set<Object> beans = new LinkedHashSet<>();
155+
beans.addAll(beanFactory.getBeansOfType(GenericConverter.class).values());
156+
beans.addAll(beanFactory.getBeansOfType(Converter.class).values());
157+
beans.addAll(beanFactory.getBeansOfType(Printer.class).values());
158+
beans.addAll(beanFactory.getBeansOfType(Parser.class).values());
159+
for (Object bean : beans) {
160+
if (bean instanceof GenericConverter) {
161+
registry.addConverter((GenericConverter) bean);
162+
}
163+
else if (bean instanceof Converter) {
164+
registry.addConverter((Converter<?, ?>) bean);
165+
}
166+
else if (bean instanceof Formatter) {
167+
registry.addFormatter((Formatter<?>) bean);
168+
}
169+
else if (bean instanceof Printer) {
170+
registry.addPrinter((Printer<?>) bean);
171+
}
172+
else if (bean instanceof Parser) {
173+
registry.addParser((Parser<?>) bean);
174+
}
175+
}
176+
}
177+
137178
}

0 commit comments

Comments
 (0)