JSON.simple is a small Java library that reads and writes JSON with two classes, JSONObject (a HashMap) and JSONArray (an ArrayList), plus JSONParser for parsing. It has no dependencies, but its last release, 1.1.1, dates from March 2012, so new projects use Jackson or Gson instead.
We still meet JSON.simple in older codebases, in small tools and in coding exercises, so it helps to know how it works and where it fails. This guide shows the json-simple code for writing and reading JSON, and the same tasks with Jackson and Gson for migration.
The following example builds a song as JSON with json-simple 1.1.1 and parses it back.
JSONObject song = new JSONObject();
song.put("title", "Yesterday");
song.put("seconds", 125);
String json = song.toJSONString(); // {"seconds":125,"title":"Yesterday"}
JSONObject parsed = (JSONObject) new JSONParser().parse(json);
String title = (String) parsed.get("title"); // "Yesterday"
long seconds = (Long) parsed.get("seconds"); // 125
Notice the casts on every get() call and that the number comes back as a Long, although we put in an int. We cover the library status first, followed by writing and reading files, the pitfalls that cause bugs in production, and the Jackson and Gson versions of the same code.
1. Is JSON.simple Still Maintained?
The json-simple project (com.googlecode.json-simple:json-simple) released version 1.1.1 in 2012, and Maven Central has no newer version. The library still compiles and runs on Java 25, because it uses only basic JDK classes, but it gets no fixes for bugs or security issues. For example, toJSONString() calls itself for each nesting level, so deeply nested data ends in a StackOverflowError.
A second library with a similar name, Clifton Labs json-simple (com.github.cliftonlabs:json-simple), is a rewrite with a different API, namely Jsoner, JsonObject and JsonArray. Code written for one does not compile with the other.

| Library | Latest version | Typed binding to classes | Pretty printing | Streaming API |
|---|---|---|---|---|
| JSON.simple | 1.1.1 (2012) | No | No | Limited (ContentHandler) |
| Jackson | 2.22.3 (2.x), 3.2.3 (3.x) | Yes, including records | Yes | Yes |
| Gson | 2.14.0 | Yes, including records | Yes | Yes |
| Jakarta JSON Processing | API 2.1.3, Parsson 1.1.9 | Through Jakarta JSON Binding | Yes | Yes |
Use Jackson or Gson for new code, and keep JSON.simple only where replacing it costs more than it saves. Spring Boot already ships Jackson, so in a Spring Boot application the switch adds no dependency.
2. JSON.simple Features
The design of JSON.simple is to reuse the Java collections. A JSON object is a Map, a JSON array is a List, and the values are String, Long, Double, Boolean or null.
- It encodes and decodes JSON following RFC 4627, the JSON specification of 2006.
- It has no external dependencies, and the jar is about 23 KB.
- The JSONObject and JSONArray classes extend HashMap and ArrayList as raw types, so the code needs casts and gets unchecked warnings.
- It can write JSON to any Writer with writeJSONString().
- It has no mapping to Java classes, no annotations and no pretty printing.
3. Maven Dependency
Version 1.1.1 of the original library declares JUnit 4.10 as a compile dependency by mistake, so we exclude it to keep JUnit off the runtime classpath.
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
4. Write JSON to a File
To write JSON, we fill a JSONObject with put() and a JSONArray with add(), nest them as needed, and write the result. The writeJSONString(Writer) method writes to the stream, so the JSON text is not built as one big String first.
The following example writes a playlist with two songs to playlist.json. Each song is an object, and the playlist holds the songs in an array.
@SuppressWarnings("unchecked")
static JSONObject song(String title, String artist, int seconds) {
JSONObject song = new JSONObject();
song.put("title", title);
song.put("artist", artist);
song.put("seconds", seconds);
return song;
}
JSONArray songs = new JSONArray();
songs.add(song("Bohemian Rhapsody", "Queen", 354));
songs.add(song("Yesterday", "The Beatles", 125));
JSONObject playlist = new JSONObject();
playlist.put("name", "Road trip");
playlist.put("songs", songs);
try (Writer out = Files.newBufferedWriter(Path.of("playlist.json"))) {
playlist.writeJSONString(out);
}
long size = Files.size(Path.of("playlist.json")); // 150 bytes, written on one line
The file content has no line breaks or indentation, and the keys appear in HashMap order, not in the order of the put() calls.
{"songs":[{"seconds":354,"artist":"Queen","title":"Bohemian Rhapsody"},{"seconds":125,"artist":"The Beatles","title":"Yesterday"}],"name":"Road trip"}
5. Read JSON from a File
To read JSON, we create a JSONParser and pass it a Reader. The parse() method returns Object, which is a JSONObject, JSONArray, String, Number, Boolean or null depending on the JSON, so we cast to the type we expect.
JSONObject root;
try (Reader in = Files.newBufferedReader(Path.of("playlist.json"))) {
root = (JSONObject) new JSONParser().parse(in);
}
String name = (String) root.get("name"); // "Road trip"
JSONArray list = (JSONArray) root.get("songs");
int count = list.size(); // 2
JSONObject first = (JSONObject) list.get(0);
String artist = (String) first.get("artist"); // "Queen"
long length = (Long) first.get("seconds"); // 354
Object missing = first.get("album"); // null
A missing key returns null, the same as a key with a JSON null value, so containsKey() is the only way to tell the two apart. Invalid JSON makes parse() throw org.json.simple.parser.ParseException, which reports the position of the problem.
String error;
try {
new JSONParser().parse("{\"title\": }");
error = "valid";
} catch (ParseException e) {
error = e.getClass().getSimpleName() + ": " + e;
}
String message = error; // "ParseException: Unexpected token RIGHT BRACE(}) at position 10."
6. Pitfalls of JSON.simple
Most bugs with JSON.simple come from its loose typing. The compiler accepts any value in put() and any cast after get(), so the errors show up at runtime.
6.1. Numbers Are Long or Double
The parser returns every whole number as Long and every decimal number as Double. Casting to Integer throws ClassCastException, which is a frequent json-simple question on Stack Overflow.
JSONObject track = (JSONObject) new JSONParser().parse("{\"seconds\":125,\"rating\":4.5}");
Integer wrong = (Integer) track.get("seconds"); // ClassCastException: class java.lang.Long cannot be cast to class java.lang.Integer
int seconds = ((Number) track.get("seconds")).intValue(); // 125
double rating = ((Number) track.get("rating")).doubleValue(); // 4.5
Casting to Number and calling intValue() or doubleValue() works for both Long and Double values.
6.2. Unknown Objects Produce Invalid JSON
When a value is not a type that JSON.simple knows, toJSONString() writes its toString() output without quotes. A Java record, a LocalDate or an enum ends up as broken JSON that other parsers reject.
record Album(String name) {}
JSONObject bad = new JSONObject();
bad.put("album", new Album("Help!"));
String invalid = bad.toJSONString(); // {"album":Album[name=Help!]}
6.3. Silent Failures and Escaped Slashes
The shortcut JSONValue.parse() returns null for invalid input instead of throwing an exception, so a corrupt file looks like an empty one. The writer also escapes every forward slash, which is valid JSON but makes URLs harder to read in logs.
Object nothing = JSONValue.parse("[1, 2"); // null, no exception
String url = JSONValue.toJSONString("https://example.com/a"); // "https:\/\/example.com\/a"
7. Migrating from JSON.simple to Jackson or Gson
A music app stores user playlists as JSON files and reads them with JSON.simple. Every new field means more casts, and a ClassCastException from a Long broke the import once already. Binding the JSON to a typed record removes the casts and catches type errors in one place.
The following examples use the same playlist.json file and two records that describe its structure.
record Song(String title, String artist, int seconds) {}
record Playlist(String name, List<Song> songs) {}
7.1. Jackson
Jackson 2.22 maps JSON to records and classes with ObjectMapper. Jackson is also the default JSON library of Spring Boot, and Spring Boot 4 ships Jackson 3, which uses the new tools.jackson packages and JsonMapper, but the reading and writing calls stay the same.
ObjectMapper mapper = new ObjectMapper();
Playlist trip = mapper.readValue(Path.of("playlist.json").toFile(), Playlist.class);
String firstTitle = trip.songs().get(0).title(); // "Bohemian Rhapsody"
int total = trip.songs().stream().mapToInt(Song::seconds).sum(); // 479
String pretty = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(trip.songs().get(1));
List<String> prettyLines = pretty.lines().toList(); // [{, "title" : "Yesterday",, "artist" : "The Beatles",, "seconds" : 125, }]
When the structure is not known in advance, mapper.readTree() returns a JsonNode tree, which is the closest Jackson equivalent to a JSONObject and still has typed getters such as asInt().
JsonNode tree = new ObjectMapper().readTree(Path.of("playlist.json").toFile());
int secondsOfFirst = tree.get("songs").get(0).get("seconds").asInt(); // 354
7.2. Gson
Gson 2.14 does the same with a smaller API and no dependencies, which suits Android apps and small tools. Records are supported since Gson 2.10.
Gson gson = new GsonBuilder().create();
Playlist fromGson;
try (Reader in = Files.newBufferedReader(Path.of("playlist.json"))) {
fromGson = gson.fromJson(in, Playlist.class);
}
String lastArtist = fromGson.songs().get(1).artist(); // "The Beatles"
String compact = gson.toJson(new Song("Help!", "The Beatles", 139)); // {"title":"Help!","artist":"The Beatles","seconds":139}
The mapping from JSON.simple calls to Jackson and Gson is mostly one to one.
| Task | JSON.simple | Jackson | Gson |
|---|---|---|---|
| Parse to a tree | new JSONParser().parse(reader) | mapper.readTree(reader) | JsonParser.parseReader(reader) |
| Parse to a class | Not supported | mapper.readValue(reader, Song.class) | gson.fromJson(reader, Song.class) |
| Create an object | new JSONObject() | mapper.createObjectNode() | new JsonObject() |
| Write to a String | obj.toJSONString() | mapper.writeValueAsString(obj) | gson.toJson(obj) |
| Pretty print | Not supported | writerWithDefaultPrettyPrinter() | new GsonBuilder().setPrettyPrinting() |
For a deeper look at the replacement libraries, see converting JSON to a Map with Jackson and parsing JSON arrays with Gson.
8. JSON.simple FAQs
Finding JSON.simple in an old project raises two questions, whether it is safe to keep and how its output differs from other libraries.
8.1. Is JSON.simple deprecated?
JSON.simple is not formally deprecated, but it has had no release since 1.1.1 in 2012. It works on current Java versions, and for new code Jackson, Gson or Jakarta JSON Processing are the maintained choices.
8.2. Why are the keys in a different order than I added them?
JSONObject extends HashMap, which has no defined order. JSON objects are unordered by definition, so the output is valid, but if the order matters for people reading it, Jackson with a record or a LinkedHashMap keeps the declaration or insertion order.
8.3. How do I pretty print JSON with JSON.simple?
JSON.simple has no pretty printer. We parse the text with Jackson and write it with writerWithDefaultPrettyPrinter(), or use Gson with setPrettyPrinting(), as shown in pretty printing JSON with Gson.
8.4. How do I convert a JSONObject to a Java object?
JSON.simple cannot do it, so we copy the values field by field with casts. A better way is to pass obj.toJSONString() to Jackson’s readValue() or Gson’s fromJson() with the target class, or to replace the parsing step completely.
8.5. Can JSON.simple parse a JSON array at the top level?
Yes. The parse() method returns a JSONArray when the text starts with [, so we cast the result to JSONArray instead of JSONObject.
9. Conclusion
JSON.simple turns JSON into HashMap and ArrayList objects and back with very little code. The price is casts on every value, numbers that come back as Long or Double, random key order, no pretty printing and invalid output for unknown types.
The library has had no release since 2012, so it belongs in maintenance work only. Jackson and Gson read the same files into typed records, write them with pretty printing, and are maintained, which makes either of them the better choice for new code.
10. References
- JSON.simple on GitHub
- JSON.simple Google Code archive
- Jackson Databind
- Gson
- RFC 8259, The JSON Data Interchange Format
Happy Learning !!
I have followed exactly as you have mentioned in the article . but was getting errors. following is the code snippet
public class WriteJsonExample { @SuppressWarnings("unchecked") public static void main(String[] args) { //first employee JSONObject employeeDetails= new JSONObject(); employeeDetails.put("firstName", "Sonal"); employeeDetails.put("lastName", "Gupta"); employeeDetails.put("company","TCS"); JSONObject employeeObject= new JSONObject(); employeeObject.put("employee", employeeObject); //second employee JSONObject employeeDetails2 = new JSONObject(); employeeDetails2.put("firstName", "Harsh"); employeeDetails2.put("lastName", "Vardhhan"); employeeDetails2.put("company", "Infosys"); JSONObject employeeObject2= new JSONObject(); employeeObject2.put("employee", employeeObject2); //Add employees to list JSONArray employeeList= new JSONArray(); employeeList.add(employeeObject); employeeList.add(employeeObject2); //WriteJsonFile try(FileWriter file = new FileWriter("employees.json")){ file.write(employeeList.toJSONString()); file.flush(); }catch(IOException e){ e.printStackTrace(); } } }following are the error logs
Exception in thread “main” java.lang.StackOverflowError
at java.base/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:748)
at java.base/java.lang.StringBuffer.append(StringBuffer.java:424)
at org.json.simple.JSONValue.escape(JSONValue.java:266)
at org.json.simple.JSONObject.toJSONString(JSONObject.java:116)
at org.json.simple.JSONObject.toJSONString(JSONObject.java:101)
at org.json.simple.JSONObject.toJSONString(JSONObject.java:108)
…..
and similar long list of errors
Had to make some changes for it to compile, namely:
Object obj = jsonParser.parse(reader); JSONArray userList = new JSONArray(); userList.add(obj);instead of directly casting like shown in the example here
Object obj = jsonParser.parse(reader); JSONArray employeeList = (JSONArray) obj;Hi,
I followed the example above but the JSON wrote to file does not have indentations. Am I doing something wrong?
Thank you so much!
Hello,
How can I update just one entity value in json file?
For example,
I have a json file with all the data in it and
I have to a change “firstname”: “lokesh”
to some other value which is stored in a string.
How can I just write this value into my json file using java
Please help.
Thanks
Hi, how do I do this with a 500GB json file (wikidata)?
How can you parse a FileReader object? What is a FileReader object?
In comparison, I want to get a JSON file read in, then make it to string, then I know how to deal with it, but my parse method won’t take a FileReader.