From fee8abfa5f54b9fa45f6f5a491bbbec1ac53b0a0 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Wed, 7 Oct 2020 16:44:11 +0100 Subject: [PATCH] Drop "[]" from parameter names in data binding Closes gh-25836 --- .../web/bind/WebDataBinder.java | 24 ++++++++++++++++++- .../support/WebExchangeDataBinderTests.java | 11 ++++++++- .../support/WebRequestDataBinderTests.java | 14 ++++++++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java b/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java index c2893de0fe..a1cd50ad74 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java +++ b/spring-web/src/main/java/org/springframework/web/bind/WebDataBinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -194,6 +194,7 @@ public class WebDataBinder extends DataBinder { protected void doBind(MutablePropertyValues mpvs) { checkFieldDefaults(mpvs); checkFieldMarkers(mpvs); + adaptEmptyArrayIndices(mpvs); super.doBind(mpvs); } @@ -249,6 +250,27 @@ public class WebDataBinder extends DataBinder { } } + /** + * Check for property values with names that end on {@code "[]"}. This is + * used by some clients for array syntax without an explicit index value. + * If such values are found, drop the brackets to adapt to the expected way + * of expressing the same for data binding purposes. + * @param mpvs the property values to be bound (can be modified) + * @since 5.3 + */ + protected void adaptEmptyArrayIndices(MutablePropertyValues mpvs) { + for (PropertyValue pv : mpvs.getPropertyValues()) { + String name = pv.getName(); + if (name.endsWith("[]")) { + String field = name.substring(0, name.length() - 2); + if (getPropertyAccessor().isWritableProperty(field) && !mpvs.contains(field)) { + mpvs.add(field, pv.getValue()); + } + mpvs.removePropertyValue(pv); + } + } + } + /** * Determine an empty value for the specified field. *

The default implementation delegates to {@link #getEmptyValue(Class)} diff --git a/spring-web/src/test/java/org/springframework/web/bind/support/WebExchangeDataBinderTests.java b/spring-web/src/test/java/org/springframework/web/bind/support/WebExchangeDataBinderTests.java index 176397e5e3..8eb211f562 100644 --- a/spring-web/src/test/java/org/springframework/web/bind/support/WebExchangeDataBinderTests.java +++ b/spring-web/src/test/java/org/springframework/web/bind/support/WebExchangeDataBinderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -104,6 +104,15 @@ public class WebExchangeDataBinderTests { assertThat(this.testBean.isPostProcessed()).isFalse(); } + @Test // gh-25836 + public void testFieldWithEmptyArrayIndex() { + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("stringArray[]", "ONE"); + formData.add("stringArray[]", "TWO"); + this.binder.bind(exchange(formData)).block(Duration.ofMillis(5000)); + assertThat(this.testBean.getStringArray()).containsExactly("ONE", "TWO"); + } + @Test public void testFieldDefault() throws Exception { MultiValueMap formData = new LinkedMultiValueMap<>(); diff --git a/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderTests.java b/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderTests.java index b01cd408b9..5122f33ca6 100644 --- a/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderTests.java +++ b/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -112,6 +112,18 @@ public class WebRequestDataBinderTests { assertThat(target.isPostProcessed()).isFalse(); } + @Test // gh-25836 + public void testFieldWithEmptyArrayIndex() { + TestBean target = new TestBean(); + WebRequestDataBinder binder = new WebRequestDataBinder(target); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("stringArray[]", "ONE"); + request.addParameter("stringArray[]", "TWO"); + binder.bind(new ServletWebRequest(request)); + assertThat(target.getStringArray()).containsExactly("ONE", "TWO"); + } + @Test public void testFieldDefault() throws Exception { TestBean target = new TestBean();