Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use @ConfigurationProperties with Records?

Java 16 introduced Records, which help to reduce boilerplate code when writing classes that carry immutable data. When I try to use a Record as @ConfigurationProperties bean as follows I get the following error message:

@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.

How can I use Records as @ConfigurationProperties?

like image 611
Moritz Avatar asked Mar 18 '21 18:03

Moritz


People also ask

What is the use of @configuration in spring boot?

Spring @Configuration annotation is part of the spring core framework. Spring Configuration annotation indicates that the class has @Bean definition methods. So Spring container can process the class and generate Spring Beans to be used in the application.

How do you call a properties file in spring boot?

Another method to access values defined in Spring Boot is by autowiring the Environment object and calling the getProperty() method to access the value of a property file.


2 Answers

Answering my own question.

The above error raises from Spring Boot not being able to construct the bean because of the lack of a no-argument constructor. Records implicitly declare a constructor with a parameter for every member.

Spring Boot allows us to use the @ConstructorBinding annotation to enable property binding by constructor instead of setter methods (as stated in the docs and the answer to this question). This also works for records, so this works:

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

Update: As of Spring Boot 2.6, using records works out of the box and @ConstructorBinding is not required anymore when the record has a single constructor. See the release notes.

like image 166
Moritz Avatar answered Nov 01 '22 10:11

Moritz


If you need to declare default values programatically:

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

java.util.Optional properties:

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

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

@Validated and java.util.Optional in combination:

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

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

Based on this Spring Boot issue.

like image 20
Lovro Pandžić Avatar answered Nov 01 '22 08:11

Lovro Pandžić