简体   繁体   中英

Jackson SAX parser throws exception when parsing huge JSON

I'm trying to implement JSON array iterator with Jackson SAX parser (please, don't ask why). My app should work with huge files (up to 5 MiB), and that's a problem.

That's how I initialize JsonParser and call iterator creation. I create InputStream initialized with JSON placed in \\raw folder.

private JsonArrayIterator getIterator(String needle) throws IOException
    {
        InputStream inputStream = getApplicationContext().getResources().openRawResource(R.raw.products);
        inputStream.mark(-1);

        try {
        JsonParser jsonParser = createJsonParser(inputStream);

        // Some unrelated code

        return new JsonArrayIterator(jsonParser);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        inputStream.close();
    }

        return null;
    }

And here is my iterator class.

private Object parseNextObject() throws IOException {
        // I'm not using ObjectMapper because of reasons
        HashMap nextObject = new HashMap();

        int objectsCount = 1;

        while (objectsCount > 0) {
            JsonToken currentToken = currentParser.nextValue();

            if(currentToken == JsonToken.START_OBJECT) {
                ++objectsCount;
            }
            else if(currentToken == JsonToken.END_OBJECT) {
                --objectsCount;
            }
            else if(currentToken == JsonToken.START_ARRAY) {
                String currentName = currentParser.getCurrentName();
                ArrayList list = new ArrayList(100);
                JsonArrayIterator it = new JsonArrayIterator(currentParser);

                while (it.hasNext()) {
                    list.add(it.next());
                }

                nextObject.put(currentName, list);
            }
            else {
                // Here exception is throwed
                nextObject.put(currentParser.getCurrentName(), currentParser.getText());
            }
        }

        currentParser.nextToken();  // Skip END_OBJECT
        return nextObject;
    }

It seem to work perfe... OH, WAIT.

I have 3 sections (named arrays) in some huge file. It successfully parses first (a tiny one, under 1000 bytes). But I can't parse next.

Next array has nested array with simple objects (like this):

{
        "properties":[
            {
                "id":"1",
                "title":"\u0426\u0432\u0435\u0442",
                "values":[
                    {
                        "id":"1_2",
                        "title":"\u0427\u0435\u0440\u043d\u044b\u0439"
                    },
                    {
                        "id":"1_5005",
                        "title":"\u0417\u0435\u043b\u0435\u043d\u044b\u0439"
                    },
                    {
                        "id":"1_5006",
                        "title":"\u0421\u0435\u0440\u044b\u0439"
                    }
                ]
            }
        ]
    }

For one object in values I call nextObject.put. currentParser.getCurrentName() is runs successfully and returns correct string, but currentParser.getText() fails. It's not a JSON problem: it perfectly being mapped on iOS. It's not an object or iterator creation problem: I can delete that where parser throws exception, but it will fail in the same place.

Here is stack trace:

05-15 21:57:28.617: ERROR/AndroidRuntime(14758): FATAL EXCEPTION: main
    java.lang.NullPointerException: asset
    at android.content.res.AssetManager.readAsset(Native Method)
    at android.content.res.AssetManager.access$700(AssetManager.java:36)
    at android.content.res.AssetManager$AssetInputStream.read(AssetManager.java:576)
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.loadMore(UTF8StreamJsonParser.java:174)
    at com.fasterxml.jackson.core.base.ParserBase.loadMoreGuaranteed(ParserBase.java:425)
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._finishString2(UTF8StreamJsonParser.java:1930)
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._finishString(UTF8StreamJsonParser.java:1911)
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.getText(UTF8StreamJsonParser.java:276)
    at ru.studiomobile.JsonArrayIterator.parseNextObject(JsonArrayIterator.java:57)
    at ru.studiomobile.JsonArrayIterator.next(JsonArrayIterator.java:73)
    at ru.studiomobile.JsonArrayIterator.parseNextObject(JsonArrayIterator.java:47)
    at ru.studiomobile.JsonArrayIterator.next(JsonArrayIterator.java:73)
    at ru.studiomobile.MainActivity$2.onClick(MainActivity.java:81)
    at android.view.View.performClick(View.java:3127)
    at android.view.View$PerformClick.run(View.java:12025)
    at android.os.Handler.handleCallback(Handler.java:587)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:132)
    at android.app.ActivityThread.main(ActivityThread.java:4126)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
    at dalvik.system.NativeStart.main(Native Method)

I noticed that there are something called Utf8StreamJsonParser. It has a field named _inputEnd equal 4000 (why 4000?). When other field, _inputPtr, become bigger it throw an exception. How do I can handle it? I tried to use BufferedInputStream with predefined block size instead of InputStream but it had no effect.

Update

Info about some lines

47: list.add(it.next());  
    73: return parseNextObject();  
    75: e.printStackTrace();

Nothing special.

这是一个明显的问题:我忘了在创建解析器之后关闭流...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM