How to add input to parsing exceptions in json4s? - json

Suppose I am parsing JSON with json4s.
val jv = org.json4s.native.JsonMethods.parse(json) // json is any JsonInput
The parse may raise exceptions. Unfortunately those exceptions don't contain the input (json) and sometimes I cannot understand and reproduce them.
I can wrap the parse with a wrapper (see below) but it doesn't work
try org.json4s.native.JsonMethods.parse(json) catch {
case e: Exception => throw new MyParseException(json, e)
}
Now what if json is an InputStream ? Should I read the stream ? What if the JSON is very large ? I probably don't need the whole stream. I need just the part of it up to the character where the parse failed.
How would you suggest add the input to the parsing exceptions ?

Related

Volley response JSON Exception: Unterminated array at character

I use Volley to get data from Xtream server.
It normally works, but when it sends certain requests, Volley returns an unterminated array which occurs a JSONException.
I had some investigation on it, and found that those cases are when the server returns relatively large amount of data, and that the response string emits some symbols such as comma, bracket etc.
try {
...
JSONArray array = new JSONArray(data);
...
} catch(JSONException e) {}
How can I pretreat the variable "data" so the above statement won't return any Exception?
Thank you for your reply in advance.

How to convert compact Json to pretty print codename one

I want to know how to convert a string of compact Json to pretty print so that I can parse it. I have searched for this question in stack overflow but it doesn't seem like anyone has asked it for codename one.
Right now I have a string of compact Json but it can not be parsed. This is the code:
String JsonData = "{\"document\":{ \"type\":\"PLAIN_TEXT\", \"content\":\"Ask not what your country can do for you, ask what you can do for your country.\" },\"encodingType\":\"UTF8\"}";
JsonResponse = Rest.
post("https://language.googleapis.com/v1/documents:analyzeSyntax?key=[API KEY").
jsonContent().
body(JsonData).
getAsJsonMap();
String JsonString = (JsonResponse.getResponseData()).toString();
JSONParser parser = new JSONParser();
Map<String, Object> results = null;
try {
results = parser.parseJSON(new StringReader(JsonString));
} catch (IOException e) {
e.printStackTrace();
System.out.println("fail");
}
System.out.println("results "+results);
But when I run this code I get a bunch of these responses:
[EDT] 0:0:3,269 - Expected null for key value while parsing JSON token at row: 1 column: 5 buffer: e
and
java.lang.NumberFormatException: For input string: "ee0"
How should I convert my string of compact Json (JsonString) to pretty print so that I can parse it? Alternatively, is there a way to directly parse the response (JsonResponse)?
Thank You
You are printing out a map not a JSON string as the JSON data is already parsed. If you just want to look at the network protocol for debugging the best way to do that is open the Network Monitor in the simulator where you will see all HTTP requests and can copy out the response body JSON.
However you can still convert a Map back to JSON using:
Log.p("results " + JSONParser.mapToJson(results));
Notice you should use Log.p() and Log.e() to log strings/exceptions as that would work better on the devices.

How to parse "streamed" json objects with json4s?

I have a streaming source that produces many JSON objects without separators (or only whitespace in between). If I pass that to json4s parse function, it only produces AST for the first object.
As a workaround, I could parse it manually and either turn it into a JSON array by adding brackets and commas as appropriate or chunk it and call parse on each chunk.
However, this is a rather common format, so I'm sure the problem is already solved. I just cannot find the API for it in json4s documentation.
If you reading it from an InputStream, then use BufferedInputStream wrapper with mark(), read() and reset() calls to skip whitespace(s) between parse() call:
val in = new BufferedInputStream(new FileInputStream("/tmp/your.json"))
try {
var continue = true
in.mark(1)
do {
in.reset()
// <-- here should be call for parse
// skip white spaces or exit if EOF found
var b = 0
do {
in.mark(1)
b = in.read()
if (b < 0) continue = false
} while (Character.isWhitespace(b))
} while (continue)
} finally in.close()
EDIT: Today I have released 0.11.0 version of jsoniter-scala with new ability to parse streaming JSON values or JSON arrays w/o need to hold all values in memory.

Unable to return a json inside Future[JsValue] from a WebSocket in Play 2.4

I have implemented Play framework's WebSocket so as to perform server communication using a WebSocket instead of Http. I have created a function as WebSocket.using[JsValue]. My json response is stored inside a Future[JsValue] variable and I am trying to fetch and return the json value from within Future[JsValue] variable. However I have been unable to return the json data from the Future[JsValue] variable. When I tried creating the WebSocket function as WebSocket.using[Future[JsValue]], in this case I was unable to create a json FrameFormatter for it.
def socketTest = WebSocket.using[JsValue] { request =>
val in = Iteratee.ignore[JsValue]
val out = Enumerator[JsValue](
Json.toJson(futureJsonVariable)
).andThen(Enumerator.eof)
(in, out)
}
futureJsonVariable is a variable of type Future[JsValue] In the above code the error at runtime is No Json serializer found for type scala.concurrent.Future[play.api.libs.json.JsValue]. Try to implement an implicit Writes or Format for this type. How can I return a json using a WebSocket method in Scala ? How can it be achieved using an Actor class instance ? If anyone knows best available online tutorials for WebSocket in Play framework. Any help is appreciated.
Use tryAccept to return either the result of the future when it is redeemed, or an error:
def socketTest = WebSocket.tryAccept[JsValue] { request =>
futureJsonVariable.map { json =>
val in = Iteratee.ignore[JsValue]
val out = Enumerator(json).andThen(Enumerator.eof)
Right((in, out))
} recover {
case err => Left(InternalServerError(err.getMessage))
}
}
This is similar to using but returns a Future[Either[Result, (Iteratee[A, _], Enumerator[A])]]. The Either[Result, ...] allows you to handle the case where something unexpected occurs calculating the future value A by providing a play.api.mvc.Result in the Left branch. The corollary is that you need to also wrap the "happy path" (where nothing goes wrong) in Right, in this case the iteratee/enumerator tuple you'd ordinarily return from using.
You can do something similar with the tryAcceptWithActor function.

Jerkson JsonMappingException

I'm trying to serialize scala case class to JSON string using Jerkson like this:
case class Page(title: String, id: String, ls: List[(String, String, Int)])
val pageList = new mutable.ArrayBuffer[Page]()
val jsonString = Json.generate(pageList)
pageList is extremely large with several million Page objects.
The call fails with this exception:
Caused by: org.codehaus.jackson.map.JsonMappingException:
[no message for java.lang.ArrayIndexOutOfBoundsException]
You may want to consider using a Streaming solution. You can use one of the the Jackson Streaming APIs:
JsonGenerator jg = jsonFactory.createJsonGenerator(file, JsonEncoding.UTF8); // or Stream, Reader
or, you can use a TokenBuffer (which is considered best practice for some situations):
TokenBuffer buffer = new TokenBuffer();
// serialize object as JSON tokens (but don't serialize as JSON text!)
objectMapper.writeValue(buffer, myBean);
Details: Jackson Streaming Documentation
Given that you've got "several million" objects, I'm guessing you might be hitting the length limit of String. Try generating to an OutputStream, ie, Json.generate(pageList, out).