retrofit MalformedJsonException - json

I am receiving a response from the server in JSON format.
val gson = Gson().newBuilder()
.setLenient()
.create()
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
the response contains characters \r, \n, " and I get an error "com.google.gson.stream.MalformedJsonException: Unterminated object at line"
please tell me how to process this JSON correctly
tried using Moshi but doesn't work either
.addConverterFactory(MoshiConverterFactory.create(moshi).asLenient())

Related

Gson Json conversion adding extra back slash

I am working on a service that has the following code (I can change this code):
import com.google.gson.JsonObject;
import com.google.gson.Gson;
Gson gson = new Gson();
JsonObject json = new JsonObject();
json.addProperty("customer", gson.toJson(customer));
anotherServiceClient.dispatch(json.toString());
AnotherService Class code has a dispatch method implementation that takes in a String object and adds it to a json where party is a String. I can't change this code.
JsonObject json = new JsonObject();
json.addProperty("party", inputCustomerJson);
I need the anotherService to have the output like:
"party": "{\"customer\":\"{\"id\":\"A123\"}"}
but instead it is :
"party": "{\"customer\":\"{\\\"id\\\":\\\"A123\\\"}"}
The problem is this line:
json.addProperty("customer", gson.toJson(customer));
Gson.toJson produces a JSON string as output ("{\"id\":\"A123\"}"), so when you then later serialize this data again as JSON the backslashes and double quotes are escaped.
Most likely you want to use Gson.toJsonTree and JsonObject.add(String, JsonElement):
json.add("customer", gson.toJsonTree(customer));

Gson - JsonObject with null values

I am a little confused about how Gson is parsing Strings to JSON.
At the very start, I initialize gson like this
val gson = Gson().newBuilder().serializeNulls().disableHtmlEscaping().create()
Next, I'm converting my map to a String:
val pushJson = gson.toJson(data) // data is of type Map<String,Any>
That gives the following output:
{
"name": null,
"uuid": "5a8e8202-6654-44d9-a452-310773da78c1",
"paymentCurrency": "EU"
}
At this point, the JSON string has null values. But in the following step:
val jsonObject = JsonParser.parseString(pushJson).asJsonObject
it hasn't!
{
"uuid": "5a8e8202-6654-44d9-a452-310773da78c1",
"paymentCurrency": "EU"
}
Nulls are omitted. How to get all null values in JsonObject like in JSON string:
{
"string-key": null,
"other-key": null
}
#Edit
Added some json's to help understand the issue.
After discussing with the OP it came out that the JSON object was then serialised by Retrofit to allow for an API call, using the following code:
return Retrofit.Builder()
.baseUrl("api/url")
.client(httpClient.build())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiInterface::class.java)
The issue here lays in the GsonConverterFactory: since no Gson object is passed to the create method, a new default Gson instance gets created under the hood, and by default it doesn't serialise null values.
The issue can be easily solved by passing the appropriate instance to the factory:
val gson = GsonBuilder().serializeNulls().create() // plus any other custom configuration
....
fun createRetrofit() = Retrofit.Builder()
.baseUrl("api/url")
.client(httpClient.build())
.addConverterFactory(GsonConverterFactory.create(gson)) // use the configured Gson instance
.build()
.create(ApiInterface::class.java)

GSON: converting a .json file to a JsonObject

Of course, for this i used JsonParser, Here is my Code:
JsonParser parser = new JsonParser();
Object object = parser.parse(new FileReader("c:\\Projects\\elastic-search-single-log-result.json"));
JsonObject jobject = (JsonObject) object;
String message = jobject.get("msg").toString();
return message;
However, the msg is a stack trace enclosed by triple quotes, and it gives me a Malformed Json Exception, at the second line shown above.
I saw stuff about JsonReader having a getLenientMethod, I was wondering if there was something similar for this.
I fixed it --- I simply had to remove the triple quotes, and I get the JSON file from kibana (which formatted the stack trace a little differently). I hope this helps anyone in the future who will have the same problem

JsonSlurper returns No signature of method: groovy.json.JsonSlurper.parseText() is applicable for argument types: (java.util.ArrayList)

I'm trying to parse JSON file with JsonSlurper.parseText but keep getting similar problems.
def jsonParse = null
def http = new HTTPBuilder(url)
http.auth.basic(username, password)
http.request(Method.GET) {
response.success = { resp, reader ->;
jsonParse = new JsonSlurper().parseText(reader)
}
}
Whenever I run my application the error message says
No signature of method: groovy.json.JsonSlurper.parseText() is applicable for argument types: (java.util.ArrayList)
I understand that JsonSlurper.parseText() is asking for a java.util.ArrayList type as an input. So I tried the following to figure out the type of the input using this code.
def jsonParse = null
def http = new HTTPBuilder(url)
http.auth.basic(username, password)
http.request(Method.GET) {
response.success = { resp, reader ->;
jsonParse = reader
}
}
render jsonParse.getClass()
This prints out the following:
class java.util.ArrayList
I don't understand why I'm getting this error when I am feeding the input with correct datatype.
Any suggestions?
According to the documentation, the HTTPBuilder could be parsing your JSON for you. If your JSON response has its root as a JSON array, then that explains the ArrayList object in your reader variable.
Regarding how this explains the exception being thrown. The reader parameter of the Closure is an ArrayList of parsed JSON, not a String of unparsed JSON. Thus, the code fails on new JsonSlurper().parseText(reader) because reader is not text and the JsonSlurper does not have a method defined for how to parse an ArrayList as JSON.

Receiving JSON in salesforce

I am trying to receive a JSON string in salesforce by converting a blob in the body of an Http request. However, when I convert the blob to a string there are \ characters that get inserted into the request which prevents me from parsing.
I then tried to take the string and remove all \ characters... that didn't work either.
RestRequest req = RestContext.request;
Blob jsonBlob = req.requestBody;
String jsonString = jsonBlob.toString();
return jsonString;
The original string (the one that is received as a blob) looks like this:
{"putTimeCard":{"timecard":{"timeCardID": "","employeeID": ""}}
And after converting to a salesforce string and assigned to the jsonString is altered to:
{\"putTimeCard\":{\"timecard\":{\"timeCardID\": \"\",\"employeeID\": \"\"}}
Has anyone found a solution for this?
Thanks
The JSON Deserializer can parse the string with the escape characters. You can either deserialize into an object like so:
String jsonString = '{\"putTimeCard\":{\"timecard\":{\"timeCardID\": \"\",\"employeeID\": \"\"}}}'
Timecard t = (Timecard) JSON.deserialize(jsonString, Type.forName('Timecard'));
or if you just want a map of objects you can do the following:
String jsonString = '{\"putTimeCard\":{\"timecard\":{\"timeCardID\": \"\",\"employeeID\": \"\"}}}'
Map<String, Object> m = (Map<String, Object>) JSON.deserializeUntyped(jsonString);