Из-за чего для @Value используются PropertyEditors, а не Converter?

Ссылка скопирована
1 ответ

По вводным: в документации сказано, что для преобразования значение из @Value в необходимый тип поля используется ConversionService. Для преобразования значения из @Value в кастомный тип необходимо добавить свой Converter в ConversionService (например, в DefaultConvetsionService).

По вводным: на деле столкнулся, что при преобразование String значения из @Value в long значение поля, выбрасывается исключение, трассировка для которого выглядит так (неполная)

java.lang.NumberFormatException: For input string: "${user-file-min-size}"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) ~[na:na]
at java.base/java.lang.Long.parseLong(Long.java:697) ~[na:na]
at java.base/java.lang.Long.valueOf(Long.java:1163) ~[na:na]
at org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:204) ~[spring-core-6.2.11.jar:6.2.11]
at org.springframework.beans.propertyeditors.CustomNumberEditor.setAsText(CustomNumberEditor.java:115) ~[spring-beans-6.2.11.jar:6.2.11]
at org.springframework.beans.TypeConverterDelegate.doConvertTextValue(TypeConverterDelegate.java:439) ~[spring-beans-6.2.11.jar:6.2.11]
at org.springframework.beans.TypeConverterDelegate.doConvertValue(TypeConverterDelegate.java:412) ~[spring-beans-6.2.11.jar:6.2.11]
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:161) ~[spring-beans-6.2.11.jar:6.2.11]
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:80) ~[spring-beans-6.2.11.jar:6.2.11]
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:71) ~[spring-beans-6.2.11.jar:6.2.11]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1672) ~[spring-beans-6.2.11.jar:6.2.11]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1643) ~[spring-beans-6.2.11.jar:6.2.11]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:785) ~[spring-beans-6.2.11.jar:6.2.11]

at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject

По вводным: отсюда видно, что AutowiredAnnotationBeanPostProcessor использует DefaultListableBeanFactory, который вызывает TypeConverterDelegate, который в свою очередь использует CustomNumberEditor. Никакого ConversionService нет, как об этом пишут в документации.

По вводным: использую Spring Boot 3.5.6

Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Редакция Security Ответ

В Spring действительно может выглядеть странно: документация говорит про ConversionService, но в трассировке для @Value вы видите PropertyEditor. Это не обязательно противоречие. В Spring исторически есть несколько слоёв преобразования: старые JavaBeans PropertyEditor и более новый ConversionService. В зависимости от места биндинга, контекста и зарегистрированных компонентов может использоваться один или другой путь.

Для простых типов вроде long проблем быть не должно:

@Value("${app.timeout}")
private long timeout;

@Value("${app.timeout}") private long timeout;

Если падает преобразование String в long, сначала проверьте само значение свойства: пробелы, пустая строка, суффиксы, запятые, неверный placeholder. Например, 10_000, 10ms или пустое значение не обязаны конвертироваться в long.

Для кастомного типа в Spring Boot лучше зарегистрировать converter как bean:

@Component
public class MyTypeConverter implements Converter<String, MyType> {
    @Override
    public MyType convert(String source) {
        return MyType.parse(source);
    }
}

@Component public class MyTypeConverter implements Converter<String, MyType> { @Override public MyType convert(String source) { return MyType.parse(source); } }

Если нужно именно для конфигурационных свойств, часто лучше уйти от одиночных @Value к @ConfigurationProperties. Там биндинг понятнее и лучше диагностируется:

@ConfigurationProperties(prefix = "app")
public record AppProperties(long timeout) {}

@ConfigurationProperties(prefix = "app") public record AppProperties(long timeout) {}

Итог: PropertyEditor в стеке не всегда ошибка. Проверьте реальное значение свойства и способ регистрации converter. Для сложной конфигурации используйте @ConfigurationProperties, а не россыпь @Value.

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно