diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/AudienceGsonDeserializer.java b/core-api/src/main/java/com/optimizely/ab/config/parser/AudienceGsonDeserializer.java index f729bf1a3..408b92046 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/AudienceGsonDeserializer.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/AudienceGsonDeserializer.java @@ -49,8 +49,15 @@ public Audience deserialize(JsonElement json, Type typeOfT, JsonDeserializationC if (!typeOfT.toString().contains("TypedAudience")) { conditionsElement = parser.parse(jsonObject.get("conditions").getAsString()); } - List rawObjectList = gson.fromJson(conditionsElement, List.class); - Condition conditions = ConditionUtils.parseConditions(UserAttribute.class, rawObjectList); + Condition conditions = null; + if (conditionsElement.isJsonArray()) { + List rawObjectList = gson.fromJson(conditionsElement, List.class); + conditions = ConditionUtils.parseConditions(UserAttribute.class, rawObjectList); + } + else if (conditionsElement.isJsonObject()) { + Object object = gson.fromJson(conditionsElement,Object.class); + conditions = ConditionUtils.parseConditions(UserAttribute.class, object); + } return new Audience(id, name, conditions); } diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/GsonHelpers.java b/core-api/src/main/java/com/optimizely/ab/config/parser/GsonHelpers.java index 41e479d04..a227102fb 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/GsonHelpers.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/GsonHelpers.java @@ -23,6 +23,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; +import com.google.gson.internal.LinkedTreeMap; import com.google.gson.reflect.TypeToken; import com.optimizely.ab.bucketing.DecisionService; import com.optimizely.ab.config.Experiment; @@ -108,10 +109,16 @@ static Condition parseAudienceConditions(JsonObject experimentJson) { JsonElement conditionsElement = experimentJson.get("audienceConditions"); - List rawObjectList = gson.fromJson(conditionsElement, List.class); - Condition conditions = ConditionUtils.parseConditions(AudienceIdCondition.class, rawObjectList); + if (conditionsElement.isJsonArray()) { + List rawObjectList = gson.fromJson(conditionsElement, List.class); + return ConditionUtils.parseConditions(AudienceIdCondition.class, rawObjectList); + } + else if (conditionsElement.isJsonObject()) { + Object jsonObject = gson.fromJson(conditionsElement,Object.class); + return ConditionUtils.parseConditions(AudienceIdCondition.class, jsonObject); + } - return conditions; + return null; } static Experiment parseExperiment(JsonObject experimentJson, String groupId, JsonDeserializationContext context) { diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java index 85efed6ac..03cebdfbb 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java @@ -37,6 +37,7 @@ import com.optimizely.ab.internal.ConditionUtils; import org.json.JSONArray; import org.json.JSONObject; +import org.json.JSONTokener; import javax.annotation.Nonnull; import java.util.ArrayList; @@ -148,9 +149,7 @@ private List parseExperiments(JSONArray experimentJson, String group Condition conditions = null; if (experimentObject.has("audienceConditions")) { Object jsonCondition = experimentObject.get("audienceConditions"); - if (jsonCondition instanceof JSONArray) { - conditions = ConditionUtils.parseConditions(AudienceIdCondition.class, (JSONArray) jsonCondition); - } + conditions = ConditionUtils.parseConditions(AudienceIdCondition.class, jsonCondition); } // parse the child objects @@ -289,9 +288,19 @@ private List parseAudiences(JSONArray audienceJson) { String id = audienceObject.getString("id"); String key = audienceObject.getString("name"); Object conditionsObject = audienceObject.get("conditions"); - JSONArray conditionJson = new JSONArray((String)conditionsObject); + if (conditionsObject instanceof String) { // should always be true + JSONTokener tokener = new JSONTokener((String)conditionsObject); + char token = tokener.nextClean(); + if (token =='[') { + // must be an array + conditionsObject = new JSONArray((String)conditionsObject); + } + else if (token =='{') { + conditionsObject = new JSONObject((String)conditionsObject); + } + } - Condition conditions = ConditionUtils.parseConditions(UserAttribute.class, conditionJson); + Condition conditions = ConditionUtils.parseConditions(UserAttribute.class, conditionsObject); audiences.add(new Audience(id, key, conditions)); } @@ -306,9 +315,8 @@ private List parseTypedAudiences(JSONArray audienceJson) { String id = audienceObject.getString("id"); String key = audienceObject.getString("name"); Object conditionsObject = audienceObject.get("conditions"); - JSONArray conditionJson = (JSONArray)conditionsObject; - Condition conditions = ConditionUtils.parseConditions(UserAttribute.class, conditionJson); + Condition conditions = ConditionUtils.parseConditions(UserAttribute.class, conditionsObject); audiences.add(new Audience(id, key, conditions)); } diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java index 48e7227bc..4eae0374d 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java @@ -156,13 +156,11 @@ private List parseExperiments(JSONArray experimentJson, String group Condition conditions = null; if (experimentObject.containsKey("audienceConditions")) { Object jsonCondition = experimentObject.get("audienceConditions"); - if (jsonCondition instanceof JSONArray) { - try { - conditions = ConditionUtils.parseConditions(AudienceIdCondition.class, (JSONArray)jsonCondition); - } catch (Exception e) { - // unable to parse conditions. - Logger.getAnonymousLogger().log(Level.ALL, "problem parsing audience conditions", e); - } + try { + conditions = ConditionUtils.parseConditions(AudienceIdCondition.class, jsonCondition); + } catch (Exception e) { + // unable to parse conditions. + Logger.getAnonymousLogger().log(Level.ALL, "problem parsing audience conditions", e); } } // parse the child objects @@ -303,7 +301,7 @@ private List parseAudiences(JSONArray audienceJson) throws ParseExcept String id = (String)audienceObject.get("id"); String key = (String)audienceObject.get("name"); Object conditionObject = audienceObject.get("conditions"); - JSONArray conditionJson = (JSONArray)parser.parse((String)conditionObject); + Object conditionJson = parser.parse((String)conditionObject); Condition conditions = ConditionUtils.parseConditions(UserAttribute.class, conditionJson); audiences.add(new Audience(id, key, conditions)); } @@ -319,8 +317,7 @@ private List parseTypedAudiences(JSONArray audienceJson) throws ParseE String id = (String)audienceObject.get("id"); String key = (String)audienceObject.get("name"); Object conditionObject = audienceObject.get("conditions"); - JSONArray conditionJson = (JSONArray)conditionObject; - Condition conditions = ConditionUtils.parseConditions(UserAttribute.class, conditionJson); + Condition conditions = ConditionUtils.parseConditions(UserAttribute.class, conditionObject); audiences.add(new Audience(id, key, conditions)); } diff --git a/core-api/src/main/java/com/optimizely/ab/internal/ConditionUtils.java b/core-api/src/main/java/com/optimizely/ab/internal/ConditionUtils.java index 61c83dc84..92ec00d5c 100644 --- a/core-api/src/main/java/com/optimizely/ab/internal/ConditionUtils.java +++ b/core-api/src/main/java/com/optimizely/ab/internal/ConditionUtils.java @@ -32,6 +32,75 @@ import java.util.Map; public class ConditionUtils { + + static public Condition parseConditions(Class clazz, Object object) throws InvalidAudienceCondition { + if (object instanceof List) { + List objectList = (List)object; + return ConditionUtils.parseConditions(clazz, objectList); + } + else if (object instanceof String) { // looking for audience conditions in experiment + AudienceIdCondition audienceIdCondition = new AudienceIdCondition((String)object); + if (clazz.isInstance(audienceIdCondition)) { + return audienceIdCondition; + } + else { + throw new InvalidAudienceCondition(String.format("Expected AudienceIdCondition got %s", clazz.getCanonicalName())); + } + } + else if (object instanceof LinkedTreeMap) { // gson + if (clazz != UserAttribute.class) { + throw new InvalidAudienceCondition(String.format("Expected UserAttributes got %s", clazz.getCanonicalName())); + + } + + LinkedTreeMap conditionMap = (LinkedTreeMap)object; + return new UserAttribute((String)conditionMap.get("name"), (String)conditionMap.get("type"), + (String)conditionMap.get("match"), conditionMap.get("value")); + } + else if (object instanceof JSONObject) { + if (clazz != UserAttribute.class) { + throw new InvalidAudienceCondition(String.format("Expected UserAttributes got %s", clazz.getCanonicalName())); + + } + + JSONObject conditionMap = (JSONObject)object; + return new UserAttribute((String)conditionMap.get("name"), (String)conditionMap.get("type"), + (String)conditionMap.get("match"), conditionMap.get("value")); + } + else if (object instanceof org.json.JSONArray) { + return ConditionUtils.parseConditions(clazz, (org.json.JSONArray) object); + } + else if (object instanceof org.json.JSONObject){ + if (clazz != UserAttribute.class) { + throw new InvalidAudienceCondition(String.format("Expected UserAttributes got %s", clazz.getCanonicalName())); + + } + org.json.JSONObject conditionMap = (org.json.JSONObject)object; + String match = null; + Object value = null; + if (conditionMap.has("match")) { + match = (String) conditionMap.get("match"); + } + if (conditionMap.has("value")) { + value = conditionMap.get("value"); + } + return new UserAttribute((String)conditionMap.get("name"), (String)conditionMap.get("type"), + match, value); + } + + else { // looking for audience conditions in audience + if (clazz != UserAttribute.class) { + throw new InvalidAudienceCondition(String.format("Expected UserAttributes got %s", clazz.getCanonicalName())); + + } + + Map conditionMap = (Map)object; + return new UserAttribute((String)conditionMap.get("name"), (String)conditionMap.get("type"), + (String)conditionMap.get("match"), conditionMap.get("value")); + } + + } + /** * parse conditions using List and Map * @param rawObjectList list of conditions @@ -55,49 +124,7 @@ static public Condition parseConditions(Class clazz, List rawObje for (int i = startingParseIndex; i < rawObjectList.size(); i++) { Object obj = rawObjectList.get(i); - if (obj instanceof List) { - List objectList = (List)rawObjectList.get(i); - conditions.add(ConditionUtils.parseConditions(clazz, objectList)); - } - else if (obj instanceof String) { // looking for audience conditions in experiment - AudienceIdCondition audienceIdCondition = new AudienceIdCondition((String)obj); - if (clazz.isInstance(audienceIdCondition)) { - conditions.add(new AudienceIdCondition((String) obj)); - } - else { - throw new InvalidAudienceCondition(String.format("Expected AudienceIdCondition got %s", clazz.getCanonicalName())); - } - } - else if (obj instanceof LinkedTreeMap) { // gson - if (clazz != UserAttribute.class) { - throw new InvalidAudienceCondition(String.format("Expected UserAttributes got %s", clazz.getCanonicalName())); - - } - - LinkedTreeMap conditionMap = (LinkedTreeMap)rawObjectList.get(i); - conditions.add(new UserAttribute((String)conditionMap.get("name"), (String)conditionMap.get("type"), - (String)conditionMap.get("match"), conditionMap.get("value"))); - } - else if (obj instanceof JSONObject) { - if (clazz != UserAttribute.class) { - throw new InvalidAudienceCondition(String.format("Expected UserAttributes got %s", clazz.getCanonicalName())); - - } - - JSONObject conditionMap = (JSONObject)obj; - conditions.add(new UserAttribute((String)conditionMap.get("name"), (String)conditionMap.get("type"), - (String)conditionMap.get("match"), conditionMap.get("value"))); - } - else { // looking for audience conditions in audience - if (clazz != UserAttribute.class) { - throw new InvalidAudienceCondition(String.format("Expected UserAttributes got %s", clazz.getCanonicalName())); - - } - - Map conditionMap = (Map)rawObjectList.get(i); - conditions.add(new UserAttribute((String)conditionMap.get("name"), (String)conditionMap.get("type"), - (String)conditionMap.get("match"), conditionMap.get("value"))); - } + conditions.add(parseConditions(clazz, obj)); } Condition condition; @@ -158,33 +185,7 @@ static public Condition parseConditions(Class clazz, org.json.JSONArray c for (int i = startingParseIndex; i < conditionJson.length(); i++) { Object obj = conditionJson.get(i); - if (obj instanceof org.json.JSONArray) { - conditions.add(ConditionUtils.parseConditions(clazz, (org.json.JSONArray) conditionJson.get(i))); - } else if (obj instanceof String) { - AudienceIdCondition audiencCondition = new AudienceIdCondition((String)obj); - if (clazz.isInstance(audiencCondition)) { - conditions.add(audiencCondition); - } - else { - throw new InvalidAudienceCondition(String.format("Expected AudienceIdCondition got %s", clazz.getCanonicalName())); - } - } else { - if (clazz != UserAttribute.class) { - throw new InvalidAudienceCondition(String.format("Expected UserAttributes got %s", clazz.getCanonicalName())); - - } - org.json.JSONObject conditionMap = (org.json.JSONObject)obj; - String match = null; - Object value = null; - if (conditionMap.has("match")) { - match = (String) conditionMap.get("match"); - } - if (conditionMap.has("value")) { - value = conditionMap.get("value"); - } - conditions.add(new UserAttribute((String)conditionMap.get("name"), (String)conditionMap.get("type"), - match, value)); - } + conditions.add(parseConditions(clazz, obj)); } Condition condition; @@ -205,5 +206,4 @@ static public Condition parseConditions(Class clazz, org.json.JSONArray c return condition; } - }