String object vs. string literal in OutputStreamWriter in Java - java

I'm making requests to a HTTP server sending JSON string. I used Gson for serializing and deserializing JSON objects. Today I observed this pretty weird behavior that I don't understand.
I have:
String jsonAsString = gson.toJson(jsonAsObject).replace("\"", "\\\"");
System.out.println(jsonAsString);
That outputs exactly this:
{\"content\":\"Literal\",\"pos\":{\"left\":20,\"top\":20}}
Now I'm using OutputStreamWriter obtained from HttpURLConnection to make HTTP, PUT request with JSON payload. The foregoing request works fine:
os.write("{\"content\":\"Literal\",\"pos\":{\"left\":20,\"top\":20}}");
However, when I say:
os.write(jsonAsString);
...the request doesn't work (this server doesn't return any errors but I can see that when writing JSON as string object it doesn't do what it should). Is there a difference when using string literal over string object. Am I doing something wrong?
Here is the snippet:
public static void EditWidget(SurfaceWidget sw, String widgetId) {
Gson gson = new Gson();
String jsonWidget = gson.toJson(sw).replace("\"", "\\\"");
System.out.println(jsonWidget);
try {
HttpURLConnection hurl = getConnectionObject("PUT", "http://fltspc.itu.dk/widget/5162b1a0f835c1585e00009e/");
hurl.connect();
OutputStreamWriter os = new OutputStreamWriter(hurl.getOutputStream());
//os.write("{\"content\":\"Literal\",\"pos\":{\"left\":20,\"top\":20}}");
os.write(jsonWidget);
os.flush();
os.close();
System.out.println(hurl.getResponseCode());
} catch (IOException e) {
e.printStackTrace();
}
}

Remove the .replace("\"", "\\\"") instruction. It's unnecessary.
You're forced to add slashes before double quotes when you send a JSON String literal because in a Java String literal, double quotes must be escaped (otherwise, they would mark the end of the String instead of being a double quote inside the String).
But the actual String, in the bytecode, doesn't contain these backslashes. They're only used in the source code.

Related

How escape string works in ObjectMapper of jackson

I want to generate JSON string from given string but with single backslash character before single quote character like this \'. For example I have string "you are the 'great'" and want output like this "you are the \'great\'". I am using jackson object mapper class and following is the code:
String str = "you are the 'great'";
String jsonStr = "";
System.out.println(str);//Line-1
ObjectMapper mapper = new ObjectMapper();
try
{
jsonStr = mapper.writeValueAsString(str);
}
catch (IOException e)
{
e.printStackTrace();
}
System.out.println(jsonStr);//Line-2
So based on that I have performed following testcases:
Input string: "you are the \'great\'"
Output of Line-1: you are the 'great'
Output of Line-2: you are the 'great'
Input string: "you are the \\'great\\'"
Output of Line-1: you are the \'great\'
Output of Line-2: you are the \\'great\\'
But I am not able to get the expected output. Please provide some solution.
Note: Here to explain you the problem I have taken string as a input but actually I have some string properties in object and want Json string of that object.

Unable to split json response?

This is my method
public String buildJsonData(String username , String message)
{
JsonObject jsonObject = Json.createObjectBuilder().add("Username",username+":"+message).build();
StringWriter stringWriter = new StringWriter();
try(JsonWriter jsonWriter = Json.createWriter(stringWriter))
{
jsonWriter.write(jsonObject);
}
catch(Exception e)
{
System.out.print("buildJsonData ="+e);
}
return stringWriter.toString();
}
If i input username as john and message as hello.I get output as
{"Username":"john:hello"}
But I want output without braces and doublequotes I want my output as
John:hello
I tried to split it using array[0] but didn't get the output.Is it possible in json to get my desired output(without braces and quotes).
On the sending end, you would put the Username and Message entities into a JSONObject and send the resulting string over the network.
On the receiving end, you would unmarshal the JSON to extract the entities. You can then format them however you like.
Please read about JSON encoding here.
This is a simple example:
private String getResponse(){
JSONObject json = new JSONObject();
try {
json.put("Username", "John");
json.put("Message", "Hellow");
} catch (JSONException e) {
e.printStackTrace();
}
return json.toString();
}
private void receiver(){
try {
JSONObject response = new JSONObject(getResponse());
String username = response.getString("Username");
String message = response.getString("Message");
System.out.println(String.format("%s : %s", username,message));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Your structure is not really JSON.
A json structure would be like
{
Username : "John",
Message : "Hello"
}
Anf if your want to really use JSON, there is not way to remove braces and quotes. This IS Json.
If you want to output only the part you quoted, store the json value in a variable
String myoutput = stringWriter.toString();
And then remove the parts you don't want with replace() or a regexp
Braces are part of the JSON notation - they indicate an object. If you remove them, then it's not JSON any more. Same goes for double quotes.You are creating your JSON object as:
Json.createObjectBuilder().add("Username",username+":"+message)
This creates an object with property named Username and value john:hello. Again, this is the JSON notation. It's not intended to be read directly, but to facilitate data transfer between applications (on the same or different devices).
If all you want to create is john:message, then instead of creating a JSON object, you should simply do:
String result = username + ":" + message;
return result;

Formatting Web Service Response

I use the below function to retrieve the web service response:
private String getSoapResponse (String url, String host, String encoding, String soapAction, String soapRequest) throws MalformedURLException, IOException, Exception {
URL wsUrl = new URL(url);
URLConnection connection = wsUrl.openConnection();
HttpURLConnection httpConn = (HttpURLConnection)connection;
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buffer = new byte[soapRequest.length()];
buffer = soapRequest.getBytes();
bout.write(buffer);
byte[] b = bout.toByteArray();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Host", host);
if (encoding == null || encoding == "")
encoding = UTF8;
httpConn.setRequestProperty("Content-Type", "text/xml; charset=" + encoding);
httpConn.setRequestProperty("Content-Length", String.valueOf(b.length));
httpConn.setRequestProperty("SOAPAction", soapAction);
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
OutputStream out = httpConn.getOutputStream();
out.write(b);
out.close();
InputStreamReader is = new InputStreamReader(httpConn.getInputStream());
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(is);
String read = br.readLine();
while(read != null) {
sb.append(read);
read = br.readLine();
}
String response = decodeHtmlEntityCharacters(sb.toString());
return response = decodeHtmlEntityCharacters(response);
}
But my problem with this code is it returns lots of special characters and makes the structure of the XML invalid.
Example response:
<PLANT>A565</PLANT>
<PLANT>A567</PLANT>
<PLANT>A585</PLANT>
<PLANT>A921</PLANT>
<PLANT>A938</PLANT>
</PLANT_GROUP>
</KPI_PLANT_GROUP_KEYWORD>
<MSU_CUSTOMERS/>
</DU>
<DU>
So to solve this, I use the below method and pass the whole response to replace all the special characters with its corresponding punctuation.
private final static Hashtable htmlEntitiesTable = new Hashtable();
static {
htmlEntitiesTable.put("&","&");
htmlEntitiesTable.put(""","\"");
htmlEntitiesTable.put("<","<");
htmlEntitiesTable.put(">",">");
}
private String decodeHtmlEntityCharacters(String inputString) throws Exception {
Enumeration en = htmlEntitiesTable.keys();
while(en.hasMoreElements()){
String key = (String)en.nextElement();
String val = (String)htmlEntitiesTable.get(key);
inputString = inputString.replaceAll(key, val);
}
return inputString;
}
But another problem arised. If the response contains this segment <VALUE>< 0.5 </VALUE< and if this will be evaluated by the method, the output would be:
<VALUE>< 0.5</VALUE>
Which makes the structure of the XML invalid again.
The data is correct and valid "< 0.5" but having it within the VALUE elements causes issue on the structure of the XML.
Can you please help how to deal with this? Maybe the way I get or build the response can be improved. Is there any better way to call and get the response from web service?
How can I deal with elements containing "<" or ">"?
Do you know how to use a third-party open source library?
You should try using apache commons-lang:
StringEscapeUtils.unescapeXml(xml)
More detail is provided in the following stack overflow post:
how to unescape XML in java
Documentation:
http://commons.apache.org/proper/commons-lang/javadocs/api-release/index.html
http://commons.apache.org/proper/commons-lang/userguide.html#lang3.
You're using SOAP wrong.
In particular, you do not need the following line of code:
String response = decodeHtmlEntityCharacters(sb.toString());
Just return sb.toString(). And for $DEITY's sake, do not use string methods to parse the retrieved string, use an XML parser, or a full-blown SOAP stack...
Does the > or < character always appear at the beginning of a value? Then you could use regex to handle the cases in which the > or < are followed by a digit (or dot, for that matter).
Sample code, assuming the replacement strings used in it don't appear anywhere else in the XML:
private String decodeHtmlEntityCharacters(String inputString) throws Exception {
Enumeration en = htmlEntitiesTable.keys();
// Replaces > or < followed by dot or digit (while keeping the dot/digit)
inputString = inputString.replaceAll(">(\\.?\\d)", "Valuegreaterthan$1");
inputString = inputString.replaceAll("<(\\.?\\d)", "Valuelesserthan$1");
while(en.hasMoreElements()){
String key = (String)en.nextElement();
String val = (String)htmlEntitiesTable.get(key);
inputString = inputString.replaceAll(key, val);
}
inputString = inputString.replaceAll("Valuelesserthan", "<");
inputString = inputString.replaceAll("Valuegreaterthan", ">");
return inputString;
}
Note the most appropriate answer (and easier for everyone) would be to correctly encode the XML at the sender side (it would also render my solution non-working BTW).
It would be hard to cope with all the situations but you could cover the most common ones by adding a few more rules by assuming that any less than followed by a space is data, and a greater than that has a space in front of it is data and need to be encoded again.
private final static Hashtable htmlEntitiesTable = new Hashtable();
static {
htmlEntitiesTable.put("&","&");
htmlEntitiesTable.put(""","\"");
htmlEntitiesTable.put("<","<");
htmlEntitiesTable.put(">",">");
}
private String decodeHtmlEntityCharacters(String inputString) throws Exception {
Enumeration en = htmlEntitiesTable.keys();
while(en.hasMoreElements()){
String key = (String)en.nextElement();
String val = (String)htmlEntitiesTable.get(key);
inputString = inputString.replaceAll(key, val);
}
inputString = inputString.replaceAll("< ","< ");
inputString = inputString.replaceAll(" >"," >");
return inputString;
}
'>' is not escaped in XML. So you shouldn't have an issue with that. Regarding '<', here are the options I can think of.
Use CDATA in web response for text containing special characters.
Rewrite the text by reversing the order. For eg. if it is x < 2, change it to 2 > x. '>' is not escaped unless its a part of CDATA.
Use another attribute or element in the XML response to indicate '<' or '>'.
Use regular expression to find a sequence that starts with '<' and followed by a string, and followed by '<' of the closing tag. And replace it with some code or some value that you can interpret and replace later.
Also, you don't need to do this:
String response = decodeHtmlEntityCharacters(sb.toString());
You should be able to parse the XML after you take care of the '<' sign in text.
You can use this site for testing regular expressions.
Why not serialize your xml?, its much easier than what you are doing.
for an example:
var ser = new XmlSerializer(typeof(MyXMLObject));
using (var reader = XmlReader.Create("http.....xml"))
{
MyXMLObject _myobj = (response)ser.Deserialize(reader);
}

How to fix encoding while reading json response in android?

I am calling an API which returns a JSON response. While reading the JSON response there are some places where data has some special characters. I want to exclude these special characters while reading the response in an object. The JSON response looks like this:
{"data":[{"title":"PSY - GANGNAM STYLE (\uac15\ub0a8\uc2a4\ud0c0\uc77c) M\/V","content":All rights reserved."}]}
The Java code is this:
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "ISO-8859-1"), 8);
When I read the title key from the response, it gives me these special characters as well which I don't want. How do get rid of those? Do i need to specify some other encoding?
Data Source :http://pipes.yahoo.com/pipes/pipe.run?_id=920adeb2e95c15877e29dc678aa78dd7&_render=json&n=1
This isn't an encoding issue (like UTF-8), it's a JavaScript syntax issue. The "\uac15", for example, is JavaScript syntax that represents the Unicode character U+AC15, which is "강". Together, those escaped characters are the name of the song written in Hangul (Korean): "강남스타일".
It's normal and OK for your Java string to contain the backslash escape sequences. When you run that string though a JSON reader, you should get a JSON object containing the actual Hangul characters.
In response to your comment about getting wrong output from a JSON reader, that depends on what JSON library you're using (and how you're using it), which you didn't specify in the question. Here's an example that works for me using Jackson 2.1.0:
public final class JsonTest {
public static void main(final String[] args) {
final String json = "\"PSY - GANGNAM STYLE (\\uac15\\ub0a8\\uc2a4\\ud0c0\\uc77c) M\\/V\"";
System.out.println("JSON: " + json);
try {
// ObjectMapper is from Jackson 2.1 databind library.
final ObjectMapper mapper = new ObjectMapper();
final String decoded = mapper.readValue(json, String.class);
System.out.println("Decoded: " + decoded);
}
catch (final IOException e) {
e.printStackTrace();
}
}
}

Sending Non-latin query string in URL in JavaME

I want to make am HTTP GET request from my J2ME application using HttpConnection class.
The problem is that I cannot send russian text in the query string.
Here is the example of how I'm sending the request
c = (HttpConnection)Connector.open("http://127.0.0.1:1418/zp.ashx?тест");
InputStream s = c.openInputStream();
The receiving asp.net script receives the query part of the url as %3f%3f%3f%3f
That is 4 identical codes. Definately that's not what I'm sending
So how can I send non-latin text in an http query in J2ME?
Thank you in advance
Your code
Connector.open("http://127.0.0.1:1418/zp.ashx?тест");
is processed by a java.nio.CharsetDecoder for the ASCII character set, and this decoder replaces all unknown characters with its replacement.
To get the behavior you want, you have to encode the URL before sending it. For example, when your server expects the URLs to be UTF8-encoded:
String encodedParameter = URLEncoder.encode("тест", "UTF-8");
Connector.open("http://127.0.0.1:1418/zp.ashx?" + encodedParameter);
Note that if you have multiple parameters, you have to encode both the parameter names and the parameter values individually, before putting them together with "=" and concatenating them with "&". If you need to encode multiple parameters, this class may be helpful to you:
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class UrlParamGenerator {
private final String encoding;
private final StringBuilder sb = new StringBuilder();
private String separator = "?";
public UrlParamGenerator(String charset) {
this.encoding = charset;
}
public void add(String key, String value) throws UnsupportedEncodingException {
sb.append(separator);
sb.append(URLEncoder.encode(key, encoding));
sb.append("=");
sb.append(URLEncoder.encode(value, encoding));
separator = "&";
}
#Override
public String toString() {
return sb.toString();
}
public static void main(String[] args) throws UnsupportedEncodingException {
UrlParamGenerator gen = new UrlParamGenerator("UTF-8");
gen.add("test", "\u0442\u0435\u0441\u0442");
gen.add("x", "0");
System.out.println(gen.toString());
}
}
You might need to explicitly set a character set in the HTTP header that supports the cyrillic alphabet. You could either use UTF-8 or another charset, such as windows-1251 (although UTF-8 should be the preferred choice).
c.setRequestProperty("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
c = (HttpConnection)Connector.open("http://127.0.0.1:1418/zp.ashx?тест");
If you use an appropriate charset, the server should be able to properly handle the cyrillic request parameter - provided it too supports this charset.
URL can contain only ASCII chars and a few punctuation chars. For other chars, you must %-encode them before adding them in the URL. Use URLEncoder.encode("тест", enc) where the enc parameter is the encoding scheme that the server expects.

Categories