How to force URIBuilder.path(...) to encode parameters like "%AD"? This method doesn't always encode parameters with percentage, correctly

jax-rs, jersey, jersey-1.0

Solution

UriBuilder

This is possible with help of UriComponent from Jersey or URLEncoder directly from Java:

UriBuilder.fromUri("https://dummy.com")
        .queryParam("param",
                UriComponent.encode("%AD",
                    UriComponent.Type.QUERY_PARAM_SPACE_ENCODED))
        .build();

Which result in:

https://dummy.com/?param=%25AD

Or:

UriBuilder.fromUri("https://dummy.com")
        .queryParam("param", URLEncoder.encode("%AD", "UTF-8"))
        .build()

Will result in:

https://dummy.com/?param=%25AD

For a more complex examples (i.e. encoding JSON in query param) this approach is also possible. Let's assume you have a JSON like `{"Entity":{"foo":"foo","bar":"bar"}}`. When encoded using `UriComponent` the result for query param would look like:

https://dummy.com/?param=%7B%22Entity%22:%7B%22foo%22:%22foo%22,%22bar%22:%22bar%22%7D%7D

JSON like this could be even injected via `@QueryParam` into resource field / method param (see JSON in Query Params or How to Inject Custom Java Types via JAX-RS Parameter Annotations).

Which Jersey version do you use? In the tags you mention Jersey 2 but in the `RuntimeDelegate` section you're using Jersey 1 stuff.

Problem

How to force `URIBuilder.path(...)` to encode parameters like `"%AD"`? The methods `path`, `replacePath` and `segment` of `URIBuilder` do not always encode parameters with percentage, correctly. When a parameter contains the character "%" followed by two characters that together form an URL-encoded character, the "%" is not encoded as "%25". For example ``` URI uri = UriBuilder.fromUri("https://dummy.com").queryParam("param", "%AD"); String test = uri.build().toString(); ``` "test" is "https://dummy.com?param=%AD" But it should be "https://dummy.com?param=%25AD" (with the character "%" encoded as "%25") The method `UriBuilderImpl.queryParam(...)` behaves like this when the two characters following the "%" are hexadecimal. I.e, the method "com.sun.jersey.api.uri.UriComponent.isHexCharacter(char)" returns true for the characters following the "%". I think the behavior of UriBuilderImpl is correct because I guess it tries to not encode parameters that already are encoded. But in my scenario, I will never try to create URLs with parameters that already encoded. What should I do? My Web application uses Jersey and in many places I build URIs using the class UriBuilder or invoke the method `getBaseUriBuilder` of `UriInfo` objects. I can replace "%" with "%25", every time I invoke the methods `queryParam`, `replaceQueryParam` or `segment`. But I am looking for a less cumbersome solution. How can I make Jersey to return my own implementation of UriBuilder? I thought of creating a class that extends UriBuilderImpl that overrides these methods and that perform this replacing before invoking `super.queryParam(...)` or whatever. Is there any way of making Jersey to return my own UriBuilder instead of UriBuilderImpl, when invoking `UriBuilder.fromURL(...)`, UriInfo.getBaseUriBuilder(...), etc? Looking at the method `RuntimeDelegate`, I thought of extending `RuntimeDelegateImpl`. My implementation would override the method `createUriBuilder(...)`, which would return my own `UriBuilder`, instead of `UriBuilderImpl`. Then, I would add the file `META-INF/services/javax.ws.rs.ext.RuntimeDelegate` and in it, a the full class name of my `RuntimeDelegateImpl`. The problem is that the jersey-bundle.jar already contains a `META-INF/services/javax.ws.rs.ext.RuntimeDelegate` that points to `com.sun.jersey.server.impl.provider.RuntimeDelegateImpl`, so the container loads that file instead of my `javax.ws.rs.ext.RuntimeDelegate`. Therefore, it does not load my `RuntimeDelegate`implementation. Is it possible to provide my own implementation of `RuntimeDelegate`? Should I take a different approach?

Original source