diff --git a/framework/project/Dependencies.scala b/framework/project/Dependencies.scala index 9f56d11f550..080ecb07162 100644 --- a/framework/project/Dependencies.scala +++ b/framework/project/Dependencies.scala @@ -93,7 +93,7 @@ object Dependencies { val javaFormsDeps = Seq( - "org.hibernate" % "hibernate-validator" % "5.4.1.Final", + "org.hibernate" % "hibernate-validator" % "6.0.5.Final", ("org.springframework" % "spring-context" % springFrameworkVersion) .exclude("org.springframework", "spring-aop") diff --git a/framework/src/play-java-forms/src/main/java/play/data/Form.java b/framework/src/play-java-forms/src/main/java/play/data/Form.java index 7259c5f414f..187e6a1d173 100644 --- a/framework/src/play-java-forms/src/main/java/play/data/Form.java +++ b/framework/src/play-java-forms/src/main/java/play/data/Form.java @@ -63,8 +63,13 @@ */ public class Form { - /** Statically compiled Pattern for replacing "." to get the field from a violation. */ - private static final Pattern REPLACE_COLLECTION_ELEMENT = Pattern.compile(".", Pattern.LITERAL); + /** + * Statically compiled Pattern for replacing pairs of "<" and ">" with an optional content and optionally prefixed with a dot. Needed to get the field from a violation. + * This takes care of occurrences like "field.", "field[somekey]", "field[somekey].", "field[somekey].", etc. + * We always want to end up with just "field" or "field[0]" in case of lists or "field[somekey]" in case of maps. + * Also see https://github.com/hibernate/hibernate-validator/blob/6.0.5.Final/engine/src/main/java/org/hibernate/validator/internal/engine/path/NodeImpl.java#L51-L56 + */ + private static final Pattern REPLACE_COLLECTION_ELEMENT = Pattern.compile("\\.?<[^<]*>"); /** Statically compiled Pattern for replacing "typeMismatch" in Form errors. */ private static final Pattern REPLACE_TYPEMISMATCH = Pattern.compile("typeMismatch", Pattern.LITERAL); diff --git a/framework/src/play-java-forms/src/test/java/play/data/ListForm.java b/framework/src/play-java-forms/src/test/java/play/data/ListForm.java deleted file mode 100644 index c3a9dee94bf..00000000000 --- a/framework/src/play-java-forms/src/test/java/play/data/ListForm.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2009-2017 Lightbend Inc. - */ -package play.data; - -import play.data.validation.Constraints; - -import java.util.List; - -import javax.validation.Valid; - -public class ListForm { - - @Valid - private List<@Constraints.Min(0) Integer> values; - - public List getValues() { - return values; - } - - public void setValues(final List values) { - this.values = values; - } -} diff --git a/framework/src/play-java-forms/src/test/java/play/data/TypeArgumentForm.java b/framework/src/play-java-forms/src/test/java/play/data/TypeArgumentForm.java new file mode 100644 index 00000000000..9dd5a10dadb --- /dev/null +++ b/framework/src/play-java-forms/src/test/java/play/data/TypeArgumentForm.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009-2017 Lightbend Inc. + */ +package play.data; + +import play.data.validation.Constraints; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class TypeArgumentForm { + + private List<@Constraints.Min(0) Integer> list; + + private Map<@Constraints.MinLength(3) String, @Constraints.Min(6) Integer> map; + + private Optional<@Constraints.MinLength(9) String> optional; + + public List getList() { + return list; + } + + public void setList(final List list) { + this.list = list; + } + + public Map getMap() { + return map; + } + + public void setMap(final Map map) { + this.map = map; + } + + public Optional getOptional() { + return optional; + } + + public void setOptional(final Optional optional) { + this.optional = optional; + } +} diff --git a/framework/src/play-java-forms/src/test/scala/play/data/FormSpec.scala b/framework/src/play-java-forms/src/test/scala/play/data/FormSpec.scala index 4df9845c8b2..3b84f65c4f3 100644 --- a/framework/src/play-java-forms/src/test/scala/play/data/FormSpec.scala +++ b/framework/src/play-java-forms/src/test/scala/play/data/FormSpec.scala @@ -372,12 +372,32 @@ trait FormSpec extends Specification { } "support type arguments constraints" in { - val listForm = formFactory.form(classOf[ListForm]).bindFromRequest(FormSpec.dummyRequest(Map("values[0]" -> Array("4"), "values[1]" -> Array("-3"), "values[2]" -> Array("6")))) + val listForm = formFactory.form(classOf[TypeArgumentForm]).bindFromRequest(FormSpec.dummyRequest(Map( + "list[0]" -> Array("4"), "list[1]" -> Array("-3"), "list[2]" -> Array("6"), + "map['ab']" -> Array("28"), "map['something']" -> Array("2"), "map['worksperfect']" -> Array("87"), + "optional" -> Array("Acme") + ))) listForm.hasErrors must beEqualTo(true) - listForm.allErrors().size() must beEqualTo(1) - listForm.errors("values[1]").get(0).messages().size() must beEqualTo(1) - listForm.errors("values[1]").get(0).messages().get(0) must beEqualTo("error.min") + listForm.allErrors().size() must beEqualTo(4) + listForm.errors("list[1]").get(0).messages().size() must beEqualTo(1) + listForm.errors("list[1]").get(0).messages().get(0) must beEqualTo("error.min") + listForm.value().get().getList.get(0) must beEqualTo(4) + listForm.value().get().getList.get(1) must beEqualTo(-3) + listForm.value().get().getList.get(2) must beEqualTo(6) + listForm.errors("map[ab]").get(0).messages().get(0) must beEqualTo("error.minLength") + listForm.value().get().getMap.get("ab") must beEqualTo(28) + listForm.errors("map[something]").get(0).messages().get(0) must beEqualTo("error.min") + listForm.value().get().getMap.get("something") must beEqualTo(2) + listForm.value().get().getMap.get("worksperfect") must beEqualTo(87) + listForm.errors("optional").get(0).messages().get(0) must beEqualTo("error.minLength") + listForm.value().get().getOptional.get must beEqualTo("Acme") + // Also test an Optional that binds a value but doesn't cause a validation error: + val optForm = formFactory.form(classOf[TypeArgumentForm]).bindFromRequest(FormSpec.dummyRequest(Map( + "optional" -> Array("Microsoft Corporation") + ))) + optForm.allErrors().size() must beEqualTo(0) + optForm.get().getOptional.get must beEqualTo("Microsoft Corporation") } "work with the @repeat helper" in { diff --git a/framework/src/play-logback/src/main/resources/logback-play-default.xml b/framework/src/play-logback/src/main/resources/logback-play-default.xml index 30791fa0967..cece01da6c9 100644 --- a/framework/src/play-logback/src/main/resources/logback-play-default.xml +++ b/framework/src/play-logback/src/main/resources/logback-play-default.xml @@ -19,8 +19,6 @@ - - diff --git a/framework/src/play-logback/src/main/resources/logback-play-dev.xml b/framework/src/play-logback/src/main/resources/logback-play-dev.xml index 47b1a576c3c..f64e79b99c5 100644 --- a/framework/src/play-logback/src/main/resources/logback-play-dev.xml +++ b/framework/src/play-logback/src/main/resources/logback-play-dev.xml @@ -15,8 +15,6 @@ - - diff --git a/framework/src/play-logback/src/main/resources/logback-play-logSql.xml b/framework/src/play-logback/src/main/resources/logback-play-logSql.xml index 8651b5455bd..5e93faf3247 100644 --- a/framework/src/play-logback/src/main/resources/logback-play-logSql.xml +++ b/framework/src/play-logback/src/main/resources/logback-play-logSql.xml @@ -29,9 +29,6 @@ - - -