Why Does Gson Fromjson Throw a Jsonsyntaxexception: Expected Begin_Object But Was Begin_Array

Why does Gson fromJson throw a JsonSyntaxException: Expected BEGIN_OBJECT but was BEGIN_ARRAY?

As the exception message states

Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 16 path $.nestedPojo

while deserializing, Gson was expecting a JSON object, but found a JSON array. Since it couldn't convert from one to the other, it threw this exception.

The JSON format is described here. In short, it defines the following types: objects, arrays, strings, numbers, null, and the boolean values true and false.

In Gson (and most JSON parsers), the following mappings exist: a JSON string maps to a Java String; a JSON number maps to a Java Number type; a JSON array maps to a Collection type or an array type; a JSON object maps to a Java Map type or, typically, a custom POJO type (not mentioned previously); null maps to Java's null, and the boolean values map to Java's true and false.

Gson iterates through the JSON content that you provide and tries to deserialize it to the corresponding type you've requested. If the content doesn't match or can't be converted to the expected type, it'll throw a corresponding exception.

In your case, you provided the following JSON

{
"nestedPojo": [
{
"name": null,
"value": 42
}
]
}

At the root, this is a JSON object which contains a member named nestedPojo which is a JSON array. That JSON array contains a single element, another JSON object with two members. Considering the mappings defined earlier, you'd expect this JSON to map to a Java object which has a field named nestedPojo of some Collection or array type, where that types defines two fields named name and value, respectively.

However, you've defined your Pojo type as having a field

NestedPojo nestedPojo;

that is neither an array type, nor a Collection type. Gson can't deserialize the corresponding JSON for this field.

Instead, you have 3 options:

  • Change your JSON to match the expected type

    {
    "nestedPojo": {
    "name": null,
    "value": 42
    }
    }
  • Change your Pojo type to expect a Collection or array type

    List<NestedPojo> nestedPojo; // consider changing the name and using @SerializedName
    NestedPojo[] nestedPojo;
  • Write and register a custom deserializer for NestedPojo with your own parsing rules. For example

    class Custom implements JsonDeserializer<NestedPojo> {
    @Override
    public NestedPojo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
    NestedPojo nestedPojo = new NestedPojo();
    JsonArray jsonArray = json.getAsJsonArray();
    if (jsonArray.size() != 1) {
    throw new IllegalStateException("unexpected json");
    }
    JsonObject jsonObject = jsonArray.get(0).getAsJsonObject(); // get only element
    JsonElement jsonElement = jsonObject.get("name");
    if (!jsonElement.isJsonNull()) {
    nestedPojo.name = jsonElement.getAsString();
    }
    nestedPojo.value = jsonObject.get("value").getAsInt();
    return nestedPojo;
    }
    }

    Gson gson = new GsonBuilder().registerTypeAdapter(NestedPojo.class, new Custom()).create();

GSON throwing Expected BEGIN_OBJECT but was BEGIN_ARRAY?

The problem is you're telling Gson you have an object of your type. You don't. You have an array of objects of your type. You can't just try and cast the result like that and expect it to magically work ;)

The User guide for Gson Explains how to deal with this:

https://github.com/google/gson/blob/master/UserGuide.md

This will work:

ChannelSearchEnum[] enums = gson.fromJson(yourJson, ChannelSearchEnum[].class);

But this is better:

Type collectionType = new TypeToken<Collection<ChannelSearchEnum>>(){}.getType();
Collection<ChannelSearchEnum> enums = gson.fromJson(yourJson, collectionType);

Gson issue:- Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1

Use the second case, but replace

private SubTasks subTasks ;

with

private List<SubTasks> subTasks ;

The clue was in the error.

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 276 path $.subTasks

Given your java classes, it was expecting an object named subTasks but found an array.

So change it to an array and you are gold.

The first case is probably correct, if you end up parsing an array of SMTStatus

gson.fromJson Expected BEGIN_OBJECT but was BEGIN_ARRAY because of how the object is stored

I just added [ ] before and after my JSON object in the exec sql statement + took the advice of the comment above and it works..for now
the code became thus:

db.execSQL("insert into favorites (obj) values ('["+g.toJson(items.get(getAdapterPosition()),Hotel.class).toString()+"]') ;");

//and when retrieved:

Gson gson = new Gson();
Type hotelListType = new TypeToken<ArrayList<Hotel>>(){}.getType();
ArrayList<Hotel> h = gson.fromJson(json, hotelListType );

this works

gson.fromJson Expected BEGIN_OBJECT but was BEGIN_ARRAY

Looks like the JSON string (rankJSON) is an array of JSON documents not a single JSON document.

If you log that JSON you'll see that it starts with [ e.g.

[
{
...
}
]

You are attempting to deserialize it into a single RankAPI, you should instead deserialize it into a List<RankAPI>, for example;

List<RankAPI> r = gson.fromJson(rankJSON, new TypeToken<ArrayList<RankAPI>>(){}.getType());

Here's a test case to verify this behaviour:

@Test
public void twoWayTransform() {
Gson gson = new GsonBuilder().serializeNulls().create();

List<RankAPI> incomings = Arrays.asList(new RankAPI(), new RankAPI());

String json = gson.toJson(incomings);

// use TypeToken to inform Gson about the type of the elements in the generic list
List<RankAPI> fromJson = gson.fromJson(json, new TypeToken<ArrayList<RankAPI>>(){}.getType());

assertEquals(2, fromJson.size());
for (RankAPI incoming : incomings) {
// this will pass if RankAPI has an equals() method
assertTrue(fromJson.contains(incoming));
}
}

OkHttp / Retrofit / Gson: Expected BEGIN_OBJECT but was BEGIN_ARRAY

Error: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $

As the error clearly says, you are trying to parse JSONArray into a JSONObject

@GET("characters/house/{house}")
Call<Data> getPersonajes(@Path("house") String house);

This service method expecting JSONObject, but according the logcat shared by in the image, the response is giving JSONArray. Instead you should parse it as:

@GET("characters/house/{house}")
Call<List<Personaje>> getPersonajes(@Path("house") String house)

GSON throwing “Expected BEGIN_OBJECT but was BEGIN_ARRAY”

Your input is not valid Json. It should look like this:

{
"1": {
"Butter": [
{
"x": 16.23,
"y": 21.11
},
{
"x": 18.18,
"y": 26.67
}
]
},
"2": {
"Butter": [
{
"x": 41.98,
"y": 47.62
}
]
}
}

JsonSyntaxException Expected BEGIN_OBJECT but was BEGIN_ARRAY at path

Instead of jsonObject.get("rows"), use the below syndax

jsonObject.getAsJsonArray("rows")

Java gson error: Expected BEGIN_OBJECT but was BEGIN_ARRAY (but my type map is correct?)

That's because GroupedTotals isn't a list, it is an object that contains a list.

Valid json that would convert into an instance of that class would look like

{
"BSRecvDestDNSName": [
...
]
}

Alternately, you could obtain the Type for a list and convert directly to it. For instance, using your original json, this code:

Type type = new TypeToken<List<Map<String, Float>>>() {}.getType();
List<Map<String, Float>> myList = gson.fromJson(output, type);
System.out.println("myList='"+myList+"'");

Outputs

myList='[{aws.amazon.com=426788.0}, {atsv2-fp.wg1.b.yahoo.com=141154.0}, {e2svi.x.incapdns.net=140445.0}, {stackoverflow.com=87624.0}, {a-sg03sl05.insnw.net=56665.0}]'



Related Topics



Leave a reply



Submit