Skip to content

Commit fce8c53

Browse files
author
Caitlin Bales (MSFT)
committed
Serialize additional data all the way down the object chain
Child Graph objects that have additional data will now be serialized with this information intact. OData.type will now also be included in the serialized data.
1 parent ca74d0c commit fce8c53

File tree

2 files changed

+153
-14
lines changed

2 files changed

+153
-14
lines changed

src/main/java/com/microsoft/graph/serializer/DefaultSerializer.java

Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import com.google.gson.JsonObject;
2828
import com.microsoft.graph.logger.ILogger;
2929

30+
import java.util.HashMap;
31+
import java.util.Iterator;
3032
import java.util.Map;
3133

3234
/**
@@ -55,7 +57,7 @@ public DefaultSerializer(final ILogger logger) {
5557
}
5658

5759
/**
58-
* Deserialize an object from the input string.
60+
* Deserializes an object from the input string.
5961
*
6062
* @param inputString The string that stores the representation of the item.
6163
* @param clazz The .class of the item to be deserialized.
@@ -66,7 +68,7 @@ public DefaultSerializer(final ILogger logger) {
6668
public <T> T deserializeObject(final String inputString, final Class<T> clazz) {
6769
final T jsonObject = gson.fromJson(inputString, clazz);
6870

69-
// Populate the json backed fields for any annotations that are not in the object model
71+
// Populate the JSON-backed fields for any annotations that are not in the object model
7072
if (jsonObject instanceof IJsonBackedObject) {
7173
logger.logDebug("Deserializing type " + clazz.getSimpleName());
7274
final IJsonBackedObject jsonBackedObject = (IJsonBackedObject) jsonObject;
@@ -93,27 +95,99 @@ public <T> String serializeObject(final T serializableObject) {
9395
JsonElement outJsonTree = gson.toJsonTree(serializableObject);
9496

9597
if (serializableObject instanceof IJsonBackedObject) {
96-
AdditionalDataManager additionalData =
97-
((IJsonBackedObject) serializableObject)
98-
.additionalDataManager();
98+
IJsonBackedObject serializableJsonObject = (IJsonBackedObject) serializableObject;
99+
100+
AdditionalDataManager additionalData = serializableJsonObject.additionalDataManager();
101+
102+
// If the item is a valid Graph object, add its additional data
99103
if (outJsonTree.isJsonObject()) {
100104
JsonObject outJson = outJsonTree.getAsJsonObject();
101-
for (Map.Entry<String, JsonElement> entry : additionalData.entrySet()) {
102-
if (!fieldIsOdataTransient(entry)) {
103-
outJson.add(
104-
entry.getKey(),
105-
entry.getValue()
106-
);
107-
}
108-
}
105+
106+
addAdditionalDataToJson(additionalData, outJson);
107+
outJson = getChildAdditionalData(serializableJsonObject, outJson);
108+
109109
outJsonTree = outJson;
110110
}
111111
}
112112

113113
return outJsonTree.toString();
114114
}
115+
116+
/**
117+
* Recursively populates additional data for each child object
118+
*
119+
* @param serializableObject The child to get additional data for
120+
* @param outJson The serialized output JSON to add to
121+
* @return The serialized output JSON including the additional child data
122+
*/
123+
private JsonObject getChildAdditionalData(IJsonBackedObject serializableObject, JsonObject outJson) {
124+
// Use reflection to iterate through fields for eligible Graph children
125+
for (java.lang.reflect.Field field : serializableObject.getClass().getFields()) {
126+
try {
127+
Object fieldObject = field.get(serializableObject);
128+
129+
// If the object is a HashMap, iterate through its children
130+
if (fieldObject instanceof HashMap) {
131+
HashMap serializableChildren = (HashMap) fieldObject;
132+
Iterator it = serializableChildren.entrySet().iterator();
133+
134+
while (it.hasNext()) {
135+
HashMap.Entry pair = (HashMap.Entry)it.next();
136+
Object child = pair.getValue();
137+
138+
// If the item is a valid Graph object, add its additional data
139+
if (child instanceof IJsonBackedObject) {
140+
AdditionalDataManager childAdditionalData = ((IJsonBackedObject) child).additionalDataManager();
141+
142+
addAdditionalDataToJson(
143+
childAdditionalData,
144+
outJson.getAsJsonObject(
145+
field.getName())
146+
.getAsJsonObject()
147+
.get(pair.getKey()
148+
.toString())
149+
.getAsJsonObject());
150+
151+
// Serialize its children
152+
outJson = getChildAdditionalData((IJsonBackedObject)child, outJson);
153+
}
154+
}
155+
}
156+
// If the object is a valid Graph object, add its additional data
157+
else if (fieldObject != null && fieldObject instanceof IJsonBackedObject) {
158+
IJsonBackedObject serializableChild = (IJsonBackedObject) fieldObject;
159+
AdditionalDataManager childAdditionalData = serializableChild.additionalDataManager();
160+
161+
addAdditionalDataToJson(childAdditionalData, outJson.get(field.getName()).getAsJsonObject());
162+
163+
// Serialize its children
164+
outJson = getChildAdditionalData(serializableChild, outJson);
165+
}
166+
} catch (IllegalArgumentException | IllegalAccessException e) {
167+
logger.logError("Unable to access child fields of " + serializableObject.getClass().getSimpleName(), e);
168+
}
169+
}
170+
171+
return outJson;
172+
}
173+
174+
/**
175+
* Add each non-transient additional data property to the given JSON node
176+
* @param additionalDataManager The additional data bag to iterate through
177+
* @param jsonNode The JSON node to add the additional data properties to
178+
*/
179+
private void addAdditionalDataToJson(AdditionalDataManager additionalDataManager, JsonObject jsonNode) {
180+
for (Map.Entry<String, JsonElement> entry : additionalDataManager.entrySet()) {
181+
if (!fieldIsOdataTransient(entry)) {
182+
jsonNode.add(
183+
entry.getKey(),
184+
entry.getValue()
185+
);
186+
}
187+
}
188+
}
115189

116190
private boolean fieldIsOdataTransient(Map.Entry<String, JsonElement> entry) {
117-
return entry.getKey().startsWith("@");
191+
return (entry.getKey().startsWith("@") && entry.getKey() != "@odata.type");
118192
}
119193
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.microsoft.graph.serializer;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import org.junit.Before;
6+
import org.junit.Test;
7+
8+
import com.google.gson.JsonPrimitive;
9+
import com.microsoft.graph.logger.DefaultLogger;
10+
import com.microsoft.graph.models.extensions.Entity;
11+
import com.microsoft.graph.models.extensions.PlannerAssignment;
12+
import com.microsoft.graph.models.extensions.PlannerAssignments;
13+
import com.microsoft.graph.models.extensions.PlannerTask;
14+
import com.microsoft.graph.models.extensions.User;
15+
16+
public class AdditionalDataTests {
17+
public DefaultSerializer serializer;
18+
19+
@Before
20+
public void setUp() {
21+
serializer = new DefaultSerializer(new DefaultLogger());
22+
}
23+
24+
@Test
25+
public void testAddAdditionalData() {
26+
Entity entity = new Entity();
27+
entity.id = "1";
28+
29+
entity.additionalDataManager().put("additionalData", new JsonPrimitive("additionalValue"));
30+
31+
String serializedObject = serializer.serializeObject(entity);
32+
33+
assertEquals("{\"id\":\"1\",\"additionalData\":\"additionalValue\"}", serializedObject);
34+
}
35+
36+
@Test
37+
public void testChildAdditionalData() {
38+
User manager = new User();
39+
manager.id = "1";
40+
manager.additionalDataManager().put("additionalData", new JsonPrimitive("additionalValue"));
41+
42+
User user = new User();
43+
user.id = "2";
44+
45+
user.manager = manager;
46+
47+
String serializedObject = serializer.serializeObject(user);
48+
49+
assertEquals("{\"manager\":{\"id\":\"1\",\"additionalData\":\"additionalValue\"},\"id\":\"2\"}", serializedObject);
50+
}
51+
52+
@Test
53+
public void testHashMapChildAnnotationData() {
54+
// PlannerTask task = new PlannerTask();
55+
// task.assignments = new PlannerAssignments();
56+
// PlannerAssignment assignment = new PlannerAssignment();
57+
// assignment.orderHint = "!";
58+
// assignment.additionalDataManager().put("additionalData", new JsonPrimitive("additionalValue"));
59+
// task.assignments.put("id", assignment);
60+
//
61+
// String serializedObject = serializer.serializeObject(task);
62+
//
63+
// assertEquals("{\"assignments\":{\"id\":{\"orderHint\":\"!\",\"additionalData\":\"additionalValue\"}}}", serializedObject);
64+
}
65+
}

0 commit comments

Comments
 (0)