Browser replaces '+ ' character with space - gwt

I am passing an attribute(say, test="ae23+raj") in URL and retrieve it. My URL is 10.203.16.15:8080/page1?test="ae23+raj"
I initially thought this is related to encoding issue and tried out that option too. Later i noticed that after retrieving the attribute value, I printed the value in Window.alert(test). i get "ae23 raj" as value.
I need this value as it's. That is "ae23+raj". I don't know how many such special characters are there which will be replaced by the browser with some other character. Any help here? Thanks in advance.

Encode/Decode the URL. Here are the JSNI methods that you can use at client side.
public static final native String encodeUri(String uri) /*-{
return encodeURI(uri);
}-*/;
public static final native String decodeUri(String uri) /*-{
return decodeURI(uri);
}-*/;
%22ae23%2Braj%22 is the encoded value of "ae23+raj". Decode back at client side to get the desired value.
There are lots of others ways also in JavaScript to encode/decode the URL.
Read about
JavaScript decodeURI() Function
JavaScript decodeURIComponent() Function
JavaScript encodeURI() Function
JavaScript encodeURIComponent() Function
Look at URL Decoder/Encoder.
Read more about HttpServletResponse#encodeURL() to encode a URL at server side.
how to get url query params
/** The query params. */
private static Map<String, String> queryParams = new HashMap<String, String>();
static {
Map<String, List<String>> paramsMap = Window.Location.getParameterMap();
for (String key : paramsMap.keySet()) {
List<String> values = paramsMap.get(key);
if (values.size() > 0) {
String value = decodeUri(values.get(0));
queryParams.put(key.toLowerCase(), value);
queryParams.put(key, value);
}
}
}

In a query-string encoded as application/x-www-form-urlencoded (what most people use: key-value pairs separated by & with a = as the key-value separator), a + is the encoded value of a space: http://www.w3.org/TR/html5/forms.html#url-encoded-form-data.
You have to use %20 for a space.
…or you could deviate from the de-facto standard, but then you'll have to parse your query-string yourself, as all tools (HttpServlerRequest#getParameter and GWT's Window.Location#getParameter, to name a few) will decode the + into a space.

Related

RESTEasy mapping a "legacy" Moodle REST service

I'm trying to map a "legacy" REST server using RESTEasy client.
The urls of this ws are mapped like this:
http://localhost/webservice/rest/server.php?wstoken=reallylongtokenhash&wsfunction=core_course_get_courses
The endpoint is always server.php, and the function to call is mapped using a queryparam.
#POST
#Path("/server.php")
#Produces("application/json")
List<Map<String, Object>> getCourses(
#QueryParam("wstoken") String token
, #QueryParam("wsfunction") String function
, #QueryParam("moodlewsrestformat") String format);
#POST
#Path("/server.php")
#Produces("application/json")
String createUser(
#QueryParam("wstoken") String token
, #QueryParam("wsfunction") String function
, #QueryParam("moodlewsrestformat") String format
, #Form User user);
which I call in this way
private static void getCourses() {
final MoodleRest client = ProxyFactory.create(MoodleRest.class, "http://localhost/webservice/rest/");
final List<Map<String, Object>> s = client.getCourses(token, "core_course_get_courses", "json");
System.out.println("s = " + s);
}
Let's ignore the fact that a "get_courses" method is mapped using a POST, and that the token are passed using the QueryParameter on this post, is it possible to avoid passing the function and the response format on every method? I would like to map it using the annotations.
I tried to write in directly into the #Path using
/server.php?function=core_course_get_courses
But obviously this is not the right way to proceed (plus, it doesn't work since it's escaped)
Maybe it would be better to use HttpServletRequest directly in your method and parse request parameters "by hand". I mean:
#POST
#Path("/server.php")
#Produces("application/json")
List<Map<String, Object>> getCourses(#Context HttpServletRequest request){
//parse request.getParameters()
}

How to handle optional query parameters in Play framework

Lets say I have an already functioning Play 2.0 framework based application in Scala that serves a URL such as:
http://localhost:9000/birthdays
which responds with a listing of all known birthdays
I now want to enhance this by adding the ability to restrict results with optional "from" (date) and "to" request params such as
http://localhost:9000/birthdays?from=20120131&to=20120229
(dates here interpreted as yyyyMMdd)
My question is how to handle the request param binding and interpretation in Play 2.0 with Scala, especially given that both of these params should be optional.
Should these parameters be somehow expressed in the "routes" specification? Alternatively, should the responding Controller method pick apart the params from the request object somehow? Is there another way to do this?
Encode your optional parameters as Option[String] (or Option[java.util.Date], but you’ll have to implement your own QueryStringBindable[Date]):
def birthdays(from: Option[String], to: Option[String]) = Action {
// …
}
And declare the following route:
GET /birthday controllers.Application.birthday(from: Option[String], to: Option[String])
A maybe less clean way of doing this for java users is setting defaults:
GET /users controllers.Application.users(max:java.lang.Integer ?= 50, page:java.lang.Integer ?= 0)
And in the controller
public static Result users(Integer max, Integer page) {...}
One more problem, you'll have to repeat the defaults whenever you link to your page in the template
#routes.Application.users(max = 50, page = 0)
In Addition to Julien's answer. If you don't want to include it in the routes file.
You can get this attribute in the controller method using RequestHeader
String from = request().getQueryString("from");
String to = request().getQueryString("to");
This will give you the desired request parameters, plus keep your routes file clean.
Here's Julien's example rewritten in java, using F.Option: (works as of play 2.1)
import play.libs.F.Option;
public static Result birthdays(Option<String> from, Option<String> to) {
// …
}
Route:
GET /birthday controllers.Application.birthday(from: play.libs.F.Option[String], to: play.libs.F.Option[String])
You can also just pick arbitrary query parameters out as strings (you have to do the type conversion yourself):
public static Result birthdays(Option<String> from, Option<String> to) {
String blarg = request().getQueryString("blarg"); // null if not in URL
// …
}
For optional Query parameters, you can do it this way
In routes file, declare API
GET /birthdays controllers.Application.method(from: Long, to: Long)
You can also give some default value, in case API doesn't contain these query params it will automatically assign the default values to these params
GET /birthdays controllers.Application.method(from: Long ?= 0, to: Long ?= 10)
In method written inside controller Application these params will have value null if no default values assigned else default values.
My way of doing this involves using a custom QueryStringBindable. This way I express parameters in routes as:
GET /birthdays/ controllers.Birthdays.getBirthdays(period: util.Period)
The code for Period looks like this.
public class Period implements QueryStringBindable<Period> {
public static final String PATTERN = "dd.MM.yyyy";
public Date start;
public Date end;
#Override
public F.Option<Period> bind(String key, Map<String, String[]> data) {
SimpleDateFormat sdf = new SimpleDateFormat(PATTERN);
try {
start = data.containsKey("startDate")?sdf.parse(data.get("startDate") [0]):null;
end = data.containsKey("endDate")?sdf.parse(data.get("endDate")[0]):null;
} catch (ParseException ignored) {
return F.Option.None();
}
return F.Option.Some(this);
}
#Override
public String unbind(String key) {
SimpleDateFormat sdf = new SimpleDateFormat(PATTERN);
return "startDate=" + sdf.format(start) + "&" + "endDate=" + sdf.format(end);
}
#Override
public String javascriptUnbind() {
return null;
}
public void applyDateFilter(ExpressionList el) {
if (this.start != null)
el.ge("eventDate", this.start);
if (this.end != null)
el.le("eventDate", new DateTime(this.end.getTime()).plusDays(1).toDate());
}
}
applyDateFilter is just a convienence method i use in my controllers if I want to apply date filtering to the query. Obviously you could use other date defaults here, or use some other default than null for start and end date in the bind method.

Return raw string from REST service method

I have a REST service method written in C#, defined as below:
[WebGet(UriTemplate = "/{par1}/{par2}/{par3}")]
public string ProcessGet(string par1, string par2, string par3)
{
return Execute(...);
}
It should return result as XML or JSON, based on one parameter (I generate the json and XML serialization)
How can I make this method to return the RAW string, just as I created it, without HTMLEncoding it?
Thank you
Return it as a Stream - that causes the "raw" mode to be used and WCF will not touch your response. You can find more information at http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-web.aspx.

GWT Overlay Tpes check for null

I'm using GWT overlay types to parse my JSON response form the web server. It all works fine, the problem is, if the required field doesn't exist:
example:
JavaScriupt overlay type class
public class JSWorkplace extends JavaScriptObject{
protected JSWorkplace() {
}
public final native String getWidgets() /*-{
return this.Widgets;
}-*/;
now if I have something like {"Widgets":"Bla"} comes form the server everything is alright, getWidgets returns "Bla".
If this "{}" comes from the server my application throws in the gwtWidgets function. How can I check if the field "Widgets" exists before reading it.
Regards,
Stefan
You can check if it's undefined doing something like: this.Widgets == undefined.
Personally I prefer to set default values after the eval(). For example, in order to create your JSWorkplace object I would invoke a method like this:
public static native JSWorkspace createFromJSON(String json)/*-{
var object = eval('(' + json + ')');
if (object.Widgets == undefined) { object.Widgets = []; }
...
return object;
}*-/;

Why is Jersey's UriBuilder.build method encoding #'s and %'s, but not /'s?

I have a REST API which is fairly typical, except that the id's of resources are not integers, but strings, which often contain / characters. So if a customer's id is string/with/slashes then the URI for that customer should be http://localhost/customers/string%2Fwith%2Fslashes. When returning a list of customers, I want to construct that URI with a UriBuilder so I can put it in the href of ATOM-style link elements. But it doesn't quite work; here's a small test class that shows what I mean:
#Path("/customers")
public class JerseyTest {
#Path("{id}")
public Customer getCustomer(#PathParam("{id}") String id) {
return null;
}
public static void main(String[] args) {
buildURI("string#with#hashes"); // => http://localhost/customers/string%23with%23hashes
buildURI("string/with/slashes"); // => http://localhost/customers/string/with/slashes
}
public static void buildURI(String id) {
UriBuilder builder = UriBuilder.fromUri("http://localhost");
builder.path(JerseyTest.class).path(JerseyTest.class, "getCustomer");
URI uri = builder.build(id);
System.out.println(uri);
}
}
The #'s get encoded as I would expect but the /'s don't. I tried using builder.build(URLEncoder.encode(id)) instead, but then the UriBuilder encodes the %'s so you get .../string%252Fwith%252Fslashes!
It seems inconsistent to me that it encodes # and % but not /, but I suspect there is a good reason for it which I am not seeing. So my question is:
How can I get UriBuilder to give me .../string%2Fwith%2Fslashes, which is the URI that causes Jersey to call getCustomer with id equal to string/with/slashes? edit: I discovered a way to solve this: builder.buildFromEncoded(URLEncoder.encode(id)). Leaving this question open though, in hopes of getting an answer to the second part...
More generally, why does UriBuilder.build encode some special characters, but not others?
I found How do I encode URI parameter values?, where the accepted answer says "Use UriBuilder." Well, I am using it, but apparently I'm using it incorrectly.
This seem to be a confirmed issue:
http://java.net/jira/browse/JAX_RS_SPEC-70
Your workaround sounds good.