Skip to content

Commit 55ddaee

Browse files
committed
JSON serialization and deserialization
1 parent eaf1e70 commit 55ddaee

File tree

6 files changed

+247
-0
lines changed

6 files changed

+247
-0
lines changed

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,5 +220,6 @@
220220
<module>sudoku</module>
221221
<module>sudoku-output</module>
222222
<module>sudoku-client</module>
223+
<module>sudoku-serialization-json</module>
223224
</modules>
224225
</project>

sudoku-serialization-json/pom.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<parent>
5+
<groupId>de.sfuhrm</groupId>
6+
<artifactId>sudoku-parent</artifactId>
7+
<version>5.1.1-SNAPSHOT</version>
8+
</parent>
9+
<artifactId>sudoku-riddle</artifactId>
10+
<name>Sudoku Riddle</name>
11+
<description>Sudoku Riddle Serialization</description>
12+
<dependencies>
13+
<dependency>
14+
<groupId>de.sfuhrm</groupId>
15+
<artifactId>sudoku</artifactId>
16+
<version>${project.version}</version>
17+
</dependency>
18+
<dependency>
19+
<groupId>com.google.code.gson</groupId>
20+
<artifactId>gson</artifactId>
21+
<version>2.10.1</version>
22+
</dependency>
23+
</dependencies>
24+
</project>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package de.sfuhrm.sudoku;
2+
3+
import com.google.gson.JsonArray;
4+
import com.google.gson.JsonDeserializationContext;
5+
import com.google.gson.JsonDeserializer;
6+
import com.google.gson.JsonElement;
7+
import com.google.gson.JsonObject;
8+
import com.google.gson.JsonParseException;
9+
import com.google.gson.JsonSerializationContext;
10+
import com.google.gson.JsonSerializer;
11+
12+
import java.lang.reflect.Type;
13+
import java.util.List;
14+
15+
/**
16+
* GSON Serializer and Deserializer implementation for {@link Riddle}
17+
* for direct Gson serialization.
18+
* Can be registered to Gson using:
19+
* <code>
20+
* Gson gson = new GsonBuilder()
21+
* .registerTypeHierarchyAdapter(Riddle.class, new GsonRiddleSerializer())
22+
* .create();
23+
* </code>
24+
*/
25+
public class GsonRiddleSerializer implements JsonSerializer<Riddle>, JsonDeserializer<Riddle> {
26+
27+
private static final String GAMESCHEMA_WIDTH = "width";
28+
private static final String GAMESCHEMA_BLOCK_WIDTH = "blockWidth";
29+
private static final String ROOT_CELL_DATA = "data";
30+
private static final String ROOT_WRITEABLE = "writeable";
31+
32+
@Override
33+
public JsonElement serialize(Riddle src, Type typeOfSrc, JsonSerializationContext context) {
34+
JsonObject jsonObject = new JsonObject();
35+
GameSchema schema = src.getSchema();
36+
jsonObject.addProperty(GAMESCHEMA_WIDTH, schema.getWidth());
37+
jsonObject.addProperty(GAMESCHEMA_BLOCK_WIDTH, schema.getBlockWidth());
38+
39+
JsonArray dataArray = new JsonArray();
40+
byte[][] array = src.getArray();
41+
for (byte[] row : array) {
42+
JsonArray rowArray = new JsonArray();
43+
for (byte cell : row) {
44+
rowArray.add(cell);
45+
}
46+
dataArray.add(rowArray);
47+
}
48+
jsonObject.add(ROOT_CELL_DATA, dataArray);
49+
50+
JsonArray writableArray = new JsonArray();
51+
for (int i = 0; i < schema.getWidth(); i++) {
52+
JsonArray rowArray = new JsonArray();
53+
for (int j = 0; j < schema.getWidth(); j++) {
54+
rowArray.add(src.getWritable(i, j));
55+
}
56+
writableArray.add(rowArray);
57+
}
58+
jsonObject.add(ROOT_WRITEABLE, writableArray);
59+
60+
return jsonObject;
61+
}
62+
63+
@Override
64+
public Riddle deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
65+
JsonObject jsonObject = json.getAsJsonObject();
66+
int width = jsonObject.get(GAMESCHEMA_WIDTH).getAsInt();
67+
int blockWidth = jsonObject.get(GAMESCHEMA_BLOCK_WIDTH).getAsInt();
68+
69+
GameSchema schema = findSchema(width, blockWidth);
70+
if (schema == null) {
71+
throw new JsonParseException("Unsupported schema: " + width + "x" + width + " with block width " + blockWidth);
72+
}
73+
74+
Riddle riddle = new RiddleImpl(schema);
75+
76+
JsonArray dataArray = jsonObject.getAsJsonArray(ROOT_CELL_DATA);
77+
for (int i = 0; i < width; i++) {
78+
JsonArray rowArray = dataArray.get(i).getAsJsonArray();
79+
for (int j = 0; j < width; j++) {
80+
riddle.set(i, j, rowArray.get(j).getAsByte());
81+
}
82+
}
83+
84+
JsonArray writableArray = jsonObject.getAsJsonArray(ROOT_WRITEABLE);
85+
for (int i = 0; i < width; i++) {
86+
JsonArray rowArray = writableArray.get(i).getAsJsonArray();
87+
for (int j = 0; j < width; j++) {
88+
riddle.setWritable(i, j, rowArray.get(j).getAsBoolean());
89+
}
90+
}
91+
92+
return riddle;
93+
}
94+
95+
private GameSchema findSchema(int width, int blockWidth) {
96+
List<GameSchema> schemas = GameSchemas.getSupportedGameSchemas();
97+
for (GameSchema schema : schemas) {
98+
if (schema.getWidth() == width && schema.getBlockWidth() == blockWidth) {
99+
return schema;
100+
}
101+
}
102+
return null;
103+
}
104+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package de.sfuhrm.sudoku;
2+
3+
/**
4+
* Serialization of a {@linkplain Riddle} to and from a String.
5+
*/
6+
public class JsonSerializer {
7+
private final com.google.gson.Gson gson;
8+
9+
/**
10+
* Creates a new instance with a default Gson configuration.
11+
*/
12+
public JsonSerializer() {
13+
this.gson = new com.google.gson.GsonBuilder()
14+
.registerTypeHierarchyAdapter(Riddle.class, new GsonRiddleSerializer())
15+
.create();
16+
}
17+
18+
/**
19+
* Serializes a {@link Riddle} to a JSON string.
20+
* @param riddle the riddle to serialize.
21+
* @return the JSON representation of the riddle.
22+
*/
23+
public String serialize(Riddle riddle) {
24+
return gson.toJson(riddle);
25+
}
26+
27+
/**
28+
* Deserializes a {@link Riddle} from a JSON string.
29+
* @param json the JSON string to deserialize.
30+
* @return the deserialized riddle instance.
31+
*/
32+
public Riddle deserialize(String json) {
33+
return gson.fromJson(json, Riddle.class);
34+
}
35+
36+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package de.sfuhrm.sudoku;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
5+
import org.junit.jupiter.params.ParameterizedTest;
6+
import org.junit.jupiter.params.provider.MethodSource;
7+
8+
import java.util.Random;
9+
10+
import static org.junit.jupiter.api.Assertions.assertEquals;
11+
import static org.junit.jupiter.api.Assertions.assertNotNull;
12+
13+
public class GsonRiddleSerializerTest {
14+
15+
@ParameterizedTest
16+
@MethodSource("de.sfuhrm.sudoku.GameSchemas#getSupportedGameSchemas")
17+
public void testSerializeDeserialize(GameSchema gameSchema) {
18+
Random r = new Random();
19+
RiddleImpl riddle = new RiddleImpl(gameSchema);
20+
riddle.set(0, 0, (byte) 1);
21+
riddle.setWritable(0, 0, false);
22+
riddle.set(1, 1, (byte) 2);
23+
riddle.setWritable(1, 1, true);
24+
25+
Gson gson = new GsonBuilder()
26+
.registerTypeHierarchyAdapter(Riddle.class, new GsonRiddleSerializer())
27+
.create();
28+
29+
String json = gson.toJson(riddle);
30+
assertNotNull(json);
31+
32+
Riddle deserialized = gson.fromJson(json, Riddle.class);
33+
assertNotNull(deserialized);
34+
assertEquals(riddle.getSchema(), deserialized.getSchema());
35+
assertEquals(riddle.get(0, 0), deserialized.get(0, 0));
36+
assertEquals(riddle.getWritable(0, 0), deserialized.getWritable(0, 0));
37+
assertEquals(riddle.get(1, 1), deserialized.get(1, 1));
38+
assertEquals(riddle.getWritable(1, 1), deserialized.getWritable(1, 1));
39+
40+
// Check dimensions
41+
assertEquals(riddle.getSchema().getWidth(), deserialized.getSchema().getWidth());
42+
}
43+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package de.sfuhrm.sudoku;
2+
3+
import org.junit.jupiter.params.ParameterizedTest;
4+
import org.junit.jupiter.params.provider.MethodSource;
5+
6+
import java.util.Random;
7+
8+
import static org.junit.jupiter.api.Assertions.assertEquals;
9+
import static org.junit.jupiter.api.Assertions.assertNotNull;
10+
11+
public class JsonSerializerTest {
12+
13+
@ParameterizedTest
14+
@MethodSource("de.sfuhrm.sudoku.GameSchemas#getSupportedGameSchemas")
15+
public void testSerializeDeserialize(GameSchema gameSchema) {
16+
Random r = new Random();
17+
RiddleImpl riddle = new RiddleImpl(gameSchema);
18+
riddle.set(0, 0, (byte) 1);
19+
riddle.setWritable(0, 0, false);
20+
riddle.set(1, 1, (byte) 2);
21+
riddle.setWritable(1, 1, true);
22+
23+
JsonSerializer serializer = new JsonSerializer();
24+
25+
String json = serializer.serialize(riddle);
26+
assertNotNull(json);
27+
28+
Riddle deserialized = serializer.deserialize(json);
29+
assertNotNull(deserialized);
30+
assertEquals(riddle.getSchema(), deserialized.getSchema());
31+
assertEquals(riddle.get(0, 0), deserialized.get(0, 0));
32+
assertEquals(riddle.getWritable(0, 0), deserialized.getWritable(0, 0));
33+
assertEquals(riddle.get(1, 1), deserialized.get(1, 1));
34+
assertEquals(riddle.getWritable(1, 1), deserialized.getWritable(1, 1));
35+
36+
// Check dimensions
37+
assertEquals(riddle.getSchema().getWidth(), deserialized.getSchema().getWidth());
38+
}
39+
}

0 commit comments

Comments
 (0)