Add FormatterRegistry addPrinter/addParser methods

Update `FormatterRegistry` with `addPrinter` and `addParser` methods
that can be used to register Printer or Parser implementations in a
similar way to the existing `addFormatter` method.

Closes gh-23110
This commit is contained in:
Phillip Webb 2019-06-11 14:45:04 -07:00
parent a89bfffd8c
commit 5e505ce3a9
3 changed files with 61 additions and 9 deletions

View File

@ -29,6 +29,24 @@ import org.springframework.core.convert.converter.ConverterRegistry;
*/
public interface FormatterRegistry extends ConverterRegistry {
/**
* Adds a Printer to print fields of a specific type.
* The field type is implied by the parameterized Printer instance.
* @param printer the printer to add
* @since 5.2
* @see #addFormatter(Formatter)
*/
void addPrinter(Printer<?> printer);
/**
* Adds a Parser to parse fields of a specific type.
* The field type is implied by the parameterized Parser instance.
* @param parser the parser to add
* @since 5.2
* @see #addFormatter(Formatter)
*/
void addParser(Parser<?> parser);
/**
* Adds a Formatter to format fields of a specific type.
* The field type is implied by the parameterized Formatter instance.

View File

@ -37,6 +37,8 @@ import org.springframework.format.FormatterRegistry;
import org.springframework.format.Parser;
import org.springframework.format.Printer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;
@ -65,6 +67,18 @@ public class FormattingConversionService extends GenericConversionService
}
@Override
public void addPrinter(Printer<?> printer) {
Class<?> fieldType = getFieldType(printer, Printer.class);
addConverter(new PrinterConverter(fieldType, printer, this));
}
@Override
public void addParser(Parser<?> parser) {
Class<?> fieldType = getFieldType(parser, Parser.class);
addConverter(new ParserConverter(fieldType, parser, this));
}
@Override
public void addFormatter(Formatter<?> formatter) {
addFormatterForFieldType(getFieldType(formatter), formatter);
@ -97,15 +111,18 @@ public class FormattingConversionService extends GenericConversionService
static Class<?> getFieldType(Formatter<?> formatter) {
Class<?> fieldType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class);
if (fieldType == null && formatter instanceof DecoratingProxy) {
return getFieldType(formatter, Formatter.class);
}
private static <T> Class<?> getFieldType(T instance, Class<T> genericInterface) {
Class<?> fieldType = GenericTypeResolver.resolveTypeArgument(instance.getClass(), genericInterface);
if (fieldType == null && instance instanceof DecoratingProxy) {
fieldType = GenericTypeResolver.resolveTypeArgument(
((DecoratingProxy) formatter).getDecoratedClass(), Formatter.class);
}
if (fieldType == null) {
throw new IllegalArgumentException("Unable to extract the parameterized field type from Formatter [" +
formatter.getClass().getName() + "]; does the class parameterize the <T> generic type?");
((DecoratingProxy) instance).getDecoratedClass(), genericInterface);
}
Assert.notNull(fieldType, () -> "Unable to extract the parameterized field type from " +
ClassUtils.getShortName(genericInterface) + " [" + instance.getClass().getName() +
"]; does the class parameterize the <T> generic type?");
return fieldType;
}

View File

@ -346,8 +346,25 @@ public class FormattingConversionServiceTests {
@Test
public void introspectedFormatter() throws ParseException {
formattingService.addFormatter(new NumberStyleFormatter());
assertThat(formattingService.convert(null, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class))).isNull();
formattingService.addFormatter(new NumberStyleFormatter("#,#00.0#"));
assertThat(formattingService.convert(123, String.class)).isEqualTo("123.0");
assertThat(formattingService.convert("123.0", Integer.class)).isEqualTo(123);
}
@Test
public void introspectedPrinter() throws ParseException {
formattingService.addPrinter(new NumberStyleFormatter("#,#00.0#"));
assertThat(formattingService.convert(123, String.class)).isEqualTo("123.0");
assertThatExceptionOfType(ConversionFailedException.class).isThrownBy(() ->
assertThat(formattingService.convert("123.0", Integer.class)).isNull())
.withCauseInstanceOf(NumberFormatException.class);
}
@Test
public void introspectedParser() throws ParseException {
formattingService.addParser(new NumberStyleFormatter("#,#00.0#"));
assertThat(formattingService.convert("123.0", Integer.class)).isEqualTo(123);
assertThat(formattingService.convert(123, String.class)).isEqualTo("123");
}
@Test