0

I've got a json file that looks like this

{
  "races": [
    {
      "name"  : "ORC"
    },
    {
      "name"  : "HUMAN"
    },
    {
      "name"  : "ELF"
    }
  ],
  "npc": [
    {
      "race"  : "HUMAN",
      "age"   : "25",
      "name"  : "Jerome"
    },
    {
      "race"  : "ORC",
      "age"   : "26",
      "name"  : "Rz'Ul"
    }
  ]
}

I want to retrieve the data from races or npc separately on demand. I am using genson to parse JSON. I parse it like this

@SuppressWarnings("unchecked")
public static <T> List<T> readJsonList(String listName) {
    Genson genson = JsonContext.PARSER.getParser();
    List<T> result = null;
    try (InputStream is = JsonDataProcessor.class.getResourceAsStream(FILE)) {
        ObjectReader reader = genson.createReader(is);
        reader.beginObject();
        while (reader.hasNext()) {
            reader.next();

            if ("races".equals(listName) && "races".equals(reader.name())) {
                result = (List<T>) processRaceData(reader);
                break;
            }

            if ("npc".equals(listName) && "npc".equals(reader.name())) {
                result = (List<T>) processNpcData(reader);
                break;
            }

        }
        reader.endObject();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return result;
}

And for example the method to parse races looks like this

private static List<Race> processRaceData(ObjectReader reader) {
    List<Race> raceList = new ArrayList<>();
    reader.beginArray();
    while (reader.hasNext()) {
        reader.next();

        Race race = new Race();
        reader.beginObject();
        while (reader.hasNext()) {
            reader.next();

            if ("name".equals(reader.name())) { race.setName(reader.valueAsString()); }
            else { reader.skipValue(); }
        }
        reader.endObject();
        raceList.add(race);
    }
    reader.endArray();
    return raceList;
}

In debug it populates variable result just fine, but on endObject line I get exception

Exception in thread "main" com.owlike.genson.stream.JsonStreamException: Illegal character at row 11 and column 4 expected } but read ',' !
        at com.owlike.genson.stream.JsonReader.newWrongTokenException(JsonReader.java:942)
        at com.owlike.genson.stream.JsonReader.end(JsonReader.java:428)
        at com.owlike.genson.stream.JsonReader.endObject(JsonReader.java:177)
        at com.lapots.breed.platform.json.JsonDataProcessor.readJsonList(JsonDataProcessor.java:41)
        at com.lapots.breed.platform.Example.prepareDb(Example.java:18)
        at com.lapots.breed.platform.Example.main(Example.java:23)

What is the problem?

lapots
  • 12,553
  • 32
  • 121
  • 242
  • Where do the JsonContext + JsonDataProcessor classes come from? – hammerfest Jul 11 '17 at 10:49
  • @hammerfest `JsonContext` is an enum that returns instance of `Genson` while `JsonDataProcessor` is the class that contains the method from the code in the question. – lapots Jul 11 '17 at 12:52

2 Answers2

2

I played with your code and found that genson is expecting to close object and check } symbol when you call endObject. You just need to skip object with reader.skipValue(). So error is in your while block in readJsonList method. This piece of code should work good for you:

 @SuppressWarnings("unchecked")
 public static <T> List<T> readJsonList(String listName) {
 . . .
 while (reader.hasNext()) {
     reader.next();
     if ("races".equals(listName) && "races".equals(reader.name())) {
         result = result = (List<T>) processRaceData(reader);
         break;
     }
     if ("npc".equals(listName) && "npc".equals(reader.name())) {
         result = result = (List<T>) processNpcData(reader);
         break;
     }
     reader = reader.skipValue();
 }
 reader.endObject();
 . . .
rxn1d
  • 1,236
  • 6
  • 18
  • Well it works by only for single entry `races`. It ends loop after the first iteration. I guess I should investigate `genson` more. – lapots Jul 11 '17 at 12:53
  • @user1432980 I thought that this is what you want. You cannot have several `races` entries in the same hierarchy level in JSON. It would be not valid JSON file. Didn't I answered you question? – rxn1d Jul 11 '17 at 13:27
  • Yup indeed, I had some issues with `process` methods so it populated data only for `race` entry and not for others, as I fixed it it successfully processed json as expected. – lapots Jul 11 '17 at 13:48
0

Why don't you use the data-binding capabilities of Genson and let it do the skipValue and mapping for you? You could define two data structures, one for races and another one for npc and then deserialize to them like this:

class Races {
  public List<Race> races;
}

class Npcs {
  public List<Npc> npc;
}

// This will skip npc and all the fields in it
Races races = genson.deserialize(inputStream, Races.class);

This remains pretty efficient and less error prone than writing the deserialization using the low level streaming API.

eugen
  • 5,856
  • 2
  • 29
  • 26