Java.net.URI constructor is not encoding & character - java

I am trying to create a URL where the query parameters contain a symbol &. When I am passing this to Java.net.uri(https://docs.oracle.com/javase/8/docs/api/java/net/URI.html) class constructor its not encoding the & symbol to %26.
Example: https://www.anexample.com:443/hello/v5/letscheck/image/down?name=tom&jerry&episode=2
Now tom&jerry is the value of the query parameter but when we pass this to Java.net.uri constructor it encodes all spaces and special symbols but does not encode & to %26.
So tom and jerry both become separate query parameter which I don't want.
code will look something like below:
String query = "name=tom&jerry&episode=2"
URI uri = new URI(scheme, null, host, port, path, query, null);
I have also tried encoding the query parameters myself and then sending it to the constructor like below:
String query = "name=tom%26jerry&episode=2"
URI uri = new URI(scheme, null, host, port, path, query, null);
But in this case the encoded parameter becomes tom%2526jerry as % is encoded to %25
So how can I encode it so I can send & inside as a query parameter?

Have you tried something like below?
String tomJerry = "name=" + URLEncoder.encode("tom&jerry", StandardCharsets.UTF_8.toString());
String episode = "episode=" + URLEncoder.encode("2", StandardCharsets.UTF_8.toString());
String query = tomJerry + '&' + episode;
URI uri = new URI(scheme, null, host, port, path, query, null);
A better way would be looping through the key value pairing of the queries and applying URLEncoder to the value then joining the rest of the query with & after or perhaps stream, map then collect. But the point is to encode the value part of the query string.

Related

URL change encoding + instead of %20

URL encoding normally replaces a space with a plus (+) sign or with %20.
In spring MVC it replaces with %20. My controller as:
#GetMapping(path = "/post/{id}/{title}")
public String postView(#PathVariable("id") Long id, #PathVariable("title") String title, Model model){
Post post = postService.findById(id);
model.addAttribute("post", post);
return "singlePost";
}
I need to replace the %20 with (+) or (-)
Thanks
You can use decode method of URLDecoder class. As an example, if title have url encoded values,
String urlDecodedTitle = URLDecoder.decode(title, StandardCharsets.UTF_8.toString())
In the path of a URL the spaces are replaced by %20 ([RFC3986][1]), while URL query parameters follow the application/x-www-form-urlencoded that replaces spaces by +.
If you need to encode a query string parameter, you can use java.net.URLEncoder.
But as you are using #PathVariable, your parameters are part of the path, hence they must be encoded with spaces replaced by %20. Spring provides UriUtils.encodePath for this task.
For example, to build a query to your /post/{id}/{title} mapping:
Long id = 1L;
String title = "My title";
String path = "/post/" + id + "/" + UriUtils.encodePathSegment(title, "UTF-8");
On your postView method you don't need to do any decoding, as Spring does it already.
[1]: https://www.rfc-editor.org/rfc/rfc3986

URLEncoder - what character set to use for empty space instead of %20 or +

I am trying to open new email from my Java app:
String str=String.valueOf(email);
String body="This is body";
String subject="Hello worlds";
String newStr="mailto:"+str.trim()+"?subject="+URLEncoder.encode(subject,"UTF-8")+"&body="+URLEncoder.encode(body, "UTF-8")+"";
Desktop.getDesktop().mail(new URI(newStr));
Here it is my URLEncoding. As I cannot use body or subject string in URL without encoding them, my output here is with "+" instead of whitespace. Which is normal, I understand that. I was thinking if there is a way to visualize subject and body normally in my message? I tried with .replace("+"," ") but it is not working as it is giving an error. This is how it is now:
I think there might be different character set but I am not sure.
That's the way URLEncoder works.
One possible approach would be to replace all + with %20 after URLEncoder.enocde(...)
Or you could rely on URI constructor to encode your parameters correctly:
String scheme = "mailto";
String recipient = "recipient#snakeoil.com";
String subject = "The Meaning of Life";
String content = "..., the universe and all the rest is 42.\n Rly? Just kidding. Special characters: äöü";
String path = "";
String query = "subject=" + subject + "&body=" + content;
Desktop.getDesktop().mail(new URI(scheme, recipient, path, query, null));
Both solutions have issues:
In the first approach, you might replace actual + signs, with the second, you'll have issues with & character.

How to build an absolute URL from a relative URL using Java?

I have a relative url string, know host and protocol. How can I build an absolute url string?
Seems easy? Yes at first look, but until escaped characters coming. I have to build absolute url from 302 code http(s) response Location header.
lets consider an example
protocol: http
host: example.com
location: /path/path?param1=param1Data&param2= "
First I tried to build url string like:
Sting urlString = protocol+host+location
Constructor of URL class not escapes spaces and double quotes:
new URL(urlString)
Constructors of URI class fail with exception:
new URI(urlString)
URI.resolve method also fails with exception
Then I found URI can escape params in query string, but only with few constructors like for example:
URI uri = new URI("http", "example.com",
"/path/path", "param1=param1Data&param2= \"", null);
This constructor needs path and query be a separate arguments, but I have a relative URL, and it not split by path and query parts.
I could consider to check if relative URL contains "?" question sign and think everything before it is path, and everything after it is query, but what if relative url not contain path, but query only, and query contains "?" sign? Then this will not works because part of query will be considered as path.
Now I cannot get how to build absolute url from relative url.
These accepted answers seems just wrong:
how to get URL using relative path
Append relative URL to java.net.URL
Building an absolute URL from a relative URL in Java
It could be nice to consider scenario when relative url was given in relation to url with both host and some path part:
initial url http://example.com/...some path...
relative /home?...query here ...
It would be great to get java core solution, though it still possible to use a good lib.
The first ? indicates where the query string begins:
3.4. Query
[...] The query component is indicated by the first question mark (?) character and terminated by a number sign (#) character or by the end of the URI.
A simple approach (that won't handle fragments and assumes that the query string is always present) is as simple as:
String protocol = "http";
String host = "example.com";
String location = "/path/path?key1=value1&key2=value2";
String path = location.substring(0, location.indexOf("?"));
String query = location.substring(location.indexOf("?") + 1);
URI uri = new URI(protocol, host, path, query, null);
A better approach that can also handle fragments could be :
String protocol = "http";
String host = "example.com";
String location = "/path/path?key1=value1&key2=value2#fragment";
// Split the location without removing the delimiters
String[] parts = location.split("(?=\\?)|(?=#)");
String path = null;
String query = null;
String fragment = null;
// Iterate over the parts to find path, query and fragment
for (String part : parts) {
// The query string starts with ?
if (part.startsWith("?")) {
query = part.substring(1);
continue;
}
// The fragment starts with #
if (part.startsWith("#")) {
fragment = part.substring(1);
continue;
}
// Path is what's left
path = part;
}
URI uri = new URI(protocol, host, path, query, fragment);
The best way seems to be to create a URI object with the multi piece constructors, and then convert it to a URL like so:
URI uri = new URI("https", "sitename.domain.tld", "/path/goes/here", "param1=value&param2=otherValue");
URL url = uri.toURL();

Java string to URI with parameters

I have this query string to send a http request via a URI object, but the URI object reformats my query string, including the parameters.
You're adding the "query" part to the path. You want
queryString /* misnamed */ += "/v2/cart/addProduct";
String query = "?...";
...
uri = new URI("http", null, getDomain(), 80, queryString, query, null);

Extract part of a URL with URL/URI objects

I have a String holding a URL in this format: http://hello.world.com/service/sps/f4c0e810456t
And I would like to extract the last part of the URL, i.e. f4c0e810456t.
I can do it with substrings:
System.out.println(s.substring(s.lastIndexOf("/") + 1, s.length()));
Or regexp however looking for something more elegant using URL/URI objects but couldn't find something.
Any ideas...?
If you can change the URL to "http://hello.world.com/service/sps/?f4c0e810456t" then you could use the getQuery() method (both on URL and URI).
Example with URL and split (it wrap regular expression for you):
String address = "http://hello.world.com/service/sps/f4c0e810456t";
URL url = new URL(address);
String [] str = url.getPath().split("/");
String result = str[str.length-1];

Categories