|
24 | 24 | package com.microsoft.identity.labapi.utilities.client; |
25 | 25 |
|
26 | 26 | import com.google.gson.Gson; |
| 27 | +import com.google.gson.GsonBuilder; |
| 28 | +import com.google.gson.JsonDeserializationContext; |
| 29 | +import com.google.gson.JsonDeserializer; |
| 30 | +import com.google.gson.JsonElement; |
| 31 | +import com.google.gson.JsonObject; |
| 32 | +import com.google.gson.JsonParseException; |
27 | 33 | import com.google.gson.annotations.SerializedName; |
28 | 34 | import com.google.gson.reflect.TypeToken; |
29 | 35 |
|
30 | 36 | import java.io.Serializable; |
| 37 | +import java.lang.reflect.Field; |
31 | 38 | import java.lang.reflect.Type; |
| 39 | +import java.util.HashMap; |
| 40 | +import java.util.Locale; |
32 | 41 | import java.util.Map; |
33 | 42 |
|
34 | 43 | import lombok.Getter; |
@@ -70,8 +79,48 @@ public class LabJsonStringAccountEntry implements Serializable { |
70 | 79 | * @return a map of key to LabJsonStringAccountEntry |
71 | 80 | */ |
72 | 81 | public static Map<String, LabJsonStringAccountEntry> parseJsonToMap(String json) { |
73 | | - Gson gson = new Gson(); |
| 82 | + final Gson gson = new GsonBuilder() |
| 83 | + .registerTypeAdapter(LabJsonStringAccountEntry.class, new CaseInsensitiveDeserializer()) |
| 84 | + .create(); |
74 | 85 | Type type = new TypeToken<Map<String, LabJsonStringAccountEntry>>(){}.getType(); |
75 | 86 | return gson.fromJson(json, type); |
76 | 87 | } |
| 88 | + |
| 89 | + /** |
| 90 | + * Gson deserializer that matches JSON property names to {@link SerializedName} values |
| 91 | + * in a case-insensitive manner, so {@code upn}, {@code Upn} and {@code UPN} are all |
| 92 | + * treated as the same field. |
| 93 | + */ |
| 94 | + private static class CaseInsensitiveDeserializer implements JsonDeserializer<LabJsonStringAccountEntry> { |
| 95 | + @Override |
| 96 | + public LabJsonStringAccountEntry deserialize(JsonElement json, Type typeOfT, |
| 97 | + JsonDeserializationContext context) throws JsonParseException { |
| 98 | + final JsonObject src = json.getAsJsonObject(); |
| 99 | + |
| 100 | + // Build a lowercase-keyed view of the incoming JSON object. |
| 101 | + final Map<String, JsonElement> lowerCased = new HashMap<>(); |
| 102 | + for (Map.Entry<String, JsonElement> e : src.entrySet()) { |
| 103 | + lowerCased.put(e.getKey().toLowerCase(Locale.ROOT), e.getValue()); |
| 104 | + } |
| 105 | + |
| 106 | + final LabJsonStringAccountEntry result = new LabJsonStringAccountEntry(); |
| 107 | + for (Field field : LabJsonStringAccountEntry.class.getDeclaredFields()) { |
| 108 | + final SerializedName annotation = field.getAnnotation(SerializedName.class); |
| 109 | + if (annotation == null) { |
| 110 | + continue; |
| 111 | + } |
| 112 | + final JsonElement value = lowerCased.get(annotation.value().toLowerCase(Locale.ROOT)); |
| 113 | + if (value == null || value.isJsonNull()) { |
| 114 | + continue; |
| 115 | + } |
| 116 | + try { |
| 117 | + field.setAccessible(true); |
| 118 | + field.set(result, context.deserialize(value, field.getGenericType())); |
| 119 | + } catch (IllegalAccessException ex) { |
| 120 | + throw new JsonParseException("Failed to set field " + field.getName(), ex); |
| 121 | + } |
| 122 | + } |
| 123 | + return result; |
| 124 | + } |
| 125 | + } |
77 | 126 | } |
0 commit comments