Skip to Content
Course content

255: Parsing and Generating JSON with Gson

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've spent way too many hours in my career fighting with manually concatenated strings to build JSON. It's a recipe for a syntax error that'll haunt your logs for a week. Today, I want to show you how I actually handle this in production using Gson. It's a library from Google that basically maps Java objects to JSON and back again without making you write a thousand lines of boilerplate.

Let's imagine we're building a small RPG. I've got a GameCharacter class. I want to be able to save the character's state to a file and load it back later. Here is my starting point:

public class GameCharacter {
    private String name;
    private int level;
    private List<String> inventory;

    // Constructor, getters, and setters omitted for brevity
    public GameCharacter(String name, int level, List<String> inventory) {
        this.name = name;
        this.level = level;
        this.inventory = inventory;
    }

    @Override
    public String toString() {
        return "Character: " + name + " (Lvl " + level + ") Items: " + inventory;
    }
}

Turning an Object into a String

The first thing I'll do is try the simplest approach. I'll instantiate a Gson object and call toJson(). Let's see what happens.

Gson gson = new Gson();
GameCharacter hero = new GameCharacter("Valerius", 12, Arrays.asList("Iron Sword", "Health Potion"));
String json = gson.toJson(hero);
System.out.println(json);

The output is: {"name":"Valerius","level":12,"inventory":["Iron Sword","Health Potion"]}.

It works, but it's a nightmare to read. If I'm debugging a save file, I don't want a single long line of text. I want it formatted. I'll swap out the default constructor for a GsonBuilder to enable "pretty printing."

Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(hero);
System.out.println(json);

Now we're talking. It's expanded into a readable block. Much better for my sanity during debugging.

When the JSON Doesn't Match the Java

Here is where things usually get messy. Let's say I'm consuming an API from another team, and they decided to name the field char_name instead of name. If I try to parse their JSON into my GameCharacter class, Gson won't find a match for name, and it'll just leave it as null.

I could rename my Java variable to char_name, but that violates Java naming conventions. I'm not doing that. Instead, I'll use the @SerializedName annotation. This tells Gson: "In Java, I call this name, but in the JSON world, it's called char_name."

public class GameCharacter {
    @SerializedName("char_name")
    private String name;
    
    private int level;
    private List<String> inventory;
    // ... rest of class
}

Now, when I call gson.fromJson(jsonString, GameCharacter.class), Gson sees the char_name key in the JSON and knows exactly where to put it in my object. It's a clean separation between my internal data model and the external data format.

The Generic List Headache

Now, let's try something a bit more complex. What if I have a List<GameCharacter>? I'll try to parse a JSON array of characters like this:

String jsonArray = "[{\"char_name\":\"Valerius\",\"level\":12}, {\"char_name\":\"Zelda\",\"level\":20}]";
List<GameCharacter> characters = gson.fromJson(jsonArray, List.class);

This compiles, but here's the trap: List.class is just a raw list. Because of Java's type erasure, Gson doesn't actually know what's inside the list at runtime. It defaults to creating a List<LinkedTreeMap>. The moment I try to do characters.get(0).getName(), I'll get a ClassCastException because a Map isn't a GameCharacter.

To fix this, I need a TypeToken. This is a slightly weird-looking piece of syntax, but it's the only way to preserve the generic type information for Gson.

Type characterListType = new TypeToken<ArrayList<GameCharacter>>(){}.getType();
List<GameCharacter> characters = gson.fromJson(jsonArray, characterListType);

By creating an anonymous inner class of TypeToken, we capture the full generic type ArrayList<GameCharacter>. Now Gson knows exactly which class to instantiate for every element in that array. It's a weird quirk of the language, but once you've hit the ClassCastException a few times, it becomes second nature.




📋 Practical Task

Building a Save-Game Persistence System for an RPG Inventory

Your goal is to create a small utility that saves and loads a party of adventurers to a JSON file. You must handle a naming mismatch and a generic collection.

  • The Requirements:
    • Create a Hero class with three fields: String name, int strength, and String weapon.
    • Use the @SerializedName annotation so that the strength field is saved as "str_stat" in the JSON.
    • Create a class PartyManager with a method saveParty(List<Hero> party, String filename) that writes the list to a file using "pretty printing".
    • Create a method loadParty(String filename) that reads the file and uses a TypeToken to return a List<Hero>.
  • Testing your work:

    In your main method, create a list of three Hero objects, save them to party.json, then load them back into a new list and print them to the console to verify the data (and the str_stat mapping) survived the trip.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.