You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring中自定义@OptimizedName注解继承@Size时@AliasFor失效排查

自定义验证注解中@AliasFor的正确使用方式

我在Spring框架中创建了用于验证用户名的@OptimizedName注解,期望它继承@Size注解的功能并允许覆盖min和max属性,但实现后并未生效。我是否正确使用了@AliasFor?

最初的错误实现

package com.foodey.server.validation.annotation;

import jakarta.validation.Constraint;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Documented
@NotBlank
@Size
public @interface OptimizedName {

  // @AliasFor(annotation = Size.class, attribute = "message")
  // String message() default "Name must be between {min} and {max} characters";

  // Class<?>[] groups() default {};

  // Class<? extends Payload>[] payload() default {};

  @AliasFor(annotation = Size.class, attribute = "min")
  int minLength() default 3;

  @AliasFor(annotation = Size.class, attribute = "max")
  int maxLength() default 50;
}

注解使用方式

package com.foodey.server.auth.dto;

import com.foodey.server.validation.annotation.OptimizedName;
import com.foodey.server.validation.annotation.Password;
import com.foodey.server.validation.annotation.PhoneNumber;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class RegistrationRequest {

  @PhoneNumber private String phoneNumber;

  @Password private String password;

  @OptimizedName(minLength = 5, maxLength = 50)
  private String name;
}

上述代码运行后验证逻辑未生效,但硬编码@Size参数的版本可以正常工作:

package com.foodey.server.validation.annotation;

import jakarta.validation.Constraint;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Documented
@NotBlank
@Size(min = 3, max = 50)
public @interface OptimizedName {

  // @AliasFor(annotation = Size.class, attribute = "message")
  // String message() default "Name must be between {min} and {max} characters";

  // Class<?>[] groups() default {};

  // Class<? extends Payload>[] payload() default {};

  // @AliasFor(annotation = Size.class, attribute = "min")
  // int minLength() default 3;

  // @AliasFor(annotation = Size.class, attribute = "max")
  // int maxLength() default 50;
}

问题原因与正确实现

核心问题

Jakarta Validation(原JSR-380)框架要求自定义约束注解必须包含message、groups、payload三个标准属性,否则无法识别该注解的验证逻辑。同时,Spring的@AliasFor仅负责属性别名映射,无法替代Validation框架对标准属性的要求。

正确的注解实现

package com.foodey.server.validation.annotation;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Documented
@NotBlank
@Size
public @interface OptimizedName {

    // 映射@Size的message属性,自定义默认提示
    @AliasFor(annotation = Size.class, attribute = "message")
    String message() default "用户名长度必须在{min}到{max}字符之间";

    // 映射@Size的min属性,可通过注解参数覆盖
    @AliasFor(annotation = Size.class, attribute = "min")
    int minLength() default 3;

    // 映射@Size的max属性,可通过注解参数覆盖
    @AliasFor(annotation = Size.class, attribute = "max")
    int maxLength() default 50;

    // 映射@NotBlank的groups属性,Validation标准属性
    @AliasFor(annotation = NotBlank.class, attribute = "groups")
    Class<?>[] groups() default {};

    // 映射@NotBlank的payload属性,Validation标准属性
    @AliasFor(annotation = NotBlank.class, attribute = "payload")
    Class<? extends Payload>[] payload() default {};
}

关键说明

  1. 必须定义Validation标准属性:message、groups、payload是Jakarta Validation要求的约束注解必备属性,通过@AliasFor映射到元注解(@Size、@NotBlank)的对应属性,保证Validation框架能正确读取并执行验证。
  2. 属性别名映射正确:minLength和maxLength通过@AliasFor明确指向@Size的min和max属性,使用注解时传入的参数会被正确传递给@Size。
  3. 保持@Constraint配置:@Constraint(validatedBy = {})留空即可,因为我们是组合已有验证注解,无需自定义验证器。

验证使用方式不变

@OptimizedName(minLength = 5, maxLength = 50)
private String name;

内容的提问来源于stack exchange,提问作者Tùng Trần

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 01:16:02