With spring-web 6.2.5, I get the following behavior :
System.out.println(UriComponentsBuilder.fromUriString(“http://myhost?a={p1}&b={p2}&a={p3}”).buildAndExpand(“a1”, “b1”, “a2”));
Output :
http://myhost?a=a1&a=b1&b=a2
I was expecting the following output :
http://myhost?a=a1&b=b1&a=a2
It seems that query params are reordered.
Even if it’s not a good idea to rely on query parameter order, it seems to be legal (see stackoverflow > Is it legal or safe to depend on the ordering of URL query parameters?)… So I think that things like RestClient may require proper query parameter order handling.
Furthermore, query params reordering seems to happen before uri template variables are expanded so values get swapped when given from an array (ie not from map) as the order of variables is then significant.
Comment From: christophejan
If my understanding is correct, URI RFC doesn’t specify query parameters. In current WHATWG HTLM standard, 4.10.21.7 URL-encoded form data just point to WHATWG URL standard 5 application/x-www-form-urlencoded that state :
The application/x-www-form-urlencoded format provides a way to encode a list of tuples, each consisting of a name and a value.
This section also details in depth the related parsing and serializing.
I think that something based on a List of name value tuple could be more appropriate as internal model of query parameter in UriComponents than the current MultiValueMap
I think a such change may be also the opportunity to potentially design a class for such list of name value tuple with all the helping methods (get the value for the first tuple of name, from / to MultiValueMap conversion etc.) to be possibly used elsewhere. It could be class dedicated to query parameters like HttpHeaders does or a more generic one.
It is, of course, possible I just misunderstood something.
Comment From: rstoyanchev
We generally preserve the order of query parameters and their values. The only exception is when multiple values for the same query parameter are not specified together (and have other query parameters in between). This is due to the use of a MultiValueMap for internal storage that groups by query parameter name.
We do support the WhatWG URL living standard as of the parsing algorithms, but that's just the parsing side.
Arguably, we could do better with this, but there are options for you to eliminate ambiguity if this is a URI template that's in your control. Either declare query parameter values together, or use the buildAndExpand
variant with a Map
, or initialize the query parameters in a MultiValueMap.
Comment From: christophejan
There is indeed workarounds but the current behavior is : * error prone (require some knowledge of the implementation storage) * limiting (some api may require to not follow the current params grouping)
Leaving the MultiValueMap storage for a list of tuple would solve that and be closer to the specification.
I think that it could be done without breaking the backward compatibility and without introducing any drawbacks.
UriComponent is widely used so please consider it may worth this effort.
Comment From: rstoyanchev
Indeed there is room for improvement so I will mark the issue accordingly.
Comment From: Mamun-Al-Babu-Shikder
The current behavior of UriComponentsBuilder using MultiValueMap
To overcome this, an internal switch from MultiValueMap to a List
For example, instead of storing: { a: [x, z], b: [y] } We store: [(a, x), (a, z), (b, y)]
Then serialize the query string based on insertion order.
This would make URI expansion more intuitive and compliant with real-world API expectations, and could be avoid breaking existing consumers.
Comment From: SuganthiThomas
Hi, I’m interested in working on this issue. I have experience with Java and Spring Boot. Could I take this up?