I'm invoking a rest WS that returns XML. Some elements have strings include special characters like áãç etc...
When I get the information via browser all of it is shown properly but when invoking it from Android I don't get the proper special characters.
Notice the 'decoded' and 'encoded' variables:
when I use
URLDecoder.decode(result, "UTF-8")
The result stays the same
when I use
URLEncoder.encode(result, "UTF-8") The result changes to what it would be expected (full of %'s symbols and numeric representing symbols and special characters).
Here's the method to call the webservice:
public void updateDatabaseFromWebservice(){
// get data from webservice
Log.i(TAG, "Obtaining categories from webservice");
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(ConnectionProperties.CATEGORIES_URI);
ResponseHandler<String> handler = new BasicResponseHandler();
String result = "";
String decoded;
String encoded;
try {
result = client.execute(request, handler);
decoded = URLDecoder.decode(result, "UTF-8");
encoded = URLEncoder.encode(result, "UTF-8");
String c = "AS";
} catch (Exception e) {
Log.e(TAG, "An error occurred while obtaining categories", e);
}
client.getConnectionManager().shutdown();
}
Any help would be appreciated
Use this to get xml string, assuming the server encodes data in UTF-8:
HttpResponse response = client.execute(request);
... // probably some other code to check for HTTP response status code
HttpEntity responseEntity = response.getEntity();
String xml = EntityUtils.toString(responseEntity, HTTP.UTF_8);
Uh. URLDecoder and encoder are for encoding and decoding URLs, not XML content. It is used for URL you use when making requests. So code is just... wrong.
But even bigger issue is that you are taking a String, whereas content is really XML which needs to be parsed. And for parser to do proper decoding of UTF-8 (and handling of entities etc), you would be better of getting a byte[] from request, passing that to parser; although asking http client to do decoding may work ok (assuming service correctly indicates encoding used; not all do -- but even if not, XML parsers can figure it out from xml declaration).
So: remove URLDecoder/URLEncoder stuff, parser XML, and extract data you want from XML.
Related
Currently, I'm building a Android mobile app & Python restful server services.
I found that, it makes no different, whether or not I'm using
self.response.headers['Content-Type'] = "application/json"
The following code (which doesn't specific Content-Type explicitly) works fine for me. I was wondering, in what situation, I should specific Content-Type explicitly?
Python restful server services code
class DebugHandler(webapp2.RequestHandler):
def get(self):
response = {}
response["key"] = "value"
self.response.out.write(json.dumps(response))
application = webapp2.WSGIApplication([
('/debug', DebugHandler),
], debug = True)
Android mobile app client code
public static String getResponseBodyAsString(String request) {
BufferedReader bufferedReader = null;
try {
URL url = new URL(request);
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
initHttpURLConnection(httpURLConnection);
InputStream inputStream = httpURLConnection.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
int charRead = 0;
char[] buffer = new char[8*1024];
// Use StringBuilder instead of StringBuffer. We do not concern
// on thread safety. stringBuffer = new StringBuffer();
StringBuilder stringBuilder = new StringBuilder();
while ((charRead = bufferedReader.read(buffer)) > 0) {
stringBuilder.append(buffer, 0, charRead);
}
return stringBuilder.toString();
} catch (MalformedURLException e) {
Log.e(TAG, "", e);
} catch (IOException e) {
Log.e(TAG, "", e);
} finally {
close(bufferedReader);
}
return null;
}
Content-Type specifies what's inside the response (i.e. how to interpret the body of the response). Is it JSON, a HTML document, a JPEG, etc? It is useful when you have different representations of your resources and together with Accept it's a header involved in doing content negotiation between client and server.
Different clients might need different formats. A C# client might prefer XML, a Javascript client might prefer JSON, another client could work with multiple representations but try to request the most efficient one first and then settle for others if the server can't serve the preferred one, etc.
Content-Type is very important in the browser so that the user agent knows how to display the response. If you don't specify one the browser will try to guess, usually based on the extension and maybe fallback to some Save as... dialog if that fails also. In a browser, the lack of a Content-Type might cause some HTML to open a Save as... dialog, or a PDF file to be rendered as gibberish in the page.
In an application client, not having a Content-Type might cause a parsing error or might be ignored. If you server only serves JSON and your client only expects JSON then you can ignore the Content-Type, the client will just assume it's JSON because that's how it was built.
But what if at some point you want to add XML as a representation, or YAML or whatever? Then you have a problem because the client assumed it's always JSON and ignored the Content-Type. Now when it receives XML it will try to parse as JSON and fail. If instead the client was built with content types in mind and you always specify a Content-Type then your client will then take it into account and select an appropriate parser instead of blindly making assumptions.
Okay, so I was trying to send Http Post Requests to this one site, and I sniffed the sent request with wireshark thus getting the text data from the post request of this site. I used this in a stock Java application, and it worked perfectly fine. I could use the post method regularly with no problem whatsoever, and it would return the appropriate website. Then I tried doing this with Android. Instead of returning the actual html data after executing the post request, it returns the regular page html data untouched. It DOES send a post request (sniff with wireshark again), it just doesn't seem to get the appropriate response. I took the exact same method used from another one of my projects, which worked perfectly fine in that project, and pasted it into my new project. I added the INTERNET user permission in Android, so there's nothing wrong with that. The only visible difference is that I used NameValuePairs in the other one (the one that worked) and in this one I'm directly putting the string into a StringEntity without encoding (using UTF-8 encoding screws up the String though). I used this exact same line of text in regular Java like I said, and it worked fine with no encoding. So what could be the problem? This is the code:
public static String sendNamePostRequest(String urlString) {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(urlString);
StringBuffer sb = new StringBuffer();
try {
post.setEntity(new StringEntity(
"__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwULLTE3NDM5MzMwMzRkZA%3D%3D&__EVENTVALIDATION=%2FwEWBAL%2B%2B4CfBgK52%2BLYCQK1gpH7BAL0w%2FPHAQ%3D%3D&_nameTextBox=John&_zoekButton=Zoek&numberOfLettersField=3"));
HttpResponse response = client.execute(post);
HttpEntity entity = response.getEntity();
BufferedReader br = new BufferedReader(new InputStreamReader(
entity.getContent()));
String in = "";
while ((in = br.readLine()) != null) {
sb.append(in + "\n");
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
Can you see what's wrong here?
I am using the Jackson JSON parser as I heard it was a lot more efficient than the default Android parser. I learned how to use it off this tutorial here
http://www.mkyong.com/java/jackson-streaming-api-to-read-and-write-json/
which is great tutorial if anyone wants to learn how to use Jackson json parser.
However, I am having an issue in that I can parse data fine in Java from a URL, however when I use Jackson with Android, I get null values or the screen just shows up black for some reason.
In order to retrieve the data from the website I am using this code from here
http://www.javacodegeeks.com/2011/01/android-json-parsing-gson-tutorial.html
private InputStream retrieveStream(String url) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(url);
try {
HttpResponse getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(),
"Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
return getResponseEntity.getContent();
}
catch (IOException e) {
getRequest.abort();
Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
}
return null;
}
Then in my parse data method
InputStream source = retrieveStream(url);
try {
JsonFactory jfactory = new JsonFactory();
JsonParser jParser = jfactory.createJsonParser(source);
Then I parse data as was shown in the tutorial I linked above
while (jParser.nextToken() != JsonToken.END_OBJECT) {
String fieldname = jParser.getCurrentName();
if ("Name".equals(fieldname)) {
jParser.nextToken();
this.setName(jParser.getText());
}
if ("Number".equals(fieldname)) {
jParser.nextToken();
this.setNumber(jParser.getText());
}
}
The url I am using is a dummy site set up which just has a JSON file on it which I am using to practice Jackson JSON parsing.
Now I know my parse data code is fine, as I in normal Java class, I can parse the data from the website using the code I created, and it works fine.
However if I try to use the code in Android with the code I have just shown, I just get a black screen for some odd reason. I have internet permissions enabled in manifest
Is there something wrong with the http code I have used? If so could someone show me how it should be done? And also why I am getting a black screen, I don't understand why it would show that.
Thanks in advance
Not sure if this is the problem, but your looping construct is unsafe: depending on kind of data you get, it is quite possible that you do not get END_OBJECT as the next token. And at the end of content, nextToken() will return null to indicate end-of-input. So perhaps you get into infinite loop with certain input?
I found the issue, the link was local host which could not be accessed from Emulator. Settings were changed, and can now access link, works perfectly now :D
I've been looking online for how to pass parameters to RESTlet webservice but it seem there are not much tutorial concerning RESTlet.
I would like to send some parameters gathered from a form on my android application (it would be great if i could do this using JSON).
well i solved this
as for the server side
#Post
public JSONArray serverSideFunction(Representation entity)
throws JSONException {
try {
JSONObject req = (new JsonRepresentation(entity)).getJsonObject();
System.out.println(req.getString(/* filed name */));
System.out.println(req.getString(/* filed name */));
/*
* you can retrieve all the fields here
* and make all necessary actions
*/
} catch (IOException e) {
e.printStackTrace();
}
}
as for the Android Side
HttpClient client = new DefaultHttpClient();
String responseBody;
JSONObject jsonObject = new JSONObject();
try{
HttpPost post = new HttpPost(WebService_URL);
jsonObject.put("field1", ".........");
jsonObject.put("field2", ".........");
StringEntity se = new StringEntity(jsonObject.toString());
post.setEntity(se);
post.setHeader(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
post.setHeader("Content-type", "application/json");
Log.e("webservice request","executing");
ResponseHandler responseHandler = new BasicResponseHandler();
responseBody = client.execute(post, responseHandler);
/*
* You can work here on your responseBody
* if it's a simple String or XML/JSON response
*/
}
catch (Exception e) {
e.printStackTrace();
}
I hope this may be of help
In fact, it depends on what you want to do. With REST (see http://en.wikipedia.org/wiki/Representational_state_transfer), there are two ways to pass parameters or data. Before you need to understand some concepts:
Resource: the REST entity by itself.
Representation: corresponds to its state and can be gotten or updated using different HTTP methods. The kind of content is identified using the content type header (media type in Restlet).
Methods: the GET method is used to get the resource state, PUT to update it, POST to create a new resource and specify its state the same time, DELETE to delete a resource.
Restlet provides Java entities for REST elements.
So, after described that, you can see that passing data or parameters depends of your use case:
1°) Do you want to update the resource state? In this case, you will use the content of the request with methods like POST or PUT. The data structure is free from text, JSON, XML or binary... Restlet provides the ClientResource class to execute requests on RESTful applications. It also provides support to build the representation to send and extract data from the one received. In this case, your data gathered from a form will be used to build the representation. Here are some samples:
//Samples for POST / PUT
ClientResource cr = new ClientResource("http://...");
cr.post(new StringRepresentation("test"));
MyBean bean = new MyBean();
(...)
//Jackson is a tool for JSON format
JacksonRepresentation<MyBean> repr
= new JacksonRepresentation<MyBean>(bean);
cr.put(repr);
//Samples for GET
Representation repr1 = cr.get();
bean = (new JacksonRepresentation<MyBean>(repr1, MyBean.class)).getObject();
2°) Do you want to specify parameters on your GET requests (for example to configure data to retreive and so on)? In this case, you can simply add it on the ClientResource, as described below:
ClientResource cr = new ClientResource("http://...");
cr.getReference().addQueryParameter("q", "restlet");
Representation repr = cr.get();
In this case, your data gathered from a form will be used to build the parameters.
Hope it helps you.
Thierry
If you want request with json structure and your response as JSONObject maybe you can do like this in server side:
public class RequestJSON extends ServerRecource{
#Post("json")
public JSONObject testRequest(String entity){
JSONObject request = new JSONObject(entity);
String value1 = request.getString("key1");
int value2 = request.getInt("key2");
return /* your JSONObject response */;
}
}
And your request can be :
{"key1":"value1", "key2":value2}
I hope this can help you
I am sending a JSON object to a HTTP Server by using the following code.
The main thing is that I have to send Boolean values also.
public void getServerData() throws JSONException, ClientProtocolException, IOException {
ArrayList<String> stringData = new ArrayList<String>();
DefaultHttpClient httpClient = new DefaultHttpClient();
ResponseHandler <String> resonseHandler = new BasicResponseHandler();
HttpPost postMethod = new HttpPost("http://consulting.for-the.biz/TicketMasterDev/TicketService.svc/SaveCustomer");
JSONObject json = new JSONObject();
json.put("AlertEmail",true);
json.put("APIKey","abc123456789");
json.put("Id",0);
json.put("Phone",number.getText().toString());
json.put("Name",name.getText().toString());
json.put("Email",email.getText().toString());
json.put("AlertPhone",false);
postMethod.setEntity(new ByteArrayEntity(json.toString().getBytes("UTF8")));
String response = httpClient.execute(postMethod,resonseHandler);
Log.e("response :", response);
}
but its showing the exception in the line
String response = httpClient.execute(postMethod,resonseHandler);
as
org.apache.http.client.HttpResponseException: Bad Request
can any one help me.
The Bad Request is the server saying that it doesn't like something in your POST.
The only obvious problem that I can see is that you're not telling the server that you're sending it JSON, so you may need to set a Content-Type header to indicate that the body is application/json:
postMethod.setHeader( "Content-Type", "application/json" );
If that doesn't work, you may need to look at the server logs to see why it doesn't like your POST.
If you don't have direct access to the server logs, then you need to liaise with the owner of the server to try and debug things. It could be that the format of your JSON is slightly wrong, there's a required field missing, or some other such problem.
If you can't get access use to the owner of the server, the you could try using a packet sniffer, such as WireShark, to capture packets both from your app, and from a successful POST and compare the two to try and work out what is different. This can be a little bit like finding a needle in a haystack though, particularly for large bodies.
If you can't get an example of a successful POST, then you're pretty well stuffed, as you have no point of reference.
This may be non-technical, but
String response = httpClient.execute(postMethod,-->resonseHandler);
There is a spelling mistake in variable name here, use responseHandler(defined above)