question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

UriBuilder query parameter encoding behaves differently depending on required RequestParameter

See original GitHub issue

I’m upgrading from sb 1.5.9.RELEASE to 2.5.1 i steps and noticed a different behaviour in how the UriBuilder handles encoding of query parameters depending on if you set the RequestParam required to true or false. The queryparamters ZonedDateTime has to be encoded (+sign), but is not if the RequestParam(required=false). I would expect the parameter to be encoded no matter if it’s required or not. Running the example code will result in the first ‘from’ parameter to be encoded, but the ‘to’ not. I think the issue lies in the DefaultUriBuilder or related. Spring Hateoas uses this to render links.

Following the link will result in -> Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type ‘java.lang.String’ to required type ‘java.time.ZonedDateTime’; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam @org.springframework.format.annotation.DateTimeFormat java.time.ZonedDateTime] for value ‘2021-06-18T14:59:05.802044 02:00[Europe/Copenhagen]’; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2021-06-18T14:59:05.802044 02:00[Europe/Copenhagen]]] Because + is treated as space.

Sample application ->

import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;

import java.time.ZonedDateTime;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class DemoApplication {

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

    @RestController
    public class DemoController {
        @GetMapping(value = "/search/findByDate", produces = MediaType.APPLICATION_JSON_VALUE)
        public ResponseEntity<Void> findByDate(@RequestParam(name = "from", required = true) @DateTimeFormat(iso = ISO.DATE_TIME) ZonedDateTime from,
                                               @RequestParam(name = "to", required = false) @DateTimeFormat(iso = ISO.DATE_TIME) ZonedDateTime to) {
            return ResponseEntity.ok().build();
        }

        @GetMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
        public ResponseEntity<RootResource> getRoot() {
            return ResponseEntity.ok(new RootResource());
        }
    }

    public class RootResource extends RepresentationModel<RootResource> {
        public RootResource() {
            add(linkTo(methodOn(DemoController.class).findByDate(null, null)).withRel("hsf").expand(ZonedDateTime.now(), ZonedDateTime.now().plusMonths(1)));
        }

    }

}

Setting both parameters to required = true renders the link correctly.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
odrotbohmcommented, Jun 29, 2021

Just a quick analysis. It looks like in Spring Framework, there’s a conceptual difference between expanding a URI template and adding parameters via UriComponentsBuilder.queryParam(…). The latter doesn’t URI encode the values given and is used for optional request parameters, whereas required ones are applied by expanding the template. Taking this back to the team, too.

0reactions
pax95commented, Aug 3, 2021

@odrotbohm Tested on 1.4 snapshot and now the encoding is applied as expected. Thanks for looking into this.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to force URIBuilder.path(...) to encode parameters like ...
When a parameter contains the character "%" followed by two characters that together form an URL-encoded character, the "%" is not encoded as...
Read more >
URIBuilder:: query parameters are encoded differently ...
URI, the encoding of the query parameters are different compared to build the URI using URIBuilder. The URIBuilder uses e.g. "+" to encode...
Read more >
7.4 - Request Format - Google
This parameter sets the character encoding that is used to interpret the query string. You should also specify the access parameter (as shown...
Read more >
Spring WebClient Requests with Parameters - Baeldung
First, we'll need to create an instance of WebClient. ... and just pass multiple query parameters with the same key, but different values, ......
Read more >
Spring Boot REST Template URI Encoding - DZone
URI variables are usually meant for path elements, query string parameters, or when you decouple your application from your front-end.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found