Spring 4.2 vs 4.3: Difference in bind value to Collection type when submitting check box empty

This time, the check generated using the component that supports View implementation provided by Spring (JSP tag library, Macro of Freemarker, etc.) and the cooperation component made by 3rd party (Dialect for Spring cooperation of Thymeleaf, etc.) When submitting a form with the box empty (= unselected), the value set in the Collection type (List, Set, etc.) defined in the form object changes between Spring 4.2 and Spring 4.3. I will talk about it.

Note:

By the way ... If you are using an array instead of the Collection type, the behavior will not change. (An array of empty elements is set)

What is the difference between Spring 4.2 and Spring 4.3?

Suddenly from the conclusion ... In Spring 4.2, null is bound, but from Spring 4.3, a collection object of empty elements is bound.

Note:

The operating specifications have been changed from Spring 4.3 due to improvement requests from Spring users (SPR-13502).

When I actually check it ...

Let's see a concrete example using Thymeleaf (Thymeleaf-Spring). Here, we will simply create a Controller and a form class in the Spring Boot application.

package com.example;

import java.util.List;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@SpringBootApplication
public class CheckboxDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(CheckboxDemoApplication.class, args);
	}

	@RequestMapping("/sample")
	@Controller
	static class SampleController {

		@ModelAttribute //Method for storing the form in the model
		SampleForm setUpForm() {
			return new SampleForm();
		}

		@RequestMapping //Handler method for displaying the form screen
		String form() {
			return "sample/form";
		}

		@RequestMapping(method = RequestMethod.POST) //Handler method for receiving submission from form screen
		String submit(SampleForm form) {
			System.out.println("-----------------------");
			System.out.println("list :" + form.getList());
			return "sample/form";
		}
	}

	static class SampleForm {

		private List<String> list; //Properties to hold the value of the checkbox

		public List<String> getList() {
			return list;
		}

		public void setList(List<String> list) {
			this.list = list;
		}

	}

}
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>Sample</title>
</head>

<body>

<div class="container">

    <form method="post" th:object="${sampleForm}">
        <div class="form-group">
            <label>List</label> <!--Two check box selection values are available-->
            <ul>
                <li>
                    <input type="checkbox" th:field="*{list}" value="1"/>
                    <label th:for="${#ids.prev('list')}">A</label>
                </li>
                <li>
                    <input type="checkbox" th:field="*{list}" value="2"/>
                    <label th:for="${#ids.prev('list')}">B</label>
                </li>
            </ul>
        </div>
        <button class="btn btn-default">Submit</button>
    </form>

</div>
</body>

</html>

When you start the Spring Boot application and access "[http: // localhost: 8080 / sample](http: // localhost: 8080 / sample)", the following (shoboi w) screen is displayed.

checkbox-form.png

In Spring 4.2?

When you press the "Submit" button in Spring Boot 1.3.8.RELEASE (latest release version for Spring 4.2 series), on the console ...

...
2016-12-23 19:40:42.727  INFO 38839 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 13 ms
-----------------------
list :null

It will be displayed. In other words ... null is bound.

In Spring 4.3?

On the other hand ... When you press the "Submit" button in Spring Boot 1.4.3.RELEASE (latest release version for Spring 4.3 series), on the console ...

...
2016-12-23 19:40:42.727  INFO 38839 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 13 ms
-----------------------
list :[]

It will be displayed. This means that an empty list is bound instead of null.

Is there something wrong or has an impact?

Whether or not null becomes a collection of empty elements is a problem or has an effect depends on the creation of your application. For example ... I think that there is no problem (= no effect) in an application that originally treats null and empty elements as the same thing. However, applications that treat null and empty elements as different things may need to do something about it.

For example ... If the required check for the check box item is performed by whether it is null or not as shown below, the process will flow to the logic layer by bypassing the input check.

static class SampleForm {

	@NotNull // Bad ...Empty elements are bound, so null check is NG! !!
	private List<String> list;

	// ...

}

In this case, the Bean Validation standard @Size should use the Hibernate Validator-provided @NotEmpty.

static class SampleForm {
	@Size(min = 1) // Good
	private List<String> list;
	// ...
}

or

static class SampleForm {
	@NotEmpty // Good
	private List<String> list;
	// ...
}

How is the initial value (default value) set?

Generate checkboxes and select boxes using components that support View implementation provided by Spring (JSP tag library, Macros of Freemarker, etc.) and linkage components made by 3rd party (Dialect for Spring integration of Thymeleaf, etc.) Then, special parameters (parameters starting with _) for initializing the properties of the form object are embedded as hidden items. (In this post, this special parameter will be referred to as the "reset parameter" hereafter)

HTML content generated by Thymeleaf



<!DOCTYPE html>


<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Sample</title>
</head>

<body>

<div class="container">

    <form method="post">
        <div class="form-group">
            <label>List</label>
            <ul>
                <li>
                    <input type="checkbox" value="1" id="list1" name="list" /><input type="hidden" name="_list" value="on" />
                    <label for="list1">A</label>
                </li>
                <li>
                    <input type="checkbox" value="2" id="list2" name="list" /><input type="hidden" name="_list" value="on" />
                    <label for="list2">B</label>
                </li>
            </ul>
            
        </div>
        <button class="btn btn-default">Submit</button>
    </form>

</div>
</body>

</html>

In this example, _list is the reset parameter. The value is "ʻon`", but since this reset parameter is a marker parameter, the value has no meaning.

So what does Spring MVC do when you send a reset parameter? When you send the reset parameter ... When the normal request parameter (list in the above example) is not sent as the request parameter (= it is not sent when the check box is empty), the property value of the form object Will initialize.

The value used at the time of this initialization was null until Spring 4.2, but from Spring 4.3 it has become a collection of empty elements.

Note:

Specifically ... ʻorg.springframework.web.bind.WebDataBinder's getEmptyValuemethod determines the value to be set at initialization. From Spring 4.3, the initial values for the implementation class ofjava.util.Collection and the implementation class of java.util.Map` have changed.

Why do we need reset parameters?

Do you need reset parameters? ?? ?? Maybe some people thought that. In conclusion ... it is necessary.

Specifically ... When the form object is managed in session scope using @SessionAttributes, the following operations ...

  1. Display the form screen
  2. Check one check box on the form screen and submit
  3. Return to the form screen again, deselect the check box and submit

If you do, the selected state of the check box will return to the original state (the state where one is checked). The reason why the status returns is ... If all the check boxes are unselected, the request parameter of the corresponding item is not sent at the time of submit, so the process to update the status of the form object managed on the session is executed As a result, the previous state remains.

Spring MVC provides a special parameter called "reset parameter" to avoid the above situation.

Note:

If the input item is disabled, the request parameter will not be sent at the time of submit, so if the UI is to switch between active and inactive by user operation, the same phenomenon will occur unless the reset parameter is sent together. It can occur.

Summary

This time, I talked about the value set when applying the reset parameter provided by Spring MVC is different between Spring 4.2 and 4.3. Is it relatively common to equate null with an empty element? I wonder, but what about your application? For the time being, when updating to Spring 4.3, it seems better to be careful about the handling of checkboxes and select box items.

Recommended Posts

Spring 4.2 vs 4.3: Difference in bind value to Collection type when submitting check box empty
Pay attention to the boundary check of the input value when using the float type
When you want to bind InputStream in JDBI3
How to bind to property file in Spring Boot
[String type vs String Builder] Difference in processing speed in string concatenation