Skip to content

Commit 8381f40

Browse files
authored
Merge pull request #48 from LIonWeb-org/issue46-lowlevelser
Introducing LowLevelSerialization
2 parents 6b04998 + ae1f36f commit 8381f40

17 files changed

+4790
-1042
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package org.lionweb.lioncore.java.serialization;
2+
3+
import com.google.gson.JsonArray;
4+
import com.google.gson.JsonElement;
5+
import com.google.gson.JsonObject;
6+
import org.lionweb.lioncore.java.serialization.data.*;
7+
8+
import javax.annotation.Nullable;
9+
10+
import static org.lionweb.lioncore.java.serialization.SerializationUtils.*;
11+
12+
/**
13+
* This class is responsible for handling serialization and unserialization from JSON and the low-level
14+
* representation of models composed by SerializationBlock and the related classes.
15+
*/
16+
public class LowLevelJsonSerialization {
17+
18+
/**
19+
* This will return a lower-level representation of the information stored in JSON.
20+
* It is intended to load broken models.
21+
* <p>
22+
* Possible usages: repair a broken model, extract a metamodel from the model (“model archeology”), etc.
23+
* <p>
24+
* This method follows a "best-effort" approach, try to limit exception thrown and return data whenever is possible,
25+
* in the measure that it is possible.
26+
*/
27+
public SerializedChunk unserializeSerializationBlock(JsonElement jsonElement) {
28+
SerializedChunk serializedChunk = new SerializedChunk();
29+
if (jsonElement.isJsonObject()) {
30+
JsonObject topLevel = jsonElement.getAsJsonObject();
31+
readSerializationFormatVersion(serializedChunk, topLevel);
32+
readMetamodels(serializedChunk, topLevel);
33+
unserializeNodes(serializedChunk, topLevel);
34+
return serializedChunk;
35+
} else {
36+
throw new IllegalArgumentException("We expected a Json Object, we got instead: " + jsonElement);
37+
}
38+
}
39+
40+
public JsonElement serializeToJson(SerializedChunk serializedChunk) {
41+
JsonObject topLevel = new JsonObject();
42+
topLevel.addProperty("serializationFormatVersion", serializedChunk.getSerializationFormatVersion());
43+
44+
JsonArray metamodels = new JsonArray();
45+
topLevel.add("metamodels", metamodels);
46+
47+
JsonArray nodes = new JsonArray();
48+
for (SerializedNode node: serializedChunk.getNodes()) {
49+
JsonObject nodeJson = new JsonObject();
50+
nodeJson.addProperty("id", node.getID());
51+
nodeJson.add("concept", serializeToJson(node.getConcept()));
52+
53+
JsonArray properties = new JsonArray();
54+
for (SerializedPropertyValue propertyValue : node.getProperties()) {
55+
JsonObject property = new JsonObject();
56+
property.add("property", serializeToJson(propertyValue.getMetaPointer()));
57+
property.addProperty("value", propertyValue.getValue());
58+
properties.add(property);
59+
}
60+
nodeJson.add("properties", properties);
61+
62+
JsonArray children = new JsonArray();
63+
for (SerializedContainmentValue childrenValue : node.getContainments()) {
64+
JsonObject childrenJ = new JsonObject();
65+
childrenJ.add("containment", serializeToJson(childrenValue.getMetaPointer()));
66+
childrenJ.add("children", toJsonArray(childrenValue.getValue()));
67+
children.add(childrenJ);
68+
}
69+
nodeJson.add("children", children);
70+
71+
JsonArray references = new JsonArray();
72+
for (SerializedReferenceValue referenceValue : node.getReferences()) {
73+
JsonObject reference = new JsonObject();
74+
reference.add("reference", serializeToJson(referenceValue.getMetaPointer()));
75+
reference.add("targets", toJsonArrayOfReferenceValues(referenceValue.getValue()));
76+
references.add(reference);
77+
}
78+
nodeJson.add("references", references);
79+
80+
nodeJson.addProperty("parent", node.getParentNodeID());
81+
82+
nodes.add(nodeJson);
83+
}
84+
topLevel.add("nodes", nodes);
85+
86+
return topLevel;
87+
}
88+
89+
private void readSerializationFormatVersion(SerializedChunk serializedChunk, JsonObject topLevel) {
90+
if (!topLevel.has("serializationFormatVersion")) {
91+
throw new IllegalArgumentException("serializationFormatVersion not specified");
92+
}
93+
String serializationFormatVersion = topLevel.get("serializationFormatVersion").getAsString();
94+
serializedChunk.setSerializationFormatVersion(serializationFormatVersion);
95+
}
96+
97+
private void readMetamodels(SerializedChunk serializedChunk, JsonObject topLevel) {
98+
if (!topLevel.has("metamodels")) {
99+
throw new IllegalArgumentException("metamodels not specified");
100+
}
101+
if (topLevel.get("metamodels").isJsonArray()) {
102+
topLevel.get("metamodels").getAsJsonArray().asList().stream().forEach(element -> {
103+
try {
104+
MetamodelKeyVersion metamodelKeyVersion = new MetamodelKeyVersion();
105+
if (element.isJsonObject()) {
106+
JsonObject jsonObject = element.getAsJsonObject();
107+
if (!jsonObject.has("key") || !jsonObject.has("version")) {
108+
throw new IllegalArgumentException("Metamodel should have keys key and version. Found: "
109+
+ element);
110+
}
111+
metamodelKeyVersion.setKey(jsonObject.get("key").getAsString());
112+
metamodelKeyVersion.setVersion(jsonObject.get("version").getAsString());
113+
} else {
114+
throw new IllegalArgumentException("Metamodel should be an object. Found: " + element);
115+
}
116+
serializedChunk.addMetamodel(metamodelKeyVersion);
117+
} catch (Exception e) {
118+
throw new RuntimeException("Issue while unserializing " + element, e);
119+
}
120+
});
121+
} else {
122+
throw new IllegalArgumentException("We expected a Json Array, we got instead: "
123+
+ topLevel.get("metamodels"));
124+
}
125+
}
126+
127+
private void unserializeNodes(SerializedChunk serializedChunk, JsonObject topLevel) {
128+
if (!topLevel.has("nodes")) {
129+
throw new IllegalArgumentException("nodes not specified");
130+
}
131+
if (topLevel.get("nodes").isJsonArray()) {
132+
topLevel.get("nodes").getAsJsonArray().asList().stream().forEach(element -> {
133+
try {
134+
SerializedNode node = unserializeNode(element);
135+
serializedChunk.addNode(node);
136+
} catch (Exception e) {
137+
throw new RuntimeException("Issue while unserializing " + element, e);
138+
}
139+
});
140+
} else {
141+
throw new IllegalArgumentException("We expected a Json Array, we got instead: " + topLevel.get("nodes"));
142+
}
143+
}
144+
145+
private JsonElement serializeToJson(MetaPointer metapointer) {
146+
JsonObject jsonObject = new JsonObject();
147+
jsonObject.addProperty("metamodel", metapointer.getMetamodel());
148+
jsonObject.addProperty("version", metapointer.getVersion());
149+
jsonObject.addProperty("key", metapointer.getKey());
150+
return jsonObject;
151+
}
152+
153+
@Nullable
154+
private SerializedNode unserializeNode(JsonElement jsonElement) {
155+
if (!jsonElement.isJsonObject()) {
156+
throw new IllegalArgumentException("Malformed JSON. Object expected but found " + jsonElement);
157+
}
158+
JsonObject jsonObject = jsonElement.getAsJsonObject();
159+
160+
SerializedNode serializedNode = new SerializedNode();
161+
serializedNode.setID(tryToGetStringProperty(jsonObject, "id"));
162+
serializedNode.setConcept(tryToGetMetaPointerProperty(jsonObject, "concept"));
163+
serializedNode.setParentNodeID(tryToGetStringProperty(jsonObject, "parent"));
164+
165+
JsonArray properties = jsonObject.get("properties").getAsJsonArray();
166+
properties.forEach(property -> {
167+
JsonObject propertyJO = property.getAsJsonObject();
168+
serializedNode.addPropertyValue(new SerializedPropertyValue(
169+
tryToGetMetaPointerProperty(propertyJO, "property"),
170+
tryToGetStringProperty(propertyJO, "value")
171+
));
172+
});
173+
174+
JsonArray children = jsonObject.get("children").getAsJsonArray();
175+
children.forEach(childrenEntry -> {
176+
JsonObject childrenJO = childrenEntry.getAsJsonObject();
177+
serializedNode.addContainmentValue(new SerializedContainmentValue(
178+
tryToGetMetaPointerProperty(childrenJO, "containment"),
179+
tryToGetArrayOfStringsProperty(childrenJO, "children")
180+
));
181+
});
182+
183+
JsonArray references = jsonObject.get("references").getAsJsonArray();
184+
references.forEach(referenceEntry -> {
185+
JsonObject referenceJO = referenceEntry.getAsJsonObject();
186+
serializedNode.addReferenceValue(new SerializedReferenceValue(
187+
tryToGetMetaPointerProperty(referenceJO, "reference"),
188+
tryToGetArrayOfReferencesProperty(referenceJO, "targets")
189+
));
190+
});
191+
192+
return serializedNode;
193+
}
194+
195+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package org.lionweb.lioncore.java.serialization;
2+
3+
import com.google.gson.JsonArray;
4+
import com.google.gson.JsonElement;
5+
import com.google.gson.JsonObject;
6+
import org.lionweb.lioncore.java.model.ReferenceValue;
7+
import org.lionweb.lioncore.java.serialization.data.MetaPointer;
8+
import org.lionweb.lioncore.java.serialization.data.SerializedReferenceValue;
9+
10+
import javax.annotation.Nullable;
11+
import java.util.List;
12+
import java.util.stream.Collectors;
13+
14+
/**
15+
* Collection of utility methods to simplify serialization and unserialization to JSON.
16+
*/
17+
class SerializationUtils {
18+
19+
private SerializationUtils() {
20+
// Prevent instantiation
21+
}
22+
23+
@Nullable
24+
static String getAsStringOrNull(JsonElement element) {
25+
if (element == null || element.isJsonNull()) {
26+
return null;
27+
} else {
28+
return element.getAsString();
29+
}
30+
}
31+
32+
@Nullable
33+
static String tryToGetStringProperty(JsonObject jsonObject, String propertyName) {
34+
if (!jsonObject.has(propertyName)) {
35+
return null;
36+
}
37+
JsonElement value = jsonObject.get(propertyName);
38+
if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isString()) {
39+
return value.getAsJsonPrimitive().getAsString();
40+
} else {
41+
return null;
42+
}
43+
}
44+
45+
@Nullable
46+
static MetaPointer tryToGetMetaPointerProperty(JsonObject jsonObject, String propertyName) {
47+
if (!jsonObject.has(propertyName)) {
48+
return null;
49+
}
50+
JsonElement value = jsonObject.get(propertyName);
51+
if (value.isJsonObject()) {
52+
JsonObject valueJO = value.getAsJsonObject();
53+
return new MetaPointer(tryToGetStringProperty(valueJO,"metamodel"),
54+
tryToGetStringProperty(valueJO,"version"),
55+
tryToGetStringProperty(valueJO,"key"));
56+
} else {
57+
return null;
58+
}
59+
}
60+
61+
@Nullable
62+
static List<String> tryToGetArrayOfStringsProperty(JsonObject jsonObject, String propertyName) {
63+
if (!jsonObject.has(propertyName)) {
64+
return null;
65+
}
66+
JsonElement value = jsonObject.get(propertyName);
67+
if (value.isJsonArray()) {
68+
JsonArray valueJA = value.getAsJsonArray();
69+
return valueJA.asList().stream().map(e -> e.getAsString()).collect(Collectors.toList());
70+
} else {
71+
return null;
72+
}
73+
}
74+
75+
@Nullable
76+
static List<SerializedReferenceValue.Entry> tryToGetArrayOfReferencesProperty(JsonObject jsonObject,
77+
String propertyName) {
78+
if (!jsonObject.has(propertyName)) {
79+
return null;
80+
}
81+
JsonElement value = jsonObject.get(propertyName);
82+
if (value.isJsonArray()) {
83+
JsonArray valueJA = value.getAsJsonArray();
84+
return valueJA.asList().stream().map(e -> new SerializedReferenceValue.Entry(
85+
tryToGetStringProperty(e.getAsJsonObject(), "reference"),
86+
tryToGetStringProperty(e.getAsJsonObject(), "resolveInfo")
87+
)).collect(Collectors.toList());
88+
} else {
89+
return null;
90+
}
91+
}
92+
93+
static JsonArray toJsonArray(List<String> stringList) {
94+
JsonArray jsonArray = new JsonArray();
95+
stringList.forEach(s -> jsonArray.add(s));
96+
return jsonArray;
97+
}
98+
99+
static JsonArray toJsonArrayOfReferenceValues(List<SerializedReferenceValue.Entry> entries) {
100+
JsonArray jsonArray = new JsonArray();
101+
entries.forEach(e -> {
102+
JsonObject entryJson = new JsonObject();
103+
entryJson.addProperty("resolveInfo", e.getResolveInfo());
104+
entryJson.addProperty("reference", e.getReference());
105+
jsonArray.add(entryJson);
106+
});
107+
return jsonArray;
108+
}
109+
}

0 commit comments

Comments
 (0)