Skip to content

Commit ac70b8d

Browse files
author
Caitlin Bales (MSFT)
authored
Merge pull request #14 from microsoftgraph/odata.type
Serialize additional data all the way down the object chain
2 parents 884c295 + 34ab752 commit ac70b8d

File tree

2 files changed

+165
-13
lines changed

2 files changed

+165
-13
lines changed

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

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import com.google.gson.JsonObject;
2929
import com.microsoft.graph.logger.ILogger;
3030

31+
import java.util.HashMap;
32+
import java.util.Iterator;
3133
import java.util.Map;
3234

3335
/**
@@ -56,7 +58,7 @@ public DefaultSerializer(final ILogger logger) {
5658
}
5759

5860
/**
59-
* Deserialize an object from the input string.
61+
* Deserializes an object from the input string.
6062
*
6163
* @param inputString The string that stores the representation of the item.
6264
* @param clazz The class of the item to be deserialized.
@@ -101,28 +103,100 @@ public <T> String serializeObject(final T serializableObject) {
101103
JsonElement outJsonTree = gson.toJsonTree(serializableObject);
102104

103105
if (serializableObject instanceof IJsonBackedObject) {
104-
AdditionalDataManager additionalData =
105-
((IJsonBackedObject) serializableObject)
106-
.additionalDataManager();
106+
IJsonBackedObject serializableJsonObject = (IJsonBackedObject) serializableObject;
107+
108+
AdditionalDataManager additionalData = serializableJsonObject.additionalDataManager();
109+
110+
// If the item is a valid Graph object, add its additional data
107111
if (outJsonTree.isJsonObject()) {
108112
JsonObject outJson = outJsonTree.getAsJsonObject();
109-
for (Map.Entry<String, JsonElement> entry : additionalData.entrySet()) {
110-
if (!fieldIsOdataTransient(entry)) {
111-
outJson.add(
112-
entry.getKey(),
113-
entry.getValue()
114-
);
115-
}
116-
}
113+
114+
addAdditionalDataToJson(additionalData, outJson);
115+
outJson = getChildAdditionalData(serializableJsonObject, outJson);
116+
117117
outJsonTree = outJson;
118118
}
119119
}
120120

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

124198
private boolean fieldIsOdataTransient(Map.Entry<String, JsonElement> entry) {
125-
return entry.getKey().startsWith("@");
199+
return (entry.getKey().startsWith("@") && entry.getKey() != "@odata.type");
126200
}
127201

128202
/**
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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 testSkipTransientData() {
54+
Entity entity = new Entity();
55+
entity.id = "1";
56+
57+
entity.additionalDataManager().put("@odata.type", new JsonPrimitive("entity"));
58+
entity.additionalDataManager().put("@odata.nextLink", new JsonPrimitive("1"));
59+
60+
String serializedObject = serializer.serializeObject(entity);
61+
62+
assertEquals("{\"id\":\"1\",\"@odata.type\":\"entity\"}", serializedObject);
63+
}
64+
65+
@Test
66+
public void testHashMapChildAnnotationData() {
67+
// PlannerTask task = new PlannerTask();
68+
// task.assignments = new PlannerAssignments();
69+
// PlannerAssignment assignment = new PlannerAssignment();
70+
// assignment.orderHint = "!";
71+
// assignment.additionalDataManager().put("additionalData", new JsonPrimitive("additionalValue"));
72+
// task.assignments.put("id", assignment);
73+
//
74+
// String serializedObject = serializer.serializeObject(task);
75+
//
76+
// assertEquals("{\"assignments\":{\"id\":{\"orderHint\":\"!\",\"additionalData\":\"additionalValue\"}}}", serializedObject);
77+
}
78+
}

0 commit comments

Comments
 (0)