Skip to content

feature: add OptimizelyJSON #371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
May 5, 2020
Merged

feature: add OptimizelyJSON #371

merged 26 commits into from
May 5, 2020

Conversation

jaeopt
Copy link
Contributor

@jaeopt jaeopt commented Apr 21, 2020

Summary

  • Add OptimizelyJSON for JSON feature variable access

@jaeopt jaeopt requested a review from a team as a code owner April 21, 2020 18:33
@jaeopt jaeopt self-assigned this Apr 21, 2020
@coveralls
Copy link

coveralls commented Apr 21, 2020

Pull Request Test Coverage Report for Build 1389

  • 115 of 132 (87.12%) changed or added relevant lines in 7 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-0.09%) to 89.222%

Changes Missing Coverage Covered Lines Changed/Added Lines %
core-api/src/main/java/com/optimizely/ab/config/parser/JacksonConfigParser.java 4 6 66.67%
core-api/src/main/java/com/optimizely/ab/config/parser/JsonParseException.java 2 4 50.0%
core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java 7 9 77.78%
core-api/src/main/java/com/optimizely/ab/config/parser/JsonHelpers.java 34 37 91.89%
core-api/src/main/java/com/optimizely/ab/optimizelyjson/OptimizelyJSON.java 45 53 84.91%
Totals Coverage Status
Change from base Build 1387: -0.09%
Covered Lines: 3874
Relevant Lines: 4342

💛 - Coveralls

Copy link

@pawels-optimizely pawels-optimizely left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getValue should not return anything, but it should modify the object passed in by reference.

Can you also make tests similar to the tests in go sdk ?
https://github.com/optimizely/go-sdk/blob/master/pkg/optimizelyjson/optimizely_json_test.go
Also please include the test to check if you don't destroy original object (it's also in my go tests)

Copy link
Contributor

@mikecdavis mikecdavis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks fine, but there's a larger question around JSON serialization libraries that we need to address.

Comment on lines 19 to 20
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't assume that Gson is available. I see two options:

  1. We mimic the approach taken in DefaultConfigParser
  2. Take a stance on the serializer and include as a shadow dependency

Option 1 is the safer approach, since it has some precedence, but adds SDK complexity.
Option 2 is preferred but has a larger impact to the customer (my main concern is mobile).

cc @mikeng13

assertEquals((Double)md1.k3.kk2.kkk4[0], 5.7, 0.01);
assertEquals(md1.k3.kk2.kkk4[2], "vvv4");

// verify previous getValue does not destroy the data
Copy link

@pawels-optimizely pawels-optimizely Apr 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the purpose of this test is to call getValue twice with non empty json path on the same object. That will check if we don't modify the object by traversing and returning just a subset of the object. Both getValue calls need to have at least the same root of the json path (or the same json path)

@jaeopt jaeopt requested a review from pawels-optimizely May 1, 2020 00:43
Copy link
Contributor

@mikecdavis mikecdavis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've requested some cleanup on the tests to be more inline with the testing framework best practices. We're also missing a lot of unit test coverage on the parsers directly.

Comment on lines 49 to 50
String toJson(Object src) throws ConfigParseException;
<T> T fromJson(String json, Class<T> clazz) throws ConfigParseException;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we create a new exception JsonParseException for these?

@@ -52,4 +53,17 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse
throw new ConfigParseException("Unable to parse datafile: " + json, e);
}
}

public String toJson(Object src) {
return new Gson().toJson(src);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realizing that we're not caching our Gson objects. I think this is worth benchmarking as this can be a performance bottleneck. Note that the JacksonConfigParser stores an ObjectMapper on the class implementation. This might have been ok when periodically parsing the Datafile, but if OptimizelyJSON is used heavily this could be an issue.

@Override
public <T> T fromJson(String json, Class<T> clazz) throws ConfigParseException {
if (Map.class.isAssignableFrom(clazz)) {
org.json.JSONObject obj = new org.json.JSONObject(json);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're using org.json.JSONObject and not org.json.simple.

*/
package com.optimizely.ab.config.parser;

public final class UnsupportedOperationException extends Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UnsupportedOperationException is also a built-in Java runtime exception that we shouldn't implement our own checked exception with the same name as this is confusing.

@Nullable
public <T> T getValue(@Nullable String jsonKey, Class<T> clazz) throws UnsupportedOperationException {
if (!(parser instanceof GsonConfigParser || parser instanceof JacksonConfigParser)) {
throw new UnsupportedOperationException("A proper JSON parser is not available. Use Gson or Jackson parser for this operation.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per previous comment re: UnsupportedOperationException consider throwing a runtime exception or renaming to something like a JsonParserException.


import static org.junit.Assert.*;

public class OptimizelyJSONExtendedTest extends OptimizelyJSONCoreTest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of Core vs Extended you can use assumeThat to conditionally ignore a parameterized variant.

return new GsonConfigParser();
}

// Tests for GSON only
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess these classes are ok, but per the comments above, they should not be extending from OptimizelyJSONExtendedTest.

*/
package com.optimizely.ab.optimizelyjson.types;

public class MD1 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear what these test classes are supposed to represent. It might be clearer if you subclass these under something like TestTypes.MD1 etc and add some doc strings.


import java.util.*;

final class JsonHelpers {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have a corresponding JsonHelpersTest class for unit tests.

@@ -61,4 +63,23 @@ public ProjectConfigModule() {
addDeserializer(Condition.class, new ConditionJacksonDeserializer(objectMapper));
}
}

@Override
public String toJson(Object src) throws ConfigParseException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're missing unit tests on these new implementations.

Copy link
Contributor

@mikecdavis mikecdavis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

Copy link

@pawels-optimizely pawels-optimizely left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jaeopt jaeopt merged commit 8609f3d into master May 5, 2020
@jaeopt jaeopt deleted the jae/optimizely-json branch October 22, 2020 21:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants