spring-projects / spring-projects/spring-framework
Using the MvcUriComponentsBuilder to get a URL to a controller method adds empty parameter when the value is not provided [SPR-14890]
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 60.2k
- Forks
- 38.8k
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 27
Description
Cèsar Ordiñana opened SPR-14890 and commented
I'm developing a Spring boot with Spring MVC web app using Thymeleaf views. I'm using the Building URIs to Controllers and methods from views feature through the Thymeleaf #mvc.url utility.
I have the following sample controller:
@Controller
@RequestMapping(value = "/categories/{category}/products",
name = "CategoriesItemProductsThymeleafController",
produces = MediaType.TEXT_HTML_VALUE)
public class CategoriesItemProductsThymeleafController {
public CategoryService categoryService;
@Autowired
public CategoriesItemProductsThymeleafController(CategoryService categoryService) {
this.categoryService = categoryService;
}
@PostMapping(name = "addToProducts")
@ResponseBody
public ResponseEntity<?> addToProducts(@ModelAttribute Category category,
@RequestParam("products") List<Long> products) {
categoryService.addToProducts(category, products);
return ResponseEntity.ok().build();
}
}
In the Thymeleaf view I get the link to that controller method with something like:
<div id="create-url" data-data-create-url="${(#mvc.url('CategoriesItemProductsThymeleafController#addToProducts')).buildAndExpand('CATEGORY_ID')}"></div>
It uses internally the MvcUriComponentsBuilder.fromMappingName(String) method which returns a MethodArgumentBuilder. It expects a list of product ids as a request parameter, but I can't use the MethodArgumentBuilder.arg() method because the values I want to send are to be selected in javascript.
The problem with this method is that the Url return is the following one:
/categories/CATEGORY_ID/products?products
I use that Url as a parameter to call jQuery.ajax() using my own products values. If I use a GET method, the url ends up being:
/categories/CATEGORY_ID/products?products&products=1&products=2
Then the controller method receives the following list of values: [null, 1, 2]. As a workaround I can remove those null values from the list, but I think the Url is not constructed as it should.
After some debugging I've found the code which add those empty parameters is the HierarchicalUriComponents.getQuery() method. It has the following code:
for (Object value : values) {
if (queryBuilder.length() != 0) {
queryBuilder.append('&');
}
queryBuilder.append(name);
if (value != null) {
queryBuilder.append('=');
queryBuilder.append(value.toString());
}
}
The problem could be solved by changing the code to add the parameter only if value!=null.
Affects: 4.3.3
Issue Links:
- #18113 UriComponentsBuilder interprets empty request parameters as null
1 votes, 3 watchers
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with MvcUriComponentsBuilder.fromMappingName(String) and the mentioned HierarchicalUriComponents.getQuery() implementation. Reproduce the controller and URL-building example from the issue, then verify that an omitted request parameter does not produce a bare “?products” entry while explicitly added values still appear correctly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 38/100