Affects: 5.3.6


I would like to create a URL that uses path parameters, such as /foo/{fooId}/details. Any characters with special meaning in fooId such as / will need URL escaping in such context.

I had expected that UriComponents with the expand() method would do that escaping for me, but it does not:

    @Test
    public void testUriComponentsPathVariableEscaping() {
        String url = UriComponentsBuilder.newInstance()
            .path("/foo/{fooId}/details")
            .build()
            .expand("x/y")
            .toUriString();
        assertThat(url).isEqualTo("/foo/x%2Fy/details");
    }
...
org.opentest4j.AssertionFailedError: 
expected: "/foo/x%2Fy/details"
but was : "/foo/x/y/details"

I notice that "/" is indeed listed as not "allowed" in org.springframework.web.util.HierarchicalUriComponents.Type#PATH, so something is being lost in the long path between expand and there.

I am using org.springframework:spring-web:5.3.6

Thanks,

Rich

Comment From: rstoyanchev

Thanks for getting in touch, but it feels like this is a question that would be better suited to Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use the issue tracker only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add some more details if you feel this is a genuine bug.

As an aside, expand and encode are two independent steps. Please, review the documentation.

Comment From: RichardBradley

Thanks for your reply.

This was not intended as a question, but as a bug report. I think you are right that this is working as designed though, sorry.

It seems that

UriComponentsBuilder.newInstance()
            .path("/foo/{fooId}/details")
            .build("x/y");

will correctly escape variables, but my previous attempt:

UriComponentsBuilder.newInstance()
            .path("/foo/{fooId}/details")
            .build()
            .expand("x/y")
            .toUriString();

does not, as the docs state "for historic reasons and for backwards compatibility". This is alarming to me as the two do not appear to request different escaping rules.

I had carefully read the docs, but apparently not carefully enough. I think I will avoid this helper class and use String.format with explicit escaping instead.

Comment From: rstoyanchev

The difference is that the end result is a URI in one case, which brings in encoding as an implicit step. The end result of the other is a String and the Javadoc on toUriString indicates that it is a simple concatenation, without encoding.

Comment From: RichardBradley

Thanks.

In my opinion it is clearly a bug for a library to have a method "toUriString" which returns an invalid URI string because it fails to correctly escape some URI components, but I understand that this currently needs preserving for backwards compatibility.