@ConfigurationProperties

Type-Safe Settings

@Value("${shopease.payment.timeout}") is fine for one value. For a group of settings, bind them to a record with @ConfigurationProperties: typed, validated, and easy to inject.

package com.shopease.config;

import jakarta.validation.constraints.*;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

@Validated
@ConfigurationProperties(prefix = "shopease.payment")
public record PaymentProperties(
        @NotBlank String baseUrl,          // shopease.payment.base-url
        @NotBlank String keyId,            // shopease.payment.key-id
        @NotBlank String keySecret,        // shopease.payment.key-secret
        Duration timeout,                  // "5s", "500ms", "1m" are converted for you
        @Min(0) @Max(5) int maxRetries) {}

@SpringBootApplication
@ConfigurationPropertiesScan            // finds all @ConfigurationProperties classes
public class ShopEaseApplication { ... }

Using the Properties

@Service
public class PaymentService {
    private final PaymentProperties props;

    public PaymentService(PaymentProperties props) { this.props = props; }

    public void log() {
        System.out.println("Calling " + props.baseUrl() + " with timeout " + props.timeout());
    }
}

Example

If a required value is missing, the app refuses to start with a clear message (much better than a NullPointerException at the first payment):

java -jar target/shopease.jar --spring.profiles.active=prod

Example output

***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target com.shopease.config.PaymentProperties failed:

    Property: shopease.payment.keySecret
    Value: ""
    Reason: must not be blank

Action:

Update your application's configuration

Tip: Add spring-boot-configuration-processor (optional dependency) and your IDE will auto-complete shopease.payment.* in YAML files.