Skip to content

Commit d102958

Browse files
author
Caitlin Bales (MSFT)
committed
Deserialize derived class data
This will attempt to deserialize results into the odata.type that Graph responds with instead of the class that the request builder provides. This allows us to respond with a derived object to a base object call. It also allows a developer to successfully cast the response object from the base type to the expected derived type.
1 parent ef1aa2f commit d102958

File tree

1 file changed

+38
-2
lines changed

1 file changed

+38
-2
lines changed

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

Lines changed: 38 additions & 2 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;
@@ -64,13 +65,20 @@ public DefaultSerializer(final ILogger logger) {
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);
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,32 @@ 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+
* @return The derived class if found, or null if not applicable
134+
*/
135+
private Class getDerivedClass(JsonObject jsonObject) {
136+
//Identify the odata.type information if provided
137+
if (jsonObject.get("@odata.type") != null) {
138+
String odataType = jsonObject.get("@odata.type").getAsString();
139+
String derivedType = odataType.substring(odataType.lastIndexOf('.') + 1); //Remove microsoft.graph prefix
140+
derivedType = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, derivedType);
141+
derivedType = "com.microsoft.graph.models.extensions." + derivedType; //Add full package path
142+
143+
try {
144+
return Class.forName(derivedType);
145+
} catch (ClassNotFoundException e) {
146+
logger.logDebug("Unable to find a corresponding class for derived type " + derivedType + ". Falling back to parent class.");
147+
//If we cannot determine the derived type to cast to, return null
148+
//This may happen if the API and the SDK are out of sync
149+
return null;
150+
}
151+
}
152+
//If there is no defined OData type, return null
153+
return null;
154+
}
119155
}

0 commit comments

Comments
 (0)