Skip to content

Commit 2ce908e

Browse files
authored
Merge pull request #25 from LIonWeb-org/serializeLibrary
Correct serialization so that reserialize Library works
2 parents a6804f4 + 5444ca5 commit 2ce908e

File tree

4 files changed

+168
-32
lines changed

4 files changed

+168
-32
lines changed

core/src/main/java/org/lionweb/lioncore/java/self/LionCore.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public static Metamodel getInstance() {
152152
namespacedEntity.addFeature(Property.createRequired("qualifiedName", LionCoreBuiltins.getString(),
153153
"LIonCore_M3_NamespacedEntity_qualifiedName").setDerived(true));
154154

155-
namespaceProvider.addFeature(Property.createRequired("namespaceQualifier", LionCoreBuiltins.getString(), "LIonCore_M3_NamespaceProvider_namespaceQualifier"));
155+
namespaceProvider.addFeature(Property.createRequired("namespaceQualifier", LionCoreBuiltins.getString(), "LIonCore_M3_NamespaceProvider_namespaceQualifier").setDerived(true));
156156

157157
primitiveType.setExtendedConcept(dataType);
158158

core/src/main/java/org/lionweb/lioncore/java/serialization/JsonSerialization.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.gson.JsonArray;
44
import com.google.gson.JsonElement;
5+
import com.google.gson.JsonNull;
56
import com.google.gson.JsonObject;
67
import org.lionweb.lioncore.java.metamodel.*;
78
import org.lionweb.lioncore.java.model.Node;
@@ -100,7 +101,7 @@ private JsonObject serializeThisNode(Node node) {
100101
jsonObject.addProperty(ID_LABEL, node.getID());
101102

102103
JsonObject properties = new JsonObject();
103-
node.getConcept().allProperties().forEach(property -> {
104+
node.getConcept().allProperties().stream().filter(p -> !p.isDerived()).forEach(property -> {
104105
properties.addProperty(property.getID(), serializePropertyValue(node.getPropertyValue(property)));
105106
});
106107
jsonObject.add("properties", properties);
@@ -121,6 +122,12 @@ private JsonObject serializeThisNode(Node node) {
121122
});
122123
jsonObject.add("references", references);
123124

125+
if (node.getParent() == null) {
126+
jsonObject.add("parent", JsonNull.INSTANCE);
127+
} else {
128+
jsonObject.addProperty("parent", node.getParent().getID());
129+
}
130+
124131
return jsonObject;
125132
}
126133

@@ -182,7 +189,8 @@ private void populateLinks(Node node, JsonObject data) {
182189
}
183190
}
184191
if (data.has("parent")) {
185-
String parentNodeID = data.get("parent").getAsString();
192+
JsonElement parentValue = data.get("parent");
193+
String parentNodeID = parentValue instanceof JsonNull ? null : parentValue.getAsString();
186194
Node parent = nodeIdToNode.get(parentNodeID);
187195
if (node instanceof M3Node) {
188196
((M3Node<M3Node>) node).setParent(parent);

core/src/test/java/org/lionweb/lioncore/java/serialization/JsonSerializationTest.java

+89-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.lionweb.lioncore.java.serialization;
22

3-
import com.google.gson.JsonElement;
4-
import com.google.gson.JsonParser;
3+
import com.google.gson.*;
54
import org.junit.Ignore;
65
import org.junit.Test;
76
import org.lionweb.lioncore.java.metamodel.Concept;
@@ -12,7 +11,10 @@
1211

1312
import java.io.InputStream;
1413
import java.io.InputStreamReader;
15-
import java.util.List;
14+
import java.util.*;
15+
import java.util.function.Consumer;
16+
import java.util.function.Function;
17+
import java.util.stream.Collectors;
1618

1719
import static org.junit.Assert.assertEquals;
1820

@@ -65,15 +67,97 @@ public void unserializeLibrary() {
6567
List<Node> unserializedNodes = jsonSerialization.unserialize(jsonElement);
6668
}
6769

68-
@Ignore // Currently there are differences due to differences in LionCore
6970
@Test
7071
public void reserializeLibrary() {
7172
InputStream inputStream = this.getClass().getResourceAsStream("/serialization/library-metamodel.json");
7273
JsonElement jsonElement = JsonParser.parseReader(new InputStreamReader(inputStream));
7374
JsonSerialization jsonSerialization = JsonSerialization.getStandardSerialization();
7475
List<Node> unserializedNodes = jsonSerialization.unserialize(jsonElement);
7576
JsonElement reserialized = jsonSerialization.serialize(unserializedNodes.get(0));
76-
assertEquals(jsonElement, reserialized);
77+
assertEquivalentLionWebJson(jsonElement.getAsJsonArray(), reserialized.getAsJsonArray());
78+
}
79+
80+
private void assertEquivalentLionWebJson(JsonArray expected, JsonArray actual) {
81+
Map<String, JsonObject> expectedElements = new HashMap<>();
82+
Map<String, JsonObject> actualElements = new HashMap<>();
83+
Function<Map<String, JsonObject>, Consumer<JsonElement>> idCollector = collection -> e -> {
84+
String id = e.getAsJsonObject().get("id").getAsString();
85+
collection.put(id, e.getAsJsonObject());
86+
};
87+
expected.forEach(idCollector.apply(expectedElements));
88+
actual.forEach(idCollector.apply(actualElements));
89+
Set<String> unexpectedIDs = new HashSet<>(actualElements.keySet());
90+
unexpectedIDs.removeAll(expectedElements.keySet());
91+
Set<String> missingIDs = new HashSet<>(expectedElements.keySet());
92+
missingIDs.removeAll(actualElements.keySet());
93+
if (!unexpectedIDs.isEmpty()) {
94+
throw new AssertionError("Unexpected IDs found: " + unexpectedIDs);
95+
}
96+
if (!missingIDs.isEmpty()) {
97+
throw new AssertionError("Missing IDs found: " + missingIDs);
98+
}
99+
for (String id: expectedElements.keySet()) {
100+
JsonObject expectedElement = expectedElements.get(id);
101+
JsonObject actualElement = actualElements.get(id);
102+
assertEquivalentNodes(expectedElement, actualElement, "Node " + id);
103+
}
104+
}
105+
106+
private void assertEquivalentNodes(JsonObject expected, JsonObject actual, String context) {
107+
Set<String> actualMeaningfulKeys = actual.keySet();
108+
Set<String> expectedMeaningfulKeys = expected.keySet();
109+
110+
Set<String> unexpectedKeys = new HashSet<>(actualMeaningfulKeys);
111+
unexpectedKeys.removeAll(expectedMeaningfulKeys);
112+
Set<String> missingKeys = new HashSet<>(expectedMeaningfulKeys);
113+
missingKeys.removeAll(actualMeaningfulKeys);
114+
if (!unexpectedKeys.isEmpty()) {
115+
throw new AssertionError("(" + context + ") Unexpected keys found: " + unexpectedKeys);
116+
}
117+
if (!missingKeys.isEmpty()) {
118+
throw new AssertionError("(" + context + ") Missing keys found: " + missingKeys);
119+
}
120+
for (String key: actualMeaningfulKeys) {
121+
if (key.equals("parent")) {
122+
assertEquals("(" + context + ") different parent", expected.get("parent"), actual.get("parent"));
123+
} else if (key.equals("concept")) {
124+
assertEquals("(" + context + ") different concept", expected.get("concept"), actual.get("concept"));
125+
} else if (key.equals("id")) {
126+
assertEquals("(" + context + ") different id", expected.get("id"), actual.get("id"));
127+
} else if (key.equals("references")) {
128+
assertEquivalentObjects(expected.getAsJsonObject("references"), actual.getAsJsonObject("references"), "References of " + context);
129+
} else if (key.equals("children")) {
130+
assertEquivalentObjects(expected.getAsJsonObject("children"), actual.getAsJsonObject("children"), "Children of " + context);
131+
} else if (key.equals("properties")) {
132+
assertEquivalentObjects(expected.getAsJsonObject("properties"), actual.getAsJsonObject("properties"), "Properties of " + context);
133+
} else {
134+
throw new AssertionError("(" + context + ") unexpected top-level key found: " + key);
135+
}
136+
}
137+
}
138+
139+
private void assertEquivalentObjects(JsonObject expected, JsonObject actual, String context) {
140+
Set<String> actualMeaningfulKeys = actual.keySet().stream().filter(k ->
141+
!actual.get(k).equals(new JsonObject())
142+
&& !actual.get(k).equals(new JsonArray())
143+
&& !actual.get(k).equals(JsonNull.INSTANCE)).collect(Collectors.toSet());
144+
Set<String> expectedMeaningfulKeys = expected.keySet().stream().filter(k -> !expected.get(k).equals(new JsonObject())
145+
&& !expected.get(k).equals(new JsonArray())
146+
&& !expected.get(k).equals(JsonNull.INSTANCE)).collect(Collectors.toSet());
147+
148+
Set<String> unexpectedKeys = new HashSet<>(actualMeaningfulKeys);
149+
unexpectedKeys.removeAll(expectedMeaningfulKeys);
150+
Set<String> missingKeys = new HashSet<>(expectedMeaningfulKeys);
151+
missingKeys.removeAll(actualMeaningfulKeys);
152+
if (!unexpectedKeys.isEmpty()) {
153+
throw new AssertionError("(" + context + ") Unexpected keys found: " + unexpectedKeys);
154+
}
155+
if (!missingKeys.isEmpty()) {
156+
throw new AssertionError("(" + context + ") Missing keys found: " + missingKeys);
157+
}
158+
for (String key: actualMeaningfulKeys) {
159+
assertEquals("(" + context + ") Different values for key " + key, expected.get(key), actual.get(key));
160+
}
77161
}
78162

79163
}

core/src/test/resources/serialization/library-metamodel.json

+68-24
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,23 @@
1616
"nNUEzZ7it7d2HoHPAtk5rGO4SsqVA3hAlBwkK1KP8QU",
1717
"RDa_L8gbU8XgW9z46oMysBi1Hb7vjcS8O8LUgXlFpeU"
1818
]
19-
}
19+
},
20+
"references": {
21+
22+
},
23+
"parent": null
2024
},
2125
{
2226
"concept": "LIonCore_M3_PrimitiveType",
2327
"id": "INhBvWyXvxwNsePuX0rdNGB_J9hi85cTb1Q0APXCyJ0",
2428
"properties": {
2529
"LIonCore_M3_NamespacedEntity_simpleName": "String"
30+
},
31+
"children": {
32+
33+
},
34+
"references": {
35+
2636
},
2737
"parent": "txjxNU9yRzEuyghtmgJK_l-nF93qWt7d1vErz5RbLow"
2838
},
@@ -31,6 +41,12 @@
3141
"id": "uHmTCy63BV23cvXwFSumVwK1DOh4IZvIyAnRJjW9eQI",
3242
"properties": {
3343
"LIonCore_M3_NamespacedEntity_simpleName": "boolean"
44+
},
45+
"references": {
46+
47+
},
48+
"children": {
49+
3450
},
3551
"parent": "txjxNU9yRzEuyghtmgJK_l-nF93qWt7d1vErz5RbLow"
3652
},
@@ -39,6 +55,12 @@
3955
"id": "gVp8_QSmXE2k4pd-sQZgjYMoW95SLLaVIH4yMYqqbt4",
4056
"properties": {
4157
"LIonCore_M3_NamespacedEntity_simpleName": "int"
58+
},
59+
"children": {
60+
61+
},
62+
"references": {
63+
4264
},
4365
"parent": "txjxNU9yRzEuyghtmgJK_l-nF93qWt7d1vErz5RbLow"
4466
},
@@ -47,7 +69,7 @@
4769
"id": "OcDK2GESljInG-ApIqtkXUoA2UeviB97u0UuiZzM0Hs",
4870
"properties": {
4971
"LIonCore_M3_NamespacedEntity_simpleName": "Book",
50-
"LIonCore_M3_Concept_abstract": false
72+
"LIonCore_M3_Concept_abstract": "false"
5173
},
5274
"children": {
5375
"LIonCore_M3_FeaturesContainer_features": [
@@ -67,8 +89,11 @@
6789
"id": "Ei9m_HbdmEYg_EwMLLVZ71ERRBZyXH8GHVyOVia8Sqg",
6890
"properties": {
6991
"LIonCore_M3_NamespacedEntity_simpleName": "title",
70-
"LIonCore_M3_Feature_optional": false,
71-
"LIonCore_M3_Feature_derived": false
92+
"LIonCore_M3_Feature_optional": "false",
93+
"LIonCore_M3_Feature_derived": "false"
94+
},
95+
"children": {
96+
7297
},
7398
"references": {
7499
"LIonCore_M3_Property_type": [
@@ -82,8 +107,11 @@
82107
"id": "OJhF8vB_qRMrA8A9a-H0LsByONdYtHGmQ-lk9rUHUc4",
83108
"properties": {
84109
"LIonCore_M3_NamespacedEntity_simpleName": "pages",
85-
"LIonCore_M3_Feature_optional": false,
86-
"LIonCore_M3_Feature_derived": false
110+
"LIonCore_M3_Feature_optional": "false",
111+
"LIonCore_M3_Feature_derived": "false"
112+
},
113+
"children": {
114+
87115
},
88116
"references": {
89117
"LIonCore_M3_Property_type": [
@@ -97,23 +125,24 @@
97125
"id": "9ATCb8nXEuQAL3NOY-EUZwuThpIQnQ2C_2n97IRGA_g",
98126
"properties": {
99127
"LIonCore_M3_NamespacedEntity_simpleName": "author",
100-
"LIonCore_M3_Feature_optional": false,
101-
"LIonCore_M3_Feature_derived": false,
102-
"LIonCore_M3_Link_multiple": true
128+
"LIonCore_M3_Feature_optional": "false",
129+
"LIonCore_M3_Feature_derived": "false",
130+
"LIonCore_M3_Link_multiple": "true"
103131
},
104132
"references": {
105133
"LIonCore_M3_Link_type": [
106134
"DuBg-a_slgc_VOG0huySkSWi3rZQX1Q20EEd2f7lvLE"
107135
]
108136
},
137+
"children": {},
109138
"parent": "OcDK2GESljInG-ApIqtkXUoA2UeviB97u0UuiZzM0Hs"
110139
},
111140
{
112141
"concept": "LIonCore_M3_Concept",
113142
"id": "Pk1NRJfHMt4eSja2kpXia7x8vj6Vzc6WQCUzT3aVeYY",
114143
"properties": {
115144
"LIonCore_M3_NamespacedEntity_simpleName": "Library",
116-
"LIonCore_M3_Concept_abstract": false
145+
"LIonCore_M3_Concept_abstract": "false"
117146
},
118147
"children": {
119148
"LIonCore_M3_FeaturesContainer_features": [
@@ -132,8 +161,11 @@
132161
"id": "LdgCnVXNgZD7CLbBhBin2Rcdumx4qZUYz_jh2QnP5z8",
133162
"properties": {
134163
"LIonCore_M3_NamespacedEntity_simpleName": "name",
135-
"LIonCore_M3_Feature_optional": false,
136-
"LIonCore_M3_Feature_derived": false
164+
"LIonCore_M3_Feature_optional": "false",
165+
"LIonCore_M3_Feature_derived": "false"
166+
},
167+
"children": {
168+
137169
},
138170
"references": {
139171
"LIonCore_M3_Property_type": [
@@ -147,9 +179,12 @@
147179
"id": "TFS1ME6sEyRbkRchsr8zaZCcj_uF1LM0LXK24gbnxZM",
148180
"properties": {
149181
"LIonCore_M3_NamespacedEntity_simpleName": "books",
150-
"LIonCore_M3_Feature_optional": false,
151-
"LIonCore_M3_Feature_derived": false,
152-
"LIonCore_M3_Link_multiple": true
182+
"LIonCore_M3_Feature_optional": "false",
183+
"LIonCore_M3_Feature_derived": "false",
184+
"LIonCore_M3_Link_multiple": "true"
185+
},
186+
"children": {
187+
153188
},
154189
"references": {
155190
"LIonCore_M3_Link_type": [
@@ -163,7 +198,7 @@
163198
"id": "DuBg-a_slgc_VOG0huySkSWi3rZQX1Q20EEd2f7lvLE",
164199
"properties": {
165200
"LIonCore_M3_NamespacedEntity_simpleName": "Writer",
166-
"LIonCore_M3_Concept_abstract": false
201+
"LIonCore_M3_Concept_abstract": "false"
167202
},
168203
"children": {
169204
"LIonCore_M3_FeaturesContainer_features": [
@@ -181,8 +216,11 @@
181216
"id": "onRRrZaasiOtDU2qFJgyW8OVz8p5-hqQu0Vlc_7Aq6s",
182217
"properties": {
183218
"LIonCore_M3_NamespacedEntity_simpleName": "name",
184-
"LIonCore_M3_Feature_optional": false,
185-
"LIonCore_M3_Feature_derived": false
219+
"LIonCore_M3_Feature_optional": "false",
220+
"LIonCore_M3_Feature_derived": "false"
221+
},
222+
"children": {
223+
186224
},
187225
"references": {
188226
"LIonCore_M3_Property_type": [
@@ -196,7 +234,7 @@
196234
"id": "nNUEzZ7it7d2HoHPAtk5rGO4SsqVA3hAlBwkK1KP8QU",
197235
"properties": {
198236
"LIonCore_M3_NamespacedEntity_simpleName": "GuideBookWriter",
199-
"LIonCore_M3_Concept_abstract": false
237+
"LIonCore_M3_Concept_abstract": "false"
200238
},
201239
"children": {
202240
"LIonCore_M3_FeaturesContainer_features": [
@@ -216,8 +254,11 @@
216254
"id": "PoZyl6WXh-Cz5h2RspK1NL6zX9DdLwGpUUC-ygQmHMA",
217255
"properties": {
218256
"LIonCore_M3_NamespacedEntity_simpleName": "countries",
219-
"LIonCore_M3_Feature_optional": false,
220-
"LIonCore_M3_Feature_derived": false
257+
"LIonCore_M3_Feature_optional": "false",
258+
"LIonCore_M3_Feature_derived": "false"
259+
},
260+
"children": {
261+
221262
},
222263
"references": {
223264
"LIonCore_M3_Property_type": [
@@ -231,7 +272,7 @@
231272
"id": "RDa_L8gbU8XgW9z46oMysBi1Hb7vjcS8O8LUgXlFpeU",
232273
"properties": {
233274
"LIonCore_M3_NamespacedEntity_simpleName": "SpecialistBookWriter",
234-
"LIonCore_M3_Concept_abstract": false
275+
"LIonCore_M3_Concept_abstract": "false"
235276
},
236277
"children": {
237278
"LIonCore_M3_FeaturesContainer_features": [
@@ -251,8 +292,11 @@
251292
"id": "DbVixG73dI8xIF9TAoq2GOZru4CRQfRD8gG7TkFCZuU",
252293
"properties": {
253294
"LIonCore_M3_NamespacedEntity_simpleName": "subject",
254-
"LIonCore_M3_Feature_optional": false,
255-
"LIonCore_M3_Feature_derived": false
295+
"LIonCore_M3_Feature_optional": "false",
296+
"LIonCore_M3_Feature_derived": "false"
297+
},
298+
"children": {
299+
256300
},
257301
"references": {
258302
"LIonCore_M3_Property_type": [

0 commit comments

Comments
 (0)