티스토리 뷰

Spring

[Spring] Validation 애노테이션 사용 시에 발생하는 ConstraintDeclarationException 에러

망나니개발자 2026. 1. 20. 10:00
반응형

 

 

1. Validation 애노테이션 사용 시에 발생하는 ConstraintDeclarationException 에러


[ Validation 애노테이션 사용 시에 발생하는 ConstraintDeclarationException 에러 ]

에를 들어 다음과 같은 컨트롤러가 존재한다고 하자. 파라미터로 받는 name은 최소 길이가 10이여야 한다는 유효성 검사를 도와주는 @Length 애노테이션이 붙어 있다. 그리고 이를 추싱화한 TestControllerInterface에는 관련 애노테이션 정보가 존재하지 않는 상황이다. 이러한 상황에서 컨트롤러를 호출하게 되면 어떤 결과가 나올까?

import org.hibernate.validator.constraints.Length;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
class TestController implements TestControllerInterface {

    @GetMapping("/test")
    public Integer test(@RequestParam @Length(min = 10) String name) {
        return name.length();
    }
}

interface TestControllerInterface {
    Integer test(String name);
}

 

 

스프링 애플리케이션은 다음과 같은 에러를 내며 요청을 처리하지 못한다. 에러 메시지가 워낙 친절하기 때문에 해당 내용만 읽어도 어떻게 문제를 해결할 수 있을지 감을 잡을 수 있다.

2026-01-18T12:18:59.423+09:00 ERROR 47216 --- [mangkyu-spring] [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [
Request processing failed: jakarta.validation.ConstraintDeclarationException: 
HV000151: A method overriding another method must not redefine the parameter constraint configuration, 
but method TestController#test(String) redefines the configuration of TestControllerInterface#test(String).] with root cause

jakarta.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration, but method TestController#test(String) redefines the configuration of TestControllerInterface#test(String).
	at org.hibernate.validator.internal.metadata.aggregated.rule.OverridingMethodMustNotAlterParameterConstraints.apply(OverridingMethodMustNotAlterParameterConstraints.java:24) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData$Builder.assertCorrectnessOfConfiguration(ExecutableMetaData.java:462) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData$Builder.build(ExecutableMetaData.java:380) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataBuilder$BuilderDelegate.build(BeanMetaDataBuilder.java:260) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataBuilder.build(BeanMetaDataBuilder.java:133) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl.createBeanMetaData(BeanMetaDataManagerImpl.java:206) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl.getBeanMetaData(BeanMetaDataManagerImpl.java:165) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:267) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:235) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at org.springframework.validation.beanvalidation.MethodValidationAdapter.invokeValidatorForArguments(MethodValidationAdapter.java:261) ~[spring-context-6.2.6.jar:6.2.6]

 

 

에러 메시지는 오버라이딩하는 메서드에서 제약 사항을 재정의하면 안된다고(must not redefine the parameter constraint configuration) 설명하고 있다.

현재 부모이자 인터페이스인 TestControllerInterface#test 에는 Bean Validation(@NotNull, @Size, @Valid 같은 것) 이 존재하지 않는데, 이를 구현하는 구체 클래스 TestController#test 에서는 이것이 재정의되어 에러가 발생한 것이다.

그렇다면 유효성 검사의 구현체를 제공하는 하이버네이트(Hibernate)는 왜 이러한 제약을 걸어둔 것일까?

 

 

 

[ Jakarta Validation Specification – Method constraints in inheritance hierarchies ]

해당 내용은 하이버네이트만의 단독적인 특성은 아니고, Jakarta Validation(Bean Validation) 스펙에 맞게 구현했을 뿐이다. Jakrata Bean Validation 5.6.5의 Method constraints in inheritance hierarchies을 보면, 다음과 같은 내용이 존재한다. 해당 내용은 리스코프 치환 원칙에 따라, 하위 타입에서 파라미터 제약을 선언(추가/강화)하면 안 된다는 규칙과, 위반 시 ConstraintDeclarationException 에러를 던져야 한다는 내용을 담고 있다.

 

 

리스코프 치환 원칙(Liskov substitution principle)은 객체지향 프로그래밍(OOP)의 기본 원칙 중 하나로, 하위 타입은 상위 타입을 대체할 수 있어야 한다는 것이다. 즉, 부모 타입이 쓰이는 자리에 자식 타입을 넣어도 프로그램이 깨지지 않아야 한다. 하지만 만약 상위 타입에서 정의된 내용을 초과해서 하위 타입이 제공한다면, 프로그램이 실패할 수 있다. 따라서 Jakarta Validation(Bean Validation) 스펙은 리스코프 치환 원칙을 준수하도록 해당 제약을 정의해두었고, 하이버네이트 역시 이를 정확히 구현하여 Hibernate Validator Reference Guide 9.1의 3.1.4 Method constraints in inheritance hierarchies에서 이를 설명하고 있다.

 

 

결국 위의 문제는 부모 인터페이스에 정의되어 있지 않은 제약 사항을 하위 구현체에서 추가하였고, 이로 인해 리스코프 치환 원칙을 위반하게 되어 Jakarta Validation 스펙에 따라 ConstraintDeclarationException 에러가 던져진 것으로 볼 수 있다.

리스코프 치환 원칙은 사실 그렇게 낯선 개념이 아니다. 이전 포스팅에서 살펴보았듯 자바도 리스코프 치환 원칙에 따라 메소드 오버라이딩을 할 때, 더 좁은 범위의 접근제어자로 변경할 수 없도록 제약하고 있다. 즉, 인터페이스에 정의된 메서드가 public이라고 하면, 이를 구현하는 자식 클래스에서도 protected나 private으로 가시성을 좁힐 수 없는 것이다.

 

 

 

위와 같은 에러가 발생했을 떄, 에러 메시지가 워낙 친절하기 때문에 이를 수정하는 것은 그리 큰 문제가 아니다. 하지만 왜 이러한 설계 제약이 생겼고, 그 근거가 무엇인지 파악하는 것은 또 다른 문제이다. 이러한 문제가 생겼을 때, 단순한 해결보다는 깊이있는 생각을 통해 접근하는 자세가 더욱 중요할 것이다.

 

 

 

 

 

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함