1 package org.djutils.data.json;
2
3 import java.io.FileReader;
4 import java.io.FileWriter;
5 import java.io.IOException;
6 import java.io.Reader;
7 import java.io.Writer;
8 import java.util.ArrayList;
9 import java.util.IllegalFormatException;
10 import java.util.List;
11 import java.util.function.Consumer;
12
13 import org.djutils.data.Column;
14 import org.djutils.data.ListTable;
15 import org.djutils.data.Row;
16 import org.djutils.data.Table;
17 import org.djutils.data.serialization.TextSerializationException;
18 import org.djutils.data.serialization.TextSerializer;
19 import org.djutils.exceptions.Throw;
20 import org.djutils.primitives.Primitive;
21
22 import com.google.gson.stream.JsonReader;
23 import com.google.gson.stream.JsonToken;
24 import com.google.gson.stream.JsonWriter;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public final class JsonData
81 {
82
83
84
85 private JsonData()
86 {
87
88 }
89
90
91
92
93
94
95
96
97 @SuppressWarnings("resource")
98 public static void writeData(final Writer writer, final Table dataTable) throws IOException, TextSerializationException
99 {
100 try (JsonWriter jw = new JsonWriter(writer);)
101 {
102
103 jw.setIndent(" ");
104
105
106 jw.beginObject();
107 jw.name("table").beginObject();
108 jw.name("id").value(dataTable.getId());
109 jw.name("description").value(dataTable.getDescription());
110 jw.name("class").value(dataTable.getClass().getName());
111 jw.name("columns").beginArray();
112 int index = 0;
113 for (Column<?> column : dataTable.getColumns())
114 {
115 jw.beginObject();
116 jw.name("nr").value(index++);
117 jw.name("id").value(column.getId());
118 jw.name("description").value(column.getDescription());
119 jw.name("type").value(column.getValueType().getName());
120 if (column.getUnit() != null)
121 {
122 jw.name("unit").value(column.getUnit());
123 }
124 jw.endObject();
125 }
126 jw.endArray();
127 jw.endObject();
128
129
130 TextSerializer<?>[] serializers = new TextSerializer[dataTable.getNumberOfColumns()];
131 for (int i = 0; i < dataTable.getNumberOfColumns(); i++)
132 {
133 Column<?> column = dataTable.getColumns().get(i);
134 serializers[i] = TextSerializer.resolve(column.getValueType());
135 }
136
137
138 jw.name("data").beginArray();
139
140
141 for (Row row : dataTable)
142 {
143 Object[] values = row.getValues();
144 jw.beginArray();
145 jw.setIndent("");
146 for (int i = 0; i < dataTable.getNumberOfColumns(); i++)
147 {
148 jw.beginObject().name(String.valueOf(i))
149 .value(TextSerializer.serialize(serializers[i], values[i], dataTable.getColumn(i).getUnit()))
150 .endObject();
151 }
152 jw.endArray();
153 jw.setIndent(" ");
154 }
155
156
157 jw.endArray();
158 jw.endObject();
159 }
160 }
161
162
163
164
165
166
167
168
169 public static void writeData(final String filename, final Table dataTable) throws IOException, TextSerializationException
170 {
171 FileWriter fw = null;
172 try
173 {
174 fw = new FileWriter(filename);
175 writeData(fw, dataTable);
176 }
177 finally
178 {
179 if (null != fw)
180 {
181 fw.close();
182 }
183 }
184 }
185
186
187
188
189
190
191
192
193 public static Table readData(final Reader reader) throws IOException, TextSerializationException
194 {
195 try (JsonReader jr = new JsonReader(reader))
196 {
197
198 jr.beginObject();
199 readName(jr, "table");
200 jr.beginObject();
201 String[] tableProperties = new String[3];
202 tableProperties[0] = readValue(jr, "id");
203 tableProperties[1] = readValue(jr, "description");
204 tableProperties[2] = readValue(jr, "class");
205
206
207 List<Column<?>> columns = new ArrayList<>();
208 int index = 0;
209 readName(jr, "columns");
210 jr.beginArray();
211 while (jr.peek().equals(JsonToken.BEGIN_OBJECT))
212 {
213 String[] columnProperties = new String[5];
214 jr.beginObject();
215 columnProperties[0] = readValue(jr, "nr");
216 columnProperties[1] = readValue(jr, "id");
217 columnProperties[2] = readValue(jr, "description");
218 columnProperties[3] = readValue(jr, "type");
219 columnProperties[4] = jr.peek().equals(JsonToken.END_OBJECT) ? null : readValue(jr, "unit");
220 jr.endObject();
221
222 if (Integer.valueOf(columnProperties[0]).intValue() != index)
223 {
224 throw new IOException("column nr not ok");
225 }
226 String type = columnProperties[3];
227 Class<?> valueClass = Primitive.forName(type);
228 if (valueClass == null)
229 {
230 try
231 {
232 valueClass = Class.forName(type);
233 }
234 catch (ClassNotFoundException exception)
235 {
236 throw new IOException("Could not find class " + type, exception);
237 }
238 }
239 Column<?> column = new Column<>(columnProperties[1], columnProperties[2], valueClass, columnProperties[4]);
240 columns.add(column);
241 index++;
242 }
243 jr.endArray();
244 jr.endObject();
245
246
247 Table table;
248 Consumer<Object[]> unserializableTable;
249 if (tableProperties[2].equals(ListTable.class.getName()))
250 {
251 ListTable listTable = new ListTable(tableProperties[0], tableProperties[1], columns);
252 table = listTable;
253 unserializableTable = (
254 data
255 ) -> listTable.addRow(data);
256 }
257 else
258 {
259
260 ListTable listTable = new ListTable(tableProperties[0], tableProperties[1], columns);
261 table = listTable;
262 unserializableTable = (
263 data
264 ) -> listTable.addRow(data);
265 }
266
267
268 TextSerializer<?>[] serializers = new TextSerializer[table.getNumberOfColumns()];
269 for (int i = 0; i < table.getNumberOfColumns(); i++)
270 {
271 serializers[i] = TextSerializer.resolve(columns.get(i).getValueType());
272 }
273
274
275 readName(jr, "data");
276 jr.beginArray();
277 while (jr.peek().equals(JsonToken.BEGIN_ARRAY))
278 {
279 Object[] values = new Object[columns.size()];
280 jr.beginArray();
281 for (int i = 0; i < table.getNumberOfColumns(); i++)
282 {
283 jr.beginObject();
284 values[i] = TextSerializer.deserialize(serializers[i], readValue(jr, "" + i), columns.get(i));
285 jr.endObject();
286 }
287 jr.endArray();
288 unserializableTable.accept(values);
289 }
290
291
292 jr.endArray();
293 jr.endObject();
294 return table;
295 }
296 }
297
298
299
300
301
302
303
304
305
306 private static String readValue(final JsonReader jr, final String tag) throws IllegalFormatException, IOException
307 {
308 Throw.when(!jr.nextName().equals(tag), IllegalFormatException.class, "readValue: no %s object", tag);
309 if (jr.peek().equals(JsonToken.NULL))
310 {
311 jr.nextNull();
312 return null;
313 }
314 return jr.nextString();
315 }
316
317
318
319
320
321
322
323
324 private static void readName(final JsonReader jr, final String tag) throws IllegalFormatException, IOException
325 {
326 Throw.when(!jr.nextName().equals(tag), IllegalFormatException.class, "readName: no %s object", tag);
327 }
328
329
330
331
332
333
334
335
336 public static Table readData(final String filename) throws IOException, TextSerializationException
337 {
338 try (FileReader fr = new FileReader(filename);)
339 {
340 return readData(fr);
341 }
342 }
343
344 }