Skip to content

Commit 884c295

Browse files
author
Caitlin Bales (MSFT)
authored
Merge pull request #33 from microsoftgraph/derived-type-serializer
Derived type serializer
2 parents ec0d644 + 86cc46b commit 884c295

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

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

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
package com.microsoft.graph.serializer;
2424

25+
import com.google.common.base.CaseFormat;
2526
import com.google.gson.Gson;
2627
import com.google.gson.JsonElement;
2728
import com.google.gson.JsonObject;
@@ -58,19 +59,26 @@ public DefaultSerializer(final ILogger logger) {
5859
* Deserialize an object from the input string.
5960
*
6061
* @param inputString The string that stores the representation of the item.
61-
* @param clazz The .class of the item to be deserialized.
62+
* @param clazz The class of the item to be deserialized.
6263
* @param <T> The type of the item to be deserialized.
6364
* @return The deserialized item from the input string.
6465
*/
6566
@Override
6667
public <T> T deserializeObject(final String inputString, final Class<T> clazz) {
67-
final T jsonObject = gson.fromJson(inputString, clazz);
68+
T jsonObject = gson.fromJson(inputString, clazz);
6869

69-
// Populate the json backed fields for any annotations that are not in the object model
70+
// Populate the JSON-backed fields for any annotations that are not in the object model
7071
if (jsonObject instanceof IJsonBackedObject) {
7172
logger.logDebug("Deserializing type " + clazz.getSimpleName());
7273
final IJsonBackedObject jsonBackedObject = (IJsonBackedObject) jsonObject;
7374
final JsonObject rawObject = gson.fromJson(inputString, JsonObject.class);
75+
76+
// If there is a derived class, try to get it and deserialize to it
77+
Class derivedClass = this.getDerivedClass(rawObject, clazz);
78+
if (derivedClass != null) {
79+
jsonObject = (T) gson.fromJson(inputString, derivedClass);
80+
}
81+
7482
jsonBackedObject.setRawObject(this, rawObject);
7583
jsonBackedObject.additionalDataManager().setAdditionalData(rawObject);
7684
} else {
@@ -116,4 +124,38 @@ public <T> String serializeObject(final T serializableObject) {
116124
private boolean fieldIsOdataTransient(Map.Entry<String, JsonElement> entry) {
117125
return entry.getKey().startsWith("@");
118126
}
127+
128+
/**
129+
* Get the derived class for the given JSON object
130+
* This covers scenarios in which the service may return one of several derived types
131+
* of a base object, which it defines using the odata.type parameter
132+
* @param jsonObject The raw JSON object of the response
133+
* @param parentClass The parent class the derived class should inherit from
134+
* @return The derived class if found, or null if not applicable
135+
*/
136+
private Class getDerivedClass(JsonObject jsonObject, Class parentClass) {
137+
//Identify the odata.type information if provided
138+
if (jsonObject.get("@odata.type") != null) {
139+
String odataType = jsonObject.get("@odata.type").getAsString();
140+
String derivedType = odataType.substring(odataType.lastIndexOf('.') + 1); //Remove microsoft.graph prefix
141+
derivedType = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, derivedType);
142+
derivedType = "com.microsoft.graph.models.extensions." + derivedType; //Add full package path
143+
144+
try {
145+
Class derivedClass = Class.forName(derivedType);
146+
//Check that the derived class inherits from the given parent class
147+
if (parentClass.isAssignableFrom(derivedClass)) {
148+
return derivedClass;
149+
}
150+
return null;
151+
} catch (ClassNotFoundException e) {
152+
logger.logDebug("Unable to find a corresponding class for derived type " + derivedType + ". Falling back to parent class.");
153+
//If we cannot determine the derived type to cast to, return null
154+
//This may happen if the API and the SDK are out of sync
155+
return null;
156+
}
157+
}
158+
//If there is no defined OData type, return null
159+
return null;
160+
}
119161
}

src/test/java/com/microsoft/graph/serializer/DefaultSeralizerTests.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
import org.junit.Test;
88

99
import com.microsoft.graph.models.extensions.Drive;
10+
import com.microsoft.graph.models.extensions.FileAttachment;
1011
import com.microsoft.graph.models.generated.RecurrenceRangeType;
1112
import com.microsoft.graph.models.generated.BaseRecurrenceRange;
1213
import com.microsoft.graph.logger.DefaultLogger;
14+
import com.microsoft.graph.models.extensions.Attachment;
1315
import com.microsoft.graph.models.extensions.DateOnly;
1416

1517
public class DefaultSeralizerTests {
@@ -64,5 +66,16 @@ public void testRecurrenceRangeSerialization() throws Exception {
6466
assertNotNull(jsonOut);
6567
assertEquals(expected, jsonOut);
6668
}
67-
69+
70+
@Test
71+
public void testDeserializeDerivedType() throws Exception {
72+
final DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
73+
String source = "{\"@odata.context\": \"/attachments/$entity\",\"@odata.type\": \"#microsoft.graph.fileAttachment\",\"id\": \"AAMkAGQ0MjBmNWVkLTYxZjUtNDRmYi05Y2NiLTBlYjIwNzJjNmM1NgBGAAAAAAC6ff7latYeQqu_gLrhSAIhBwCF7iGjpaOmRqVwbZc-xXzwAAAAAAEMAACF7iGjpaOmRqVwbZc-xXzwAABQStA0AAABEgAQAFbGmeisbjtLnQdp7kC_9Fk=\",\"lastModifiedDateTime\": \"2018-01-23T21:50:22Z\",\"name\": \"Test Book.xlsx\",\"contentType\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\"size\": 8457,\"isInline\": false,\"contentId\": null,\"contentLocation\": null,\"contentBytes\": \"bytedata\"}";
74+
Attachment result = serializer.deserializeObject(source, Attachment.class);
75+
76+
assert(result instanceof FileAttachment);
77+
78+
FileAttachment fileAttachment = (FileAttachment) result;
79+
assertNotNull(fileAttachment.contentBytes);
80+
}
6881
}

0 commit comments

Comments
 (0)