views:

6619

answers:

5

I want to send a URI as the value of a query/matrix parameter. Before I can append it to an existing URI, I need to encode it according to RFC 2396. For example, given the input:

http://google.com/resource?key=value1 & value2

I expect the output:

http%3a%2f%2fgoogle.com%2fresource%3fkey%3dvalue1%2520%26%2520value2

Neither java.net.URLEncoder nor java.net.URI will generate the right output. URLEncoder is meant for HTML form encoding which is not the same as RFC 2396. URI has no mechanism for encoding a single value at a time so it has no way of knowing that value1 and value2 are part of the same key.

A: 

I think that the URI class is the one that you are looking for.

Glenn
It doesn't help because it expects me to pass in a full query string. It has no way of knowing which part of the string needs to be encoded and which part does not. I need a method that takes in a raw parameter value and passes out the URL encoded form.
Gili
Glen, please delete your answer. Otherwise Stackoverflow will think my question has been answered.
Gili
Uh, no it won't ...
A. Rex
Yes. Stackoverflow marks questions as answered if they have been up-voted once. This answer has been up-voted by one person and I down-voted it. It still marks my questions as answered last time I checked.
Gili
Proof: http://stackoverflow.com/unanswered/tagged/rfc2396 is empty
Gili
My bad. You're right. I assumed "upvoted answer" meant ... you know, an answer with a positive number to its left ...
A. Rex
Same here, please vote for http://stackoverflow.uservoice.com/pages/general/suggestions/103614-use-score-0-instead-of-up-votes-for-unanswered-questions
Gili
Why don't you update your question to indicate that the URI class will not work for you? Otherwise, someone else will enter in the same advice even if I delete my answer. BTW, why can't the full URI be encoded?
Glenn
Gili
The question has been updated, please delete the answer :)
Gili
+2  A: 

It seems that CharEscapers from Google GData-java-client has what you want. It has uriPathEscaper method, uriQueryStringEscaper, and generic uriEscaper. (All return Escaper object which does actual escaping). Apache License.

Peter Štibraný
I'll take a look :) thanks!
Gili
Unfortunately it uses some other classes and interfaces, but I think you'll be able to modify it to suit your needs.
Peter Štibraný
"There has to be an easier way than this". It amazes me that this common use-case (building URIs) isn't easier to do. java.net.URI should do a better job.
Gili
I was surprised at how messy this area is (honestly, I didn't even know there is such thing as special URI Encoding ... I learned something).
Peter Štibraný
Peter, I just realized this might work: https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriBuilder.htmlI am using JAX-RS anyway for my application. I'll try it and report back.
Gili
Confirmed, it works! :)
Gili
Peter, please add the following and I will mark it as the accepted answer:"javax.ws.rs.core.UriBuilder will do what you want:https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriBuilder.html"
Gili
Feel free to answer your question yourself :-) You found solution which works best for you. People who are searching for same problem can then choose whatever works for them.
Peter Štibraný
The reason I want you to post the answer is that I can't "accept" my own answer. Please post a new answer and I'll "accept it".
Gili
OK. Didn't know about accepting own answer, I thought it's possible.
Peter Štibraný
+1 for CharEscapers. I ran into this issue today and this fixed it: // false will force spaces to encode as %20CharEscapers.uriEscaper(false).escape(value);
James Cooper
A: 

Mmhh I know you've already discarded URLEncoder, but despite of what the docs say, I decided to give it a try.

You said:

For example, given an input:

http://google.com/resource?key=value

I expect the output:

http%3a%2f%2fgoogle.com%2fresource%3fkey%3dvalue

So:

C:\oreyes\samples\java\URL>type URLEncodeSample.java
import java.net.*;

public class URLEncodeSample {
    public static void main( String [] args ) throws Throwable {
        System.out.println( URLEncoder.encode( args[0], "UTF-8" ));
    }
}

C:\oreyes\samples\java\URL>javac URLEncodeSample.java

C:\oreyes\samples\java\URL>java URLEncodeSample "http://google.com/resource?key=value"
http%3A%2F%2Fgoogle.com%2Fresource%3Fkey%3Dvalue

As expected.

What would be the problem with this?

OscarRyz
It is similar to RFC2396 but is not the same. For example, try encoding spaces. URLEncoder will encode it as '+', URIs expect %20 instead. There are other differences.
Gili
Ok but you wouldn't be encodgin: "value with space" but "value+with+space" like this:
OscarRyz
like:java URLEncodeSample "http://google.com/resource?key=value+with+spaces" http%3A%2F%2Fgoogle.com%2Fresource%3Fkey%3Dvalue%2Bwith%2Bspaces
OscarRyz
There are a whole slew of rules that one must follow for RFC 2369. Instead of playing games with the input string I'd rather find a class that encodes things properly.
Gili
What do you intend to do? That would be very helpful to know in order to give you the right answer.
OscarRyz
+5  A: 

On Gili's request: https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriBuilder.html is what worked for Gili (also because he is already using JAX-RS).

Peter Štibraný
Good answer +1 :)
OscarRyz
+2  A: 

Hello. I don't have enough reputation to comment on answers, but I just wanted to note that downloading the JSR-311 api by itself will not work. You need to at least download the reference implementation (jersey).

Just downloading the api from the JSR page will just give you a ClassNotFoundException when the api tries to look for an implementation at runtime.

yincrash
specifically, you need jsr311-api, jersey-server, and jersey-core jars.
yincrash