Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
255: Parsing and Generating JSON with Gson
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
Heroclass with three fields:String name,int strength, andString weapon. - Use the
@SerializedNameannotation so that thestrengthfield is saved as"str_stat"in the JSON. - Create a class
PartyManagerwith a methodsaveParty(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 aTypeTokento return aList<Hero>.
- Create a
- Testing your work:
In your
mainmethod, create a list of threeHeroobjects, save them toparty.json, then load them back into a new list and print them to the console to verify the data (and thestr_statmapping) survived the trip.
There are no comments for now.