|
22 | 22 |
|
23 | 23 | package com.microsoft.graph.serializer; |
24 | 24 |
|
| 25 | +import com.google.common.base.CaseFormat; |
25 | 26 | import com.google.gson.Gson; |
26 | 27 | import com.google.gson.JsonElement; |
27 | 28 | import com.google.gson.JsonObject; |
@@ -64,13 +65,20 @@ public DefaultSerializer(final ILogger logger) { |
64 | 65 | */ |
65 | 66 | @Override |
66 | 67 | 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); |
68 | 69 |
|
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 |
70 | 71 | if (jsonObject instanceof IJsonBackedObject) { |
71 | 72 | logger.logDebug("Deserializing type " + clazz.getSimpleName()); |
72 | 73 | final IJsonBackedObject jsonBackedObject = (IJsonBackedObject) jsonObject; |
73 | 74 | 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 | + |
74 | 82 | jsonBackedObject.setRawObject(this, rawObject); |
75 | 83 | jsonBackedObject.additionalDataManager().setAdditionalData(rawObject); |
76 | 84 | } else { |
@@ -116,4 +124,32 @@ public <T> String serializeObject(final T serializableObject) { |
116 | 124 | private boolean fieldIsOdataTransient(Map.Entry<String, JsonElement> entry) { |
117 | 125 | return entry.getKey().startsWith("@"); |
118 | 126 | } |
| 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 | + } |
119 | 155 | } |
0 commit comments