android JSON reader - IllegalStateException; expec

2020-06-25 05:19发布

问题:

I'm trying to use a Json Reader to parse through a .json file to insert records into my database but i'm having a problem reading through the file.

I intentionally opened the methods for parsing/reader with a try/catch clause so i can see what the error was coming from.

Here is the json Parser/Reader class:

package cybertech.productions.servicehelpers;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

import android.content.Context;

import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;

public class JsonParser {

    public void readCardJsonStream1(String cardSet, CarddbAdapter yugiohDB,
            Context context) throws IOException {

        URL test = new URL(cardSet);
        InputStream in = new BufferedInputStream(test.openStream());

        JsonReader reader = new JsonReader(new InputStreamReader(in,
                "ISO-8859-1"));

        String s, s1, s2, levelstr, rankstr, atkstr, defstr, setnumstr, cardpasstr;

        int numTotalElements = 0;
        int elementsParsed = 0;

        reader.beginObject();
        s = reader.nextName();

        reader.beginObject();
        while (reader.hasNext()) {

            s = reader.nextName();
            if (s.equalsIgnoreCase("p")) { // cards

                reader.beginObject();
                while (reader.hasNext()) {
                    s1 = reader.nextName();
                    if (s1.equalsIgnoreCase("o")) { // card
                        YugiohCard c;
                        reader.beginArray();
                        while (reader.hasNext()) {

                            reader.beginObject();
                            c = new YugiohCard();
                            while (reader.hasNext()) {
                                s2 = reader.nextName();
                                if (s2.equalsIgnoreCase("a")) { // name
                                    c.name = reader.nextString();
                                } else if (s2.equalsIgnoreCase("b")) { // type
                                    c.type = reader.nextString();
                                } else if (s2.equalsIgnoreCase("c")) { // attribute_type
                                    c.attributeType = reader.nextString();
                                } else if (s2.equalsIgnoreCase("d")) { // summon_requirements
                                    c.summonRequirements = reader.nextString();
                                } else if (s2.equalsIgnoreCase("e")) { // description
                                    c.description = reader.nextString();
                                } else if (s2.equalsIgnoreCase("f")) { // spell
                                                                        // speed
                                    c.spellSpeed = reader.nextString();

                                } else if (s2.equalsIgnoreCase("g")) { // level_stars
                                    levelstr = reader.nextString();
                                    c.levelStars = Integer.parseInt(levelstr);
                                } else if (s2.equalsIgnoreCase("h")) { // rank_stars
                                    rankstr = reader.nextString();
                                    c.rankStars = Integer.parseInt(rankstr);
                                } else if (s2.equalsIgnoreCase("i")) { // atk_points
                                    atkstr = reader.nextString();
                                    c.atk_stat = Integer.parseInt(atkstr);
                                } else if (s2.equalsIgnoreCase("j")) { // def_points
                                    defstr = reader.nextString();
                                    c.def_stat = Integer.parseInt(defstr);
                                } else if (s2.equalsIgnoreCase("n")) { // set
                                                                        // initials
                                    c.setinit = reader.nextString();
                                } else if (s2.equalsIgnoreCase("k")) { // set_number
                                    setnumstr = reader.nextString();
                                    c.setNumber = Integer.parseInt(setnumstr);
                                } else if (s2.equalsIgnoreCase("l")) { // card_number_pass
                                    cardpasstr = reader.nextString();
                                    c.cardnumberPass = Integer
                                            .parseInt(cardpasstr);
                                }
                            }
                            yugiohDB.createDBCard(c);
                            reader.endObject();
                        }
                        reader.endArray();
                    }
                }
                reader.endObject();
            }
            if (s.equalsIgnoreCase("w")) { // num_cards
                numTotalElements = reader.nextInt();
            }
        }
        reader.endObject();
        reader.close();
    }
}

This is my Json file:

{
    "t": {
        "p": {
            "o": [
                {
                    "a": "Elemental HERO Absolute Zero",
                    "b": "Monster/Fusion/Effect",
                    "c": "WATER",
                    "d": "1 'HERO' monster + 1 WATER monster",
                    "e": "Blows up your field, sucks for you",
                    "f": "NULL",
                    "g": "8",
                    "h": "0",
                    "i": "2500",
                    "j": "2000",
                    "n": "YG04",
                    "k": "001",
                    "l": "40854197"
                },
                {
                    "a": "Elemental HERO Air Neos",
                    "b": "Monster/Fusion/Effect",
                    "c": "WIND",
                    "d": "Hummingbird + Neos",
                    "e": "Returns to extra at end phase",
                    "f": "NULL",
                    "g": "7",
                    "h": "0",
                    "i": "2500",
                    "j": "2000",
                    "n": "STON",
                    "k": "034",
                    "l": "11502550"
                },
                {
                    "a": "Cyber Jar",
                    "b": "Monster/Effect",
                    "c": "DARK",
                    "d": "NULL",
                    "e": "destroys all monsters on the field",
                    "f": "NULL",
                    "g": "3",
                    "h": "0",
                    "i": "900",
                    "j": "900",
                    "n": "MRL",
                    "k": "077",
                    "l": "34124316"
                },
                {
                    "a": "Wind-Up Carrier Zenmaity",
                    "b": "MACHINE/Xyz/Effect",
                    "c": "WATER",
                    "d": "2 Level 3 monsters",
                    "e": "Special summon a wind-up from your hand or deck.",
                    "f": "NULL",
                    "g": "0",
                    "h": "3",
                    "i": "1500",
                    "j": "1500",
                    "n": "ORCS",
                    "k": "044",
                    "l": "81122844"
                },
                {
                    "a": "BRAIN CONTROL",
                    "b": "Spell",
                    "c": "Spell",
                    "d": "NULL",
                    "e": "Pay 800 Life Points to target 1 face-up monster your opponent controls; take control of that target until the End Phase.",
                    "f": "Normal",
                    "g": "0",
                    "h": "0",
                    "i": "0",
                    "j": "0",
                    "n": "LCYW",
                    "k": "074",
                    "l": "87910978"
                },
                {
                    "a": "Ring of Destruction",
                    "b": "Trap",
                    "c": "Trap",
                    "d": "NULL",
                    "e": "Target 1 face-up monster on the field; destroy that target, and if you do, inflict damage to both players equal to that target's ATK.",
                    "f": "Normal",
                    "g": "0",
                    "h": "0",
                    "i": "0",
                    "j": "0",
                    "n": "YG04",
                    "k": "001",
                    "l": "40854197"
                }
            ]
        },
        "v": "2/3/2013"
    }
}

Here is a method i created to tell where the json file is located on my site:

public void CreateYUGIsets() throws MalformedURLException, IOException{
        yugiohDB.dropDB();
        JsonParser parser = new JsonParser();
        String cardSetList = "https://sites.google.com/site/yugiohlibrary/patches/test.json";
        parser.readCardJsonStream1(cardSetList, yugiohDB, this);
    }

Here is the Logcat error i'm getting too:

05-15 22:48:49.362: E/AndroidRuntime(476): FATAL EXCEPTION: main
05-15 22:48:49.362: E/AndroidRuntime(476): java.lang.RuntimeException: Unable to start activity ComponentInfo{cybertech.productions.yugiohlibrary/cybertech.productions.yugiohlibrary.LoadingScreen}: java.lang.IllegalStateException: Expected a name but was STRING
05-15 22:48:49.362: E/AndroidRuntime(476):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
05-15 22:48:49.362: E/AndroidRuntime(476):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
05-15 22:48:49.362: E/AndroidRuntime(476):  at android.app.ActivityThread.access$1500(ActivityThread.java:117)
05-15 22:48:49.362: E/AndroidRuntime(476):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
05-15 22:48:49.362: E/AndroidRuntime(476):  at android.os.Handler.dispatchMessage(Handler.java:99)
05-15 22:48:49.362: E/AndroidRuntime(476):  at android.os.Looper.loop(Looper.java:123)
05-15 22:48:49.362: E/AndroidRuntime(476):  at android.app.ActivityThread.main(ActivityThread.java:3683)
05-15 22:48:49.362: E/AndroidRuntime(476):  at java.lang.reflect.Method.invokeNative(Native Method)
05-15 22:48:49.362: E/AndroidRuntime(476):  at java.lang.reflect.Method.invoke(Method.java:507)
05-15 22:48:49.362: E/AndroidRuntime(476):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
05-15 22:48:49.362: E/AndroidRuntime(476):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
05-15 22:48:49.362: E/AndroidRuntime(476):  at dalvik.system.NativeStart.main(Native Method)
05-15 22:48:49.362: E/AndroidRuntime(476): Caused by: java.lang.IllegalStateException: Expected a name but was STRING
05-15 22:48:49.362: E/AndroidRuntime(476):  at com.google.gson.stream.JsonReader.nextName(JsonReader.java:444)
05-15 22:48:49.362: E/AndroidRuntime(476):  at cybertech.productions.servicehelpers.JsonParser.readCardJsonStream1(JsonParser.java:36)
05-15 22:48:49.362: E/AndroidRuntime(476):  at cybertech.productions.yugiohlibrary.LoadingScreen.CreateYUGIsets(LoadingScreen.java:107)
05-15 22:48:49.362: E/AndroidRuntime(476):  at cybertech.productions.yugiohlibrary.LoadingScreen.onCreate(LoadingScreen.java:41)
05-15 22:48:49.362: E/AndroidRuntime(476):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
05-15 22:48:49.362: E/AndroidRuntime(476):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
05-15 22:48:49.362: E/AndroidRuntime(476):  ... 11 more

For this specific line in the logcat: cybertech.productions.servicehelpers.JsonParser.readCardJsonStream1(JsonParser.java:36) 05-15 22:48:49.362: E/AndroidRuntime(476)

Line 36 in the JsonParser class is: s = reader.nextName();

That line is right after when the first while() loop starts.

Any help would be appreciated.

回答1:

You have chosen the most tedious method to parse your JSON file. The library you're using (Gson) provides much easier ways to process the input. Here is an example that still does manual parsing:

// Your JSON data here
final String json = "";

// Get the array element corresponding to t->p->o, in the data
final JsonElement rootElem = new JsonParser().parse(json);
final JsonArray jsonArr = rootElem.getAsJsonObject()
        .getAsJsonObject("t").getAsJsonObject("p").getAsJsonArray("o");

// Iterate through the JSON array, extracting out card info as we go
final List<Yugioh> cards = new ArrayList<Yugioh>(jsonArr.size());
for (final JsonElement objElem : jsonArr) {
    final JsonObject jsonObj = objElem.getAsJsonObject();
    final Yugioh card = new Yugioh();

    card.setName(jsonObj.get("a").getAsString());
    card.setType(jsonObj.get("b").getAsString());
    card.setAttributeType(jsonObj.get("c").getAsString());
    card.setSummonRequirements(jsonObj.get("d").getAsString());
    card.setDescription(jsonObj.get("e").getAsString());
    card.setSpellSpeed(jsonObj.get("f").getAsString());
    card.setLevelStars(Integer.parseInt(jsonObj.get("g").getAsString()));
    card.setRankStars(Integer.parseInt(jsonObj.get("h").getAsString()));
    card.setAtkStat(Integer.parseInt(jsonObj.get("i").getAsString()));
    card.setDefStat(Integer.parseInt(jsonObj.get("j").getAsString()));
    card.setNumber(Integer.parseInt(jsonObj.get("k").getAsString()));
    card.setCardNumberPass(Integer.parseInt(jsonObj.get("l")
            .getAsString()));
    card.setInit(jsonObj.get("n").getAsString());

    System.out.println(card);
    cards.add(card);
}

Notice how much more readable the code is. I took the liberty of illustrating proper use of getter/setters, and fixed up some of the variable names. You can shorten the example above even further, by indicating in your mapper class, the serialized names of the JSON attributes that you are copying from. Case in point, with this mapper class:

class Yugioh implements Serializable {
    private static final long serialVersionUID = -8125568453376399843L;

    @SerializedName("a")
    private String name;

    @SerializedName("b")
    private String type;

    @SerializedName("c")
    private String attributeType;

    @SerializedName("d")
    private String summonRequirements;

    @SerializedName("e")
    private String description;

    @SerializedName("f")
    private String spellSpeed;

    @SerializedName("g")
    private Integer levelStars;

    @SerializedName("h")
    private Integer rankStars;

    @SerializedName("i")
    private Integer atkStat;

    @SerializedName("j")
    private Integer defStat;

    @SerializedName("k")
    private Integer number;

    @SerializedName("l")
    private Integer cardNumberPass;

    @SerializedName("n")
    private String init;

    public Yugioh() {
        super();
    }

    // Getters/Setters here

    @Override
    public String toString() {
        return String.format("Card %s", getName());
    }
}

You can shorten up the deserialization code significantly:

// Your JSON data here
final String json = "";

// Deserialize JSON into a bunch of objects
final JsonElement rootElem = new JsonParser().parse(json);
final JsonArray jsonArr = rootElem.getAsJsonObject()
        .getAsJsonObject("t").getAsJsonObject("p").getAsJsonArray("o");
final List<Yugioh> cards = new Gson().fromJson(jsonArr,
        new TypeToken<List<Yugioh>>() {
        }.getType());

System.out.println(cards);

Dead simple. Make sure to read the Gson User Guide - it provides a ton of useful information on utilizing the library.