I am using JsonReader to fetch lots of data from a website and saving to a db. Incidentally, whenever the reader doesnt find a value for an object item, it fails and stops executing.
This is the error i have;
System.err﹕ java.lang.IllegalStateException: Expected a string but was NULL at line 1 column 359337 path $[19].date
Even if the specified value is not available, it seems all objects loaded before the error was encountered are lost too and are not saved to the db. Is there a way to handle these errors and keep the objects that had been loaded so far? I have set JsonReader as lenient.
This is the part of the method that parses the data:
private Post read(JsonReader reader) throws Exception {
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
switch (name) {
case TITLE:
mTitle = new StringBuilder();
mTitle.append(reader.nextString());
break;
case AUTHOR:
if (reader.hasNext()) {
JsonToken peek = reader.peek();
if (peek == JsonToken.NULL) {
reader.skipValue();
} else {
reader.beginObject();
while (reader.hasNext()) {
String enclosedName = reader.nextName();
switch (enclosedName) {
case NAME:
mAuthor = new StringBuilder();
mAuthor.append(reader.nextString());
break;
case AVATAR:
mAvatar = new StringBuilder();
mAvatar.append(reader.nextString());
break;
default:
reader.skipValue();
break;
}
}
reader.endObject();
}
}
break;
case CONTENT:
mDescription = new StringBuilder();
mDescription.append(reader.nextString());
break;
case URL:
mEntryLink = new StringBuilder();
mEntryLink.append(reader.nextString());
break;
case DATE:
mDateStringBuilder = new StringBuilder();
mDateStringBuilder.append(reader.nextString());
break;
case GUID:
mGuid = new StringBuilder();
mGuid.append(reader.nextString());
break;
case FEATURED_IMAGE:
if (reader.hasNext()) {
JsonToken look = reader.peek();
if (look == JsonToken.NULL) {
reader.skipValue();
} else {
mFeaturedImage = new StringBuilder();
reader.beginObject();
while (reader.hasNext()) {
String itemToLookFor = reader.nextName();
switch (itemToLookFor) {
case SOURCE:
mFeaturedImage.append(reader.nextString());
break;
default:
reader.skipValue();
break;
}
}
reader.endObject();
}
}
break;
case TERMS:
if (reader.hasNext()) {
JsonToken check = reader.peek();
if (check == JsonToken.NULL) {
reader.skipValue();
} else {
reader.beginObject();
while (reader.hasNext()) {
String stuff = reader.nextName();
switch (stuff) {
case CATEGORIES:
reader.beginArray();
itemCategory = new StringBuilder();
while (reader.hasNext()) {
reader.beginObject();
while (reader.hasNext()) {
String item = reader.nextName();
switch (item) {
case NAME:
itemCategory.append(reader.nextString()).append(",");
break;
default:
reader.skipValue();
break;
}
}
reader.endObject();
}
reader.endArray();
break;
case TAGS:
reader.beginArray();
itemTags = new StringBuilder();
while (reader.hasNext()) {
reader.beginObject();
while (reader.hasNext()) {
String item = reader.nextName();
switch (item) {
case NAME:
itemTags.append(reader.nextString()).append(",");
break;
default:
reader.skipValue();
break;
}
}
reader.endObject();
}
reader.endArray();
break;
default:
reader.skipValue();
break;
}
}
reader.endObject();
}
}
break;
default:
reader.skipValue();
break;
}
}
reader.endObject();
return new Post(mAuthor.toString(), mAvatar.toString(), mDateStringBuilder.toString(), mTitle.toString(), mEntryLink.toString(), mDescription.toString(), mGuid.toString(), mFeaturedImage.toString(), itemTags.toString(), itemCategory.toString());
}
I thought may be you weren't checking for NULL
elements, that seems to be the case.
At one point you use:
JsonToken check = reader.peek();
if (check == JsonToken.NULL) {
That is correct. However, in other places you simply get the String
:
mDescription.append(reader.nextString());
In all places you are getting a String
, you need to check whether there is actually an unexpected type (such as NULL
). In cases like this, you need to apply appropriate error containment code.
Incidentally, you really don't need to be creating all of those StringBuilder
s. Since you are only putting one String
into it after each initialization. You would save a lot of time by simply using a String. If you intend to write all the contents to a StringBuilder
for each type, then you need to initialize them before you start looping.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With