This is part 7 of the Bleeding edge Java series. Start at the introduction if you haven’t already.
We now have the beginnings of a modern JSON serialization library. The full featured version of this library can be found on GitHub. Let’s summarize what we achieved together.
First, let’s make one last helper to simplify the usage of the library. We’ll create a high level API for our library that exposes methods that are easier to use.
public interface Json
{
String serializeToString(Object o);
void serializeToWriter(Object o, Writer writer);
<T> T deserialize(TypeToken<T> type, String json);
<T> T deserialize(Class<T> type, String json);
<T> T deserialize(TypeToken<T> type, Reader reader);
<T> T deserialize(Class<T> type, Reader reader);
}
The implementation for it is straightforward:
new Json() {
private final JsonPrinter printer = JsonPrinter.instance();
private final JsonParser parser = JsonParser.instance();
private final JsonDeserializer deserializer = JsonDeserializer.instance();
private final JsonSerializer serializer = JsonSerializer.instance();
@Override
public String serializeToString(Object o)
{
return serializer.serialize(o)
.map(printer::print)
.collect(Collectors.joining());
}
@Override
public void serializeToWriter(Object o, Writer writer)
{
serializer.serialize(o)
.map(printer::print)
.forEach(str -> {
try {
writer.append(str);
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
});
}
@Override
public <T> T deserialize(TypeToken<T> type, String json)
{
return deserialize(type.type(), json);
}
@Override
public <T> T deserialize(TypeToken<T> type, Reader reader)
{
return deserialize(type.type(), reader);
}
@Override
public <T> T deserialize(Class<T> type, String json)
{
return deserialize((Type) type, json);
}
@Override
public <T> T deserialize(Class<T> type, Reader reader)
{
return deserialize((Type) type, reader);
}
@SuppressWarnings("unchecked")
private <T> T deserialize(Type type, String json)
{
return (T) parser.parse(json.chars())
.collect(JsonDeserializerCollector.deserializing(deserializer, type));
}
@SuppressWarnings("unchecked")
private <T> T deserialize(Type type, Reader reader)
{
BufferedReader bufferedReader = new BufferedReader(reader);
return (T) parser.parse(bufferedReader.lines().flatMapToInt(String::chars))
.collect(JsonDeserializerCollector.deserializing(deserializer, type));
}
};
Test it out for yourself!
Let’s try the high-level API to serialize and deserialize in jshell. This example will use these files:
- TypeToken.java
- JsonToken.java
- JsonSerializer.java
- StringUtils.java
- JsonPrinter.java
- JsonParser.java
- JsonDeserializer.java
- JsonDeserializerCollector.java
- Json.java
From a terminal with Java 19 installed, run the following (note you’ll need the wget utility):
wget -nc https://raw.githubusercontent.com/starburstdata/developer-blog-assets/main/bleeding-edge-java/code/TypeToken.java
wget -nc https://raw.githubusercontent.com/starburstdata/developer-blog-assets/main/bleeding-edge-java/code/JsonToken.java
wget -nc https://raw.githubusercontent.com/starburstdata/developer-blog-assets/main/bleeding-edge-java/code/JsonSerializer.java
wget -nc https://raw.githubusercontent.com/starburstdata/developer-blog-assets/main/bleeding-edge-java/code/StringUtils.java
wget -nc https://raw.githubusercontent.com/starburstdata/developer-blog-assets/main/bleeding-edge-java/code/JsonPrinter.java
wget -nc https://raw.githubusercontent.com/starburstdata/developer-blog-assets/main/bleeding-edge-java/code/JsonParser.java
wget -nc https://raw.githubusercontent.com/starburstdata/developer-blog-assets/main/bleeding-edge-java/code/JsonDeserializer.java
wget -nc https://raw.githubusercontent.com/starburstdata/developer-blog-assets/main/bleeding-edge-java/code/JsonDeserializerCollector.java
wget -nc https://raw.githubusercontent.com/starburstdata/developer-blog-assets/main/bleeding-edge-java/code/Json.java
jshell --enable-preview TypeToken.java JsonToken.java JsonSerializer.java StringUtils.java JsonPrinter.java JsonParser.java JsonDeserializer.java JsonDeserializerCollector.java Json.java
Try the following example or create your own.
var json = Json.instance();
enum Suit { Diamonds, Clubs, Spades, Hearts };
record Value(String name, int value) {}
record Card(Value value, Suit suit) {}
TypeToken<List<Card>> typeToken = new TypeToken<>() {};
List<Card> straight = List.of(
new Card(new Value("A", 1), Suit.Spades),
new Card(new Value("2", 2), Suit.Diamonds),
new Card(new Value("3", 3), Suit.Clubs),
new Card(new Value("4", 4), Suit.Hearts),
new Card(new Value("5", 5), Suit.Diamonds));
String straightJson = json.serializeToString(straight);
List<Card> deserializedStraight = json.deserialize(typeToken, straightJson);
System.out.println();
System.out.println("RESULTS");
System.out.println("straight.equals(deserializedStraight)?");
System.out.println(straight.equals(deserializedStraight));
System.out.println();
System.out.println("JSON text:");
System.out.println();
System.out.println(straightJson);
Summary
We have a simple JSON library and have learned about the very latest features of Java. We hope you’ve enjoyed this series. Look forward to future posts that explore modern topics in software development.
We’re hiring
Want to be able to use the latest features of Java? We’re hiring!