1

I am parsing a large JSONArray (33000 items approximately) of JSON objects. I am converting the JSON objects into my own objects in my app. It looks a bit like the following:

Card card = Card.build(cardObj.getString("name"))
                .setFoo(cardObj.getString("foo"))
                .setBar(cardObj.getInt("bar"))
                .setBaz(cardObj.getString("baz"))
                ... about 10 more

The Problem is that all of the cards (in the raw JSON) do not have the same keys. Because of this, I would have to have a try catch block for every single line of code in my parser, because any exception would have to be handled before the code can continue executing. For example, as in the snippet above, if I were parsing an object that didn't have bar, then the code will immediately jump to the exception handling, skipping the step where it sets the baz value.

My Question: Is there a way of doing this where I can avoid try-catching every single line? I know that you can't ignore exceptions, but perhaps there is something similar that may help.

A Better Example

try {
    Card card = Card.build(cardObj.getString("name"))
                    .setFoo(cardObj.getString("foo"))
                    .setBar(cardObj.getInt("bar"))
                    .setBaz(cardObj.getString("baz"))
} catch (JSONException e) {
    // The code will jump here for any exception. 
}

If the code fails while setting foo or bar, the execution context will jump to the error handling step inside of the catch block. The function calls following the offending line will never run, therefore bar or baz may never be set, even if they exist in the original JSON. I can see no way to prevent this other than try-catching every single line or by checking to make sure every single value exists beforehand. Is there no better way of doing this?

3
  • So you can't just put a try-catch block around the whole thing? Or use the throws keyword? Commented Jun 24, 2017 at 20:24
  • No, because the executing context will simply 'skip' the rest of the lines and jump straight to handling the exception. Commented Jun 24, 2017 at 20:26
  • Please post a minimal reproducible example. Commented Jun 24, 2017 at 20:27

4 Answers 4

2

If your JSON library has a way of handling default values I strongly suggest to use it and pass null or whatever is good-enough as default value.

The method might look something like jsonObject.getString(String key, String defaultValue).


But if your JSON library does not provide you with way to use default values you can wrap each getXXX() call in method which takes care about handling exceptions like this:

String getOrDefault(JSONObject obj, String key, String defValue) {
     try {
         String value = obj.getString(key);
         return value;
     }
     catch (Exception ex) {
         return defValue;
     }
}

// similary create functions for all data types.

And then at builder part use:

Card card = Card.build(getOrDefault(cardObj, "name", null))
                    ... about 10 more
Sign up to request clarification or add additional context in comments.

4 Comments

Ahhh very clever. Ill definitely try it if no one can think of a better way other than 'use library x and your problems disappear'
@Campbell I also mentioned the way of using default value method overload. Many JSON libraries I worked with had this feature.
@Campbell This is the overload you are looking for if you are using javax.json.JsonObject docs.oracle.com/javaee/7/api/javax/json/…
Yes that's perfect, I don't know why I didn't look at the docs beforehand. Ill accept your post as the answer. Thanks for replying so quickly.
0

This is not exactly the solution to your problem, but anyway why are you bothering so much about parsing the JSON by writing hundred lines of codes when there are some beautiful libraries like Gson?

Its pretty easy to use this library and all you have to do is writing a POJO class in which your JSON will be parsed into.

And yes, if some JSON key is not present in your JSON schema, you don't have to worry about that too. Gson handles this case too. For example, let me take a POJO class like this.

public class Parsed {
    public String name;
    public String foo;
    public Integer bar;
    public String baz;
}

So now, if in your JSON, the foo key is not available, then it'll assigned to null while parsing your JSON with Gson. So from your code just check if the value is null while assigning it to some other variable. That's it.

2 Comments

I'm using Volley for android. It natively uses JSONObjects and JSONArrays.
So this is where you can get some help - kylewbanks.com/blog/…
0

Just check if your JSONObject contains object (of correct type) before you do getSomething. JSONObject implements Map - https://docs.oracle.com/javaee/7/api/javax/json/JsonObject.html

Also, JsonArray implements List<JsonValue> https://docs.oracle.com/javaee/7/api/javax/json/JsonArray.html

For example, before calling cardObj.getString("foo") call cardObj.containsKey("foo"). Then you may consider checking value type:

JsonValue value=cardObj.get("foo");
if (value.getValueType()=!JsonValue.ValueType.STRING) {
 //do something reasonable for invalid type. 
}

You may consider using library working at higher level of abstraction. Working with Jackson, it will do nothing for non-existing json tags (matching fields in Card object will remain null).

When using Jackson, deserializing is matter of calling

Card card=new ObjectMapper().readValue("jsonString",Card.class);

Comments

0

I see two options here.

  1. Validate cardObj before creating Card which may require lots of boring code to write.
  2. Relax Card object creation - allow to create it with invalid data and then validate by implementing getValidationErrors method which would return collection of errors with details which field failed which reason. JSR303 annotations and validator would fit here as well.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.