Как использовать @ConfigurationProperties с записями?

В Java 16 появились записи , которые помогают сократить шаблонный код при написании классов, которые несут неизменяемые данные. Когда я пытаюсь использовать объект Record как bean, как показано ниже, я получаю следующее сообщение об ошибке:

      @ConfigurationProperties("demo")
public record MyConfigurationProperties(
        String myProperty
) {
}
      ***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.example.demo.MyConfigurationProperties required a bean of type 'java.lang.String' that could not be found.

Как я могу использовать записи как @ConfigurationProperties?

7 ответов

Отвечая на свой вопрос.

Вышеупомянутая ошибка возникает из-за того, что Spring Boot не может создать bean-компонент из-за отсутствия конструктора без аргументов. Записи неявно объявляют конструктор с параметром для каждого члена.

Spring Boot позволяет нам использовать @ConstructorBindingаннотация для включения привязки свойств конструктором вместо методов установки (как указано в документации и ответе на этот вопрос ). Это также работает для записей, поэтому это работает:

      @ConfigurationProperties("demo")
@ConstructorBinding
public record MyConfigurationProperties(
        String myProperty
) {
}

У меня была такая же проблема с весенней загрузкой 3.0.0 и@ConstructorBindingне рекомендуется.

Мне нужно было добавить:

      @SpringBootApplication
@ConfigurationPropertiesScan
public class Application

Если вам нужно программно объявить значения по умолчанию:

      @ConfigurationProperties("demo")
public record MyConfigurationProperties(String myProperty) { 
    
    @ConstructorBinding
    public MyConfigurationProperties(String myProperty) {
        this.myProperty = Optional.ofNullable(myProperty).orElse("default");
    }
}

характеристики:

      @ConfigurationProperties("demo")
public record MyConfigurationProperties(Optional<String> myProperty) {

    @ConstructorBinding
    public MyConfigurationProperties(String myProperty) {
        this(Optional.ofNullable(myProperty));
    }
}

@Validated и java.util.Optional в сочетании:

      @Validated
@ConfigurationProperties("demo")
public record MyConfigurationProperties(@NotBlank String myRequiredProperty,
                                        Optional<String> myProperty) {

    @ConstructorBinding
    public MyConfigurationProperties(String myRequiredProperty, 
                                     String myProperty) {
        this(myRequiredProperty, Optional.ofNullable(myProperty));
    }
}

На основе этой проблемы с загрузкой Spring .

ConstructorBindingи компактная форма конструктора в Spring Boot 3.1.0

Начиная с версии «spring-boot» «3.1.0»:

  • Аннотацияorg.springframework.boot.context.properties.ConstructorBindingустарел и не может применяться к объявлению типа (класс, интерфейс, перечисление или запись), но может применяться к объявлению конструктора
  • Аннотацияorg.springframework.boot.context.properties.bind.ConstructorBinding;не может применяться к объявлению типа (класс, интерфейс, перечисление или запись), но может применяться к объявлению конструктора

Таким образом, мы можем объявитьrecordи применитьorg.springframework.boot.context.properties.bind.ConstructorBinding к компактной форме конструктора , которая по-прежнему выглядит лаконично:

      @ConfigurationProperties
public record ApplicationProperties(/* Your properties here. E.g.:
                                    String prop1, 
                                    Integer prop2, 
                                    NestedConfig nestedProps
                                    */) {

    @ConstructorBinding
    public ApplicationProperties {
    }

}

Примечание . Не забудьте включить поддержку@ConfigurationPropertiesаннотированные bean-компоненты в вашем приложении. Например:

      @EnableConfigurationProperties(ApplicationProperties.class)
@SpringBootApplication
public class YourApplication {

    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }

}

С весенней загрузкой 3.0.4 я смог использовать записи напрямую без каких-либо аннотаций @ConstructorBinding.

      @ConfigurationProperties(prefix = "app")
@Validated
public record ApplicationProperties(String version, FtpProperties ftp) {
    public record FtpProperties(
                            @NotEmpty String host,
                            @Positive int port,
                            @NotEmpty String username) {}
}

При сопоставлении конфигурации YAML с использованием классового подхода не возникнет проблем, если вы используете аннотацию @Configuration.

Однако при переключении на использование записи для сопоставления Spring сообщит вам, что это окончательный тип и его нельзя проксировать и управлять им в контейнере.

Я обнаружил, что вы можете явно объявить в основном классе Spring, используя @EnableConfigurationProperties(XXProperties.class) или @ConfigurationPropertiesScan, что вам нужно добавить класс с аннотацией @ConfigurationProperties в контейнер, независимо от того, является ли это классом или записью. .

В версии 2.x Spring Boot, если вы хотите использовать тип записи для сопоставления файлов YAML, вам необходимо добавить к классу аннотацию @ConstructorBinding. Однако в версии Spring Boot 3.0 в этом больше нет необходимости, и он был помечен как устаревший.

https://youtrack.jetbrains.com/issue/IDEA-295483/Spring-Boot-ConfigurationProperties-annotated-java-record-is-reported-as-not-used

      @SpringBootApplication
//@EnableConfigurationProperties(YmlConfigDbProperties.class)
@ConfigurationPropertiesScan
public class AppMain {

    public static void main(String[] args) {
        SpringApplication.run(AppMain.class, args);
    }

}
      @ConfigurationProperties(prefix = "config.db")
//@Configuration
public record YmlConfigDbProperties(){}

В Spring-Boot 2.7.5 вам нужно будет только

  1. Аннотируйте запись с помощью@ConfigurationProperties
  2. Аннотируйте основной класс с помощью@ConfigurationPropertiesScan({RecordConfig.class}). Эта часть важна, поскольку она сообщает Spring особенности класса Config и помогает ему зарегистрироваться как bean-компонент.enter code here.
Другие вопросы по тегам