自定义ConstraintValidator引发StackOverflowException问题求助
解决自定义ConstraintValidator引发的StackOverflowException问题
你遇到的无限循环栈溢出问题,核心原因是校验逻辑和Hibernate的实体生命周期校验形成了闭环调用:当Spring Data REST触发实体保存时,Hibernate会自动执行Bean Validation(也就是你的@UniqueCompteEmail校验);而在校验器中调用compteRepository.findByEmail()查询时,Hibernate加载返回的Compte实体又会再次触发该实体的所有校验,如此往复直到栈被撑爆。
下面是具体的解决方案,分步骤帮你打破这个循环:
1. 改用EntityManager查询并禁用查询时的校验
把校验器里的CompteRepository注入替换为EntityManager,并在查询时添加提示禁用Bean Validation,避免查询过程中再次触发实体校验:
public class UniqueCompteEmailValidator implements ConstraintValidator<UniqueCompteEmail, Compte> { @PersistenceContext private EntityManager entityManager; @Override public void initialize(UniqueCompteEmail constraintAnnotation) {} @Override public boolean isValid(Compte value, ConstraintValidatorContext context) { if (value == null || value.getEmail() == null) { return false; } // 直接用EntityManager执行查询,同时禁用校验避免循环 TypedQuery<Long> query = entityManager.createQuery( "SELECT COUNT(c) FROM Compte c WHERE c.email = :email", Long.class); query.setParameter("email", value.getEmail()); // 关键:设置查询提示,让Hibernate查询时不触发Bean Validation query.setHint("javax.persistence.validation.mode", "NONE"); Long count = query.getSingleResult(); return count == 0; } }
2. 优化校验逻辑(区分新建/更新场景)
额外补充一个优化点:如果是更新实体(id不为null),只有当邮箱发生变更时才需要校验唯一性,避免不必要的查询:
@Override public boolean isValid(Compte value, ConstraintValidatorContext context) { if (value == null || value.getEmail() == null) { return false; } // 更新场景:检查邮箱是否和原有记录一致,一致则无需校验 if (value.getId() != null) { Compte existing = entityManager.find(Compte.class, value.getId()); if (existing != null && value.getEmail().equals(existing.getEmail())) { return true; } } // 新建或邮箱变更场景:校验唯一性 TypedQuery<Long> query = entityManager.createQuery( "SELECT COUNT(c) FROM Compte c WHERE c.email = :email", Long.class); query.setParameter("email", value.getEmail()); query.setHint("javax.persistence.validation.mode", "NONE"); Long count = query.getSingleResult(); return count == 0; }
3. 移除不必要的Validator配置
在Spring Boot中,默认已经支持让Hibernate Validator使用Spring管理的实例,你的ValidatorAddingCustomizer可能属于冗余配置,甚至可能引发双重校验触发的问题。可以尝试移除这个类,看看依赖注入是否依然正常工作——如果没问题,就彻底删掉它,减少配置复杂度。
内容的提问来源于stack exchange,提问作者Sidi Mohamed MOULEY SLIMANE
相关产品推荐
相关产品推荐

