Skip to content

Commit c9549cd

Browse files
msohailhussainMike Davis
authored and
Mike Davis
committed
test(parser): Add default parser override (#315)
* Added JSON parser override capability. * Update travis test matrix to test all supported JSON parsers.
1 parent df61424 commit c9549cd

File tree

3 files changed

+138
-26
lines changed

3 files changed

+138
-26
lines changed

.travis.yml

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ jdk:
77
install: true
88
addons:
99
srcclr: true
10+
env:
11+
- optimizely_default_parser=GSON_CONFIG_PARSER
12+
- optimizely_default_parser=JACKSON_CONFIG_PARSER
13+
- optimizely_default_parser=JSON_CONFIG_PARSER
14+
- optimizely_default_parser=JSON_SIMPLE_CONFIG_PARSER
1015
script:
1116
- "./gradlew clean"
1217
- "./gradlew exhaustiveTest"

core-api/src/main/java/com/optimizely/ab/config/parser/DefaultConfigParser.java

+56-23
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
*/
1717
package com.optimizely.ab.config.parser;
1818

19+
import com.optimizely.ab.internal.PropertyUtils;
1920
import org.slf4j.Logger;
2021
import org.slf4j.LoggerFactory;
2122

2223
import javax.annotation.Nonnull;
24+
import java.util.function.Supplier;
2325

2426
/**
2527
* Factory for generating {@link ConfigParser} instances, based on the json parser available on the classpath.
@@ -37,6 +39,33 @@ public static ConfigParser getInstance() {
3739

3840
//======== Helper methods ========//
3941

42+
public enum ConfigParserSupplier {
43+
GSON_CONFIG_PARSER("com.google.gson.Gson", GsonConfigParser::new),
44+
JACKSON_CONFIG_PARSER("com.fasterxml.jackson.databind.ObjectMapper", JacksonConfigParser::new),
45+
JSON_CONFIG_PARSER("org.json.JSONObject", JsonConfigParser::new),
46+
JSON_SIMPLE_CONFIG_PARSER("org.json.simple.JSONObject", JsonSimpleConfigParser::new);
47+
48+
private final String className;
49+
private final Supplier<ConfigParser> supplier;
50+
51+
ConfigParserSupplier(String className, Supplier<ConfigParser> supplier) {
52+
this.className = className;
53+
this.supplier = supplier;
54+
}
55+
56+
ConfigParser get() {
57+
return supplier.get();
58+
}
59+
60+
private boolean isPresent() {
61+
try {
62+
Class.forName(className);
63+
return true;
64+
} catch (ClassNotFoundException e) {
65+
return false;
66+
}
67+
}
68+
}
4069
/**
4170
* Creates and returns a {@link ConfigParser} using a json parser available on the classpath.
4271
*
@@ -45,35 +74,39 @@ public static ConfigParser getInstance() {
4574
*/
4675
private static @Nonnull
4776
ConfigParser create() {
48-
ConfigParser configParser;
49-
50-
if (isPresent("com.fasterxml.jackson.databind.ObjectMapper")) {
51-
configParser = new JacksonConfigParser();
52-
} else if (isPresent("com.google.gson.Gson")) {
53-
configParser = new GsonConfigParser();
54-
} else if (isPresent("org.json.simple.JSONObject")) {
55-
configParser = new JsonSimpleConfigParser();
56-
} else if (isPresent("org.json.JSONObject")) {
57-
configParser = new JsonConfigParser();
58-
} else {
59-
throw new MissingJsonParserException("unable to locate a JSON parser. "
60-
+ "Please see <link> for more information");
77+
78+
String configParserName = PropertyUtils.get("default_parser");
79+
80+
if (configParserName != null) {
81+
try {
82+
ConfigParserSupplier supplier = ConfigParserSupplier.valueOf(configParserName);
83+
if (supplier.isPresent()) {
84+
ConfigParser configParser = supplier.get();
85+
logger.debug("using json parser: {}, based on override config", configParser.getClass().getSimpleName());
86+
return configParser;
87+
}
88+
89+
logger.warn("configured parser {} is not available in the classpath", configParserName);
90+
} catch (IllegalArgumentException e) {
91+
logger.warn("configured parser {} is not a valid value", configParserName);
92+
}
6193
}
6294

63-
logger.info("using json parser: {}", configParser.getClass().getSimpleName());
64-
return configParser;
65-
}
95+
for (ConfigParserSupplier supplier: ConfigParserSupplier.values()) {
96+
if (!supplier.isPresent()) {
97+
continue;
98+
}
6699

67-
private static boolean isPresent(@Nonnull String className) {
68-
try {
69-
Class.forName(className);
70-
return true;
71-
} catch (ClassNotFoundException e) {
72-
return false;
100+
ConfigParser configParser = supplier.get();
101+
logger.info("using json parser: {}", configParser.getClass().getSimpleName());
102+
return configParser;
73103
}
104+
105+
throw new MissingJsonParserException("unable to locate a JSON parser. "
106+
+ "Please see <link> for more information");
74107
}
75108

76-
//======== Lazy-init Holder ========//
109+
//======== Lazy-init Holder ========//
77110

78111
private static class LazyHolder {
79112
private static final ConfigParser INSTANCE = create();

core-api/src/test/java/com/optimizely/ab/config/parser/DefaultConfigParserTest.java

+77-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
*
3-
* Copyright 2016-2017, Optimizely and contributors
3+
* Copyright 2016-2017, 2019, Optimizely and contributors
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -16,15 +16,89 @@
1616
*/
1717
package com.optimizely.ab.config.parser;
1818

19+
import com.optimizely.ab.config.ProjectConfig;
20+
import com.optimizely.ab.internal.PropertyUtils;
21+
import org.hamcrest.CoreMatchers;
22+
import org.junit.Assert;
1923
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.junit.runners.Parameterized;
26+
27+
import java.io.IOException;
28+
import java.util.Arrays;
29+
import java.util.Collection;
30+
31+
import static com.optimizely.ab.config.DatafileProjectConfigTestUtils.*;
32+
import static com.optimizely.ab.config.DatafileProjectConfigTestUtils.validConfigJsonV4;
33+
import static junit.framework.TestCase.fail;
2034

2135
/**
2236
* Tests for {@link DefaultConfigParser}.
2337
*/
38+
@RunWith(Parameterized.class)
2439
public class DefaultConfigParserTest {
2540

41+
@Parameterized.Parameters(name = "{index}")
42+
public static Collection<Object[]> data() throws IOException {
43+
return Arrays.asList(new Object[][]{
44+
{
45+
validConfigJsonV2(),
46+
validProjectConfigV2()
47+
},
48+
{
49+
validConfigJsonV3(),
50+
validProjectConfigV3()
51+
},
52+
{
53+
validConfigJsonV4(),
54+
validProjectConfigV4()
55+
}
56+
});
57+
}
58+
59+
@Parameterized.Parameter(0)
60+
public String validDatafile;
61+
62+
@Parameterized.Parameter(1)
63+
public ProjectConfig validProjectConfig;
64+
65+
/**
66+
* This method is to test DefaultConfigParser when different default_parser gets set.
67+
* For example: when optimizely_default_parser environment variable will be set to "GSON_CONFIG_PARSER" than
68+
* "DefaultConfigParser.getInstance()" returns "GsonConfigParser" and parse ProjectConfig using it. Also
69+
* this test will assertThat "configParser" (Provided in env variable) is instance of "GsonConfigParser.class"
70+
*
71+
* @throws Exception
72+
*/
2673
@Test
27-
public void createThrowException() throws Exception {
28-
// FIXME - mdodsworth: hmmm, this isn't going to be the easiest thing to test
74+
public void testPropertyDefaultParser() throws Exception {
75+
String defaultParser = PropertyUtils.get("default_parser");
76+
ConfigParser configParser = DefaultConfigParser.getInstance();
77+
ProjectConfig actual = configParser.parseProjectConfig(validDatafile);
78+
ProjectConfig expected = validProjectConfig;
79+
verifyProjectConfig(actual, expected);
80+
Class expectedParser = GsonConfigParser.class;
81+
82+
if(defaultParser != null) {
83+
DefaultConfigParser.ConfigParserSupplier defaultParserSupplier = DefaultConfigParser.ConfigParserSupplier.valueOf(defaultParser);
84+
switch (defaultParserSupplier) {
85+
case GSON_CONFIG_PARSER:
86+
expectedParser = GsonConfigParser.class;
87+
break;
88+
case JACKSON_CONFIG_PARSER:
89+
expectedParser = JacksonConfigParser.class;
90+
break;
91+
case JSON_CONFIG_PARSER:
92+
expectedParser = JsonConfigParser.class;
93+
break;
94+
case JSON_SIMPLE_CONFIG_PARSER:
95+
expectedParser = JsonSimpleConfigParser.class;
96+
break;
97+
default:
98+
fail("Not a valid config parser");
99+
}
100+
}
101+
102+
Assert.assertThat(configParser, CoreMatchers.instanceOf(expectedParser));
29103
}
30104
}

0 commit comments

Comments
 (0)