代码之家  ›  专栏  ›  技术社区  ›  user684934

无限验证循环

  •  0
  • user684934  · 技术社区  · 11 年前

    我有一个Roo模型的验证器。

    当它发现一个错误(返回false)时,它会按预期工作。

    然而,当它成功时,控制器进入一个无限循环,导致 StackOverflowError :

    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:387)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:351)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:303)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:133)
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:136)
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:94)
    at org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:181)
    at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:81)
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:377)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:369)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:286)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:339)
    at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:62)
    at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1205)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1262)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
    at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:283)
    at com.foo.domain.validate.UniqueNameValidator.isValid(UniqueNameValidator.java:30)
    at com.foo.domain.validate.UniqueNameValidator.isValid(UniqueNameValidator.java:1)
    at org.hibernate.validator.internal.engine.ConstraintTree.validateSingleConstraint(ConstraintTree.java:308)
    at org.hibernate.validator.internal.engine.ConstraintTree.validateConstraints(ConstraintTree.java:180)
    at org.hibernate.validator.internal.engine.ConstraintTree.validateConstraints(ConstraintTree.java:124)
    at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:86)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:442)
    at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:387)
    

    请注意,第一行和最后一行是相同的。在发生堆栈溢出之前,此堆栈跟踪会重复多次。

    我的UniqueNameValidator如下所示:

    public class UniqueNameValidator implements ConstraintValidator<UniqueFoo, Foo> {
      public boolean isValid(Foo value, ConstraintValidatorContext context) {
        TypedQuery<Long> q = ... // checks several conditions with other models in actual code
        return q.getSingleResult() == 0;
      }
    }
    

    我的Roo MVC控制器如下所示:

    @RequestMapping(method = RequestMethod.POST, produces = "text/html")
    public String create(@Valid Foo foo,
                         BindingResult bindingResult,
                         Model uiModel,
                         HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            populateCreateForm(uiModel, foo);
            return "foos/create";
        }
        uiModel.asMap().clear();
    
        foo.persist();
    
        return Session.getStoredURI("/" + encodeUrlPathSegment(foo.getId().toString(), httpServletRequest));
    }
    

    我的模型看起来是这样的:

    @RooJavaBean
    @RooJpaActiveRecord
    @UniqueName
    public class Foo {
      @NotNull
      private String parentName;
      ...
    }
    

    我做错了什么?

    1 回复  |  直到 11 年前
        1
  •  1
  •   user684934 user684934    11 年前

    UniqueNameValidator中的查询导致递归验证。

    TypedQuery<Long> q = ... 
    return q.getSingleResult() == 0;
    

    需要:

    TypedQuery<Long> q = ...
    q.setFlushMode(FlushModeType.COMMIT);
    return q.getSingleResult() == 0;