Add DataSize converters to DefaultConversionService

Spring Boot already provides equivalent converters, and DataSize itself
already exposes parsing support via DataSize.parse(...).

This commit makes that conversion available through Spring Framework's
default conversion service.

- new StringToDataSizeConverter
- new NumberToDataSizeConverter
- both converters are registered with the DefaultConversionService
- new tests for string, number, empty, and invalid inputs

This intentionally does not move Spring Boot's @⁠DataSizeUnit support
into Spring Framework.

See gh-28910
Closes gh-36830

Signed-off-by: YeongJae Min <whereismysejong@naver.com>
This commit is contained in:
YeongJae Min
2026-06-17 14:15:04 +02:00
committed by Sam Brannen
parent 2bc0ee7ec1
commit 175f551d91
4 changed files with 114 additions and 0 deletions
@@ -142,6 +142,9 @@ public class DefaultConversionService extends GenericConversionService {
converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToDataSizeConverter());
converterRegistry.addConverter(new NumberToDataSizeConverter());
converterRegistry.addConverter(new StringToCharacterConverter());
converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());
@@ -0,0 +1,37 @@
/*
* Copyright 2002-present 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
*
* https://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.core.convert.support;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.unit.DataSize;
/**
* Converts from a {@link Number} to a {@link DataSize}.
*
* @author YeongJae Min
* @since 7.1
* @see DataSize#parse(CharSequence)
* @see StringToDataSizeConverter
*/
final class NumberToDataSizeConverter implements Converter<Number, DataSize> {
@Override
public DataSize convert(Number source) {
return DataSize.parse(source.toString());
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2002-present 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
*
* https://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.core.convert.support;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.unit.DataSize;
/**
* Converts from a {@link String} to a {@link DataSize}.
*
* @author YeongJae Min
* @since 7.1
* @see DataSize#parse(CharSequence)
* @see NumberToDataSizeConverter
*/
final class StringToDataSizeConverter implements Converter<String, @Nullable DataSize> {
@Override
public @Nullable DataSize convert(String source) {
if (source.isEmpty()) {
return null;
}
return DataSize.parse(source);
}
}
@@ -58,6 +58,7 @@ import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.util.ClassUtils;
import org.springframework.util.unit.DataSize;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -231,6 +232,37 @@ class DefaultConversionServiceTests {
assertThat(conversionService.convert("", Number.class)).isNull();
}
@Test
void stringToDataSize() {
assertThat(conversionService.convert("10B", DataSize.class)).isEqualTo(DataSize.ofBytes(10));
assertThat(conversionService.convert("+10KB", DataSize.class)).isEqualTo(DataSize.ofKilobytes(10));
assertThat(conversionService.convert("-10MB", DataSize.class)).isEqualTo(DataSize.ofMegabytes(-10));
assertThat(conversionService.convert("10", DataSize.class)).isEqualTo(DataSize.ofBytes(10));
}
@Test
void stringToDataSizeEmptyString() {
assertThat(conversionService.convert("", DataSize.class)).isNull();
}
@Test
void stringToDataSizeInvalidString() {
assertThatExceptionOfType(ConversionFailedException.class).isThrownBy(() ->
conversionService.convert("10WB", DataSize.class));
}
@Test
void numberToDataSize() {
assertThat(conversionService.convert(10, DataSize.class)).isEqualTo(DataSize.ofBytes(10));
assertThat(conversionService.convert(-10L, DataSize.class)).isEqualTo(DataSize.ofBytes(-10));
}
@Test
void numberToDataSizeWithDecimalNumber() {
assertThatExceptionOfType(ConversionFailedException.class).isThrownBy(() ->
conversionService.convert(10.5, DataSize.class));
}
@Test
void stringToEnum() {
assertThat(conversionService.convert("BAR", Foo.class)).isEqualTo(Foo.BAR);