wix-incubator / accord

Accord: A sane validation library for Scala
http://wix.github.io/accord/
Other
529 stars 55 forks source link

Spring integration: Error details are not propagated to the error object #36

Open holograph opened 9 years ago

holograph commented 9 years ago

When validation fails on a delegated object, the error details (from the group violation) aren't persisted to the Errors object. For example, for the following domain model:

  case class Contained( field: String )
  case class Container( field: String, contained: Contained )

  object Contained {
    implicit val containedValidator = validator[ Contained ] { c =>
      c.field has ( size >= 2 and size <= 4 )
    }
  }

  object Container {
    implicit val containerValidator = validator[ Container ] { c =>
      c.field is notEmpty
      c.contained is valid
    }
  }

When running the following test:

    val contained = Contained( field = "not good!" )
    val container = Container( "ok", contained )

    val errors = new BeanPropertyBindingResult( container, container.getClass.getSimpleName )
    validator.validate( container, errors )
    println( errors )

The result is a correct Errors object, but is missing a lot of details:

Error in object 'Container': codes [accord.validation.failure.Container,accord.validation.failure]; arguments []; default message [contained is invalid]

Note that the error message is the top-level "field is invalid" constraint violation, but none of the details from the GroupViolation are included.

Reported by @hugebdu and @itaykor.

holograph commented 9 years ago

Note that this is a known limitation as indicated by the Spring integration documentation.

holograph commented 9 years ago

Need some help figuring out the right kind of rendering. To start with, I added a test to the issue36 branch so we can actually spec out the desired behavior; it looks something like:

  // Sample domain:
  case class Contained( field: String )
  implicit val containedValidator = validator[ Contained ] { c =>
    c.field has ( size >= 2 and size <= 4 )
  }

  case class Container( field: String, contained: Contained )
  implicit val containerValidator = validator[ Container ] { c =>
    c.field is notEmpty
    c.contained is valid
  }

  // Test:
  "correctly render nested validation errors" in {
    val contained = Contained( "not good!" )
    val container = Container( "ok", contained )

    val errors: Errors = new BeanPropertyBindingResult( container, "container" )
    val adapter = new AccordValidatorAdapter( containerValidator )
    adapter.validate( container, errors )
    errors.getAllErrors should have size 1
    errors.getAllErrors.head shouldBe a[ FieldError ]

    val fe = errors.getAllErrors.head.asInstanceOf[ FieldError ]
    fe.getField shouldEqual "contained"
    fe.getRejectedValue shouldEqual Contained( "not good!" )
    // What should actually go in here?
  }

Now the question is, what is the desired rendering behavior? I've been doing some reading about Spring Validation, but have yet to figure out what the "nominal" rendering behavior is.

holograph commented 9 years ago

@hugebdu @itaykor Your input would be appreciated...

holograph commented 9 years ago

Also reported by @nivi1979, your two cents would also be appreciated :-)

holograph commented 8 years ago

Removed milestone, but keeping open for future reference. No progress can be made on this without some serious feedback.