--- title: Spring Boot record @ConfigurationProperties — 보조 생성자 추가 시 No default constructor found source_type: error-note status: raw created: 2026-06-12 tags: [spring-boot, configuration-properties, record, constructor-binding] --- # Spring Boot record `@ConfigurationProperties` — 보조 생성자 추가 시 `No default constructor found` ## Parent [[raw/branch-notes/feature-domain-event-outbox-contract]] --- ## 증상 `OutboundHttpSettings` record 에 보조 6-arg 생성자를 추가한 뒤 `ApplicationContextRunner` 로 `@ConfigurationProperties` 바인딩 테스트를 실행하면: ``` org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'app.outbound.http-dev.caskeleton.adapter.outbound.httpclient.OutboundHttpSettings': Failed to instantiate [...OutboundHttpSettings]: No default constructor found Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [...OutboundHttpSettings]: No default constructor found Caused by: java.lang.NoSuchMethodException: ...OutboundHttpSettings.() ``` 기존 6-arg 단일 생성자 record 에서는 동일 테스트가 통과했음. --- ## 원인 Spring Boot 3.x 는 `@ConfigurationProperties` record 에 **생성자가 정확히 하나**일 때만 canonical constructor binding 을 자동 감지한다. 생성자가 **2개 이상**(canonical + 보조)이면 Spring 은 단일 생성자 record 특수 경로를 포기하고 일반 JavaBean 경로로 fallback — JavaBean 경로는 no-arg 생성자를 찾다 실패. 핵심 규칙: **record 에 생성자가 여러 개이면 바인딩 대상 생성자를 명시해야 한다.** --- ## 해결 바인딩에 사용할 canonical compact constructor 에 `@ConstructorBinding` 어노테이션을 추가한다. ```java import org.springframework.boot.context.properties.bind.ConstructorBinding; @ConfigurationProperties(prefix = "app.outbound.http") public record OutboundHttpSettings( Duration connectTimeout, ..., Retry retry, CircuitBreaker circuitBreaker) { @ConstructorBinding // ← 다중 생성자 record 에서 바인딩 대상 명시 public OutboundHttpSettings { // compact constructor body (validation) } /** 보조 생성자 — 기존 6-arg 호출부 무변경 유지 */ public OutboundHttpSettings(Duration connectTimeout, ..., DataSize responseSizeLimit) { this(connectTimeout, ..., responseSizeLimit, null, null); } } ``` **import 주의**: `org.springframework.boot.context.properties.bind.ConstructorBinding` (Spring Boot 3.x). Spring Boot 2.x 의 `org.springframework.boot.context.properties.ConstructorBinding` 은 deprecated. --- ## 재현 조건 - Spring Boot 3.x `@ConfigurationProperties` record - record 에 **canonical constructor 외에 보조 생성자가 1개 이상** 존재 - `ApplicationContextRunner` 또는 `@SpringBootTest` 로 `@EnableConfigurationProperties` 바인딩 단일 생성자 record 에서는 `@ConstructorBinding` 없이도 동작. --- ## 검증 방법 ```bash cd src && ./gradlew :adapter-outbound:test --tests '*OutboundHttpSettingsTest' --console=plain ``` `nested_settings_bind_from_application_context_runner()` + `settings_bind_from_application_context_runner()` 모두 PASS. --- ## Claims To Verify | Claim | Why uncertain | Status | |---|---|---| | Spring Boot 3.4 에서 단일 생성자 record 는 `@ConstructorBinding` 없이 바인딩됨 | 실측 확인(단일 → 보조 추가 시 실패) | `locally-verified` | | `org.springframework.boot.context.properties.bind.ConstructorBinding` 이 3.x SSOT import | Spring Boot 3.4 릴리즈 노트 미확인 — 기존 code 에 해당 어노테이션 미사용 | `needs-confirmation` |