runnerpaul
runnerpaul

Reputation: 7216

How do I read multiple JSON lines (line-delimited)?

I get the below json from a url:

{"bytes": 5043, "name": "a", "timestamp": "11-Apr-2017 12:11:51", "ds": "Lab1"}
{"bytes": 0, "name": "b", "timestamp": "11-Apr-2017 12:11:51", "ds": "Lab1"}
{"bytes": 11590, "name": "c", "timestamp": "11-Apr-2017 12:11:51", "ds": "Lab1"}

I want to return the bytes for each line. Using Jackson I've tried parsing it as follows(note: json is saved to file for testing):

package JsonRead;

import java.io.File;
import java.io.IOException;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonTreeModelLogStorage {
    public static void main(String[] args) {

        try{

            ObjectMapper mapper = new ObjectMapper();

            JsonNode root = mapper.readTree(new File("JsonRead/json2.json"));

            JsonNode logStorageNode = root;

            for(JsonNode node : logStorageNode){
                String bytesUsed = node.path("bytes").asText();
                System.out.println("Bytes Used: " + bytesUsed);
            }

        } catch(IOException e){
                System.out.println("IO Exception " + e );
        }
    }
}

This returns the following:

Bytes Used: 
Bytes Used: 
Bytes Used: 
Bytes Used: 

If I then change my for loop to the following I can see I'm returning the first line of json:

for(JsonNode node : logStorageNode){
            String json = node.asText();
            System.out.println("json: " + a);
}

How do I real the bytes for all lines of json?

Upvotes: 2

Views: 9023

Answers (2)

runnerpaul
runnerpaul

Reputation: 7216

Thanks guys. That was a big help.

I edited the try slightly to suit my needs. Here's what I ended up with:

ObjectMapper mapper = new ObjectMapper();
    try(
            FileReader reader = new FileReader("JsonRead/json2.json");
            BufferedReader bufferedReader = new BufferedReader(reader);
        ) {
            String currentLine;
            while((currentLine=bufferedReader.readLine()) != null) {
                Vault vlt = mapper.readValue(currentLine, Vault.class);
                System.out.println(vlt.getBytes());
            } 
        }

Upvotes: 6

Aaron
Aaron

Reputation: 24812

The content you posted isn't valid JSON: the JSON spec doesn't allow multiple objects side by side like this.

If you encounter such text (it can't be considered JSON), you will want to split it over a delimiter so that each substring is a valid JSON object which you will be able to parse.
In your case, it seems that linefeed is a valid delimiter, but you should make sure that your JSON objects will never contain any linefeed. If that's the case, you can parse your text as follows :

try(
    FileReader reader = new FileReader("JsonRead/json2.json");
    BufferedReader bufferedReader = new BufferedReader(reader);
) {
    String currentLine;
    while((currentLine=bufferedReader.readLine()) != null) {
        JsonNode logStorageNode = mapper.readTree(currentLine);
        // [...] carry on with your current code.
    }
}

I first assumed you were receiving an array instead :

[
    {"bytes": 5043, "name": "a", "timestamp": "11-Apr-2017 12:11:51", "ds": "Lab1"},
    {"bytes": 0, "name": "b", "timestamp": "11-Apr-2017 12:11:51", "ds": "Lab1"},
    {"bytes": 11590, "name": "c", "timestamp": "11-Apr-2017 12:11:51", "ds": "Lab1"}
]

In that case, you should loop on its content :

JsonNode root = mapper.readTree(new File("JsonRead/json2.json"));

if (!root.isArray()) {
    throw WhateverException("A JSON Array is expected");
}

// a cast to ArrayNode would be possible, but isn't necessary
// as per the design of jackson's JsonNode
Iterator<JsonNode> it = root.iterator();

while (it.hasNext()) {
    JsonNode logStorageNode = it.next();

    // [...] carry on with your current code.
}

Upvotes: 3

Related Questions