Skip to content

Updates for Configuration Generification#257

Open
hbordersTwitch wants to merge 1 commit into
Eppo-exp:snapshot/typo/v5from
hbordersTwitch:hbordersTwitch/generic_configuration
Open

Updates for Configuration Generification#257
hbordersTwitch wants to merge 1 commit into
Eppo-exp:snapshot/typo/v5from
hbordersTwitch:hbordersTwitch/generic_configuration

Conversation

@hbordersTwitch

Copy link
Copy Markdown
Contributor

Eppo Internal:

🎟️ Fixes issue
📜 Design Doc: link if applicable

Motivation and Context

Needed to update classes dependent on https://github.com/Eppo-exp/sdk-common-jdk/ classes.
Needed to ensure that AndroidBaseClient had no Configuration dependencies.
See Eppo-exp/sdk-common-jdk#241

Description

  1. Made AndroidBaseClient generic over SerializableEppoConfiguration and SerializableEppoConfiguration.AbstractBuilder types for compatibility with BaseEppoClient changes in Made Configuration generic to enable injectable JSON parsing sdk-common-jdk#241
  2. AndroidBaseClient.Builder generic over SerializableEppoConfiguration and SerializableEppoConfiguration.AbstractBuilder so that subclasses can reuse it in their builders.
    1. Removed AndroidBaseClient.Builder.configStore() because we can't create a FileBackedConfigStore for the consumer anymore since AndroidBaseClient.Builder is now generic over SerializableEppoConfiguration.
  3. Checked for required parameters in AndroidBaseClient.Builder.init
  4. Made CachingConfigurationStore and FiledBackedConfigStore generic over SerializableEppoConfiguration so that they can store any SerializableEppoConfiguration and not just Configuration.
    1. Added ConfigurationCodec.emptyConfiguration() so that CachingConfigurationStore to remove a Configuration dependency from CachingConfigurationStore
  5. Removed the type class from ConfigurationCodec.Default because ConfigurationCodec.Default depends on Jackson for parsing, so only Configuration makes sense to use with it.

How has this been documented?

Added javadoc

How has this been tested?

Ran unit and Android tests

@hbordersTwitch hbordersTwitch left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Some guidance for reviewers

MockitoAnnotations.openMocks(this);
}

private static class TestBuilder extends AndroidBaseClient.Builder<

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We must make an explicit class so that we can pass a class literal that captures the generic types we pass up to AndroidBaseClient.Builder. Then, all of our builder methods can downcast to TestBuilder properly.

protected CachingConfigurationStore(
@NotNull ConfigurationCodec<Configuration> codec, @NotNull ByteStore byteStore) {
@NotNull ConfigurationCodec<ConfigurationType> codec, @NotNull ByteStore byteStore) {
this.configuration = codec.emptyConfiguration();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This allows us to use any SerializableEppoConfiguration, not just Configuration

* Generic equivalent to {@link Configuration#emptyConfig()}
* @return an empty Configuration.
*/
@NotNull ConfigurationType emptyConfiguration();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

For use in CachingConfigurationStore.init

this.configClass = configClass;
}

public static class Default implements ConfigurationCodec<Configuration> {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since Default depends on Jackson, consumers would only ever use Configuration here, so there's no point in adding generics. Other ConfigurationCodec implementations will not use Jackson.

private long pollingJitterMs;

@Nullable private static AndroidBaseClient<?> instance;
@Nullable private static AndroidBaseClient<?, ?, ?> instance;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This isn't really safe. Consumers probably won't have two different eppo instances with different generics in the same classpath, but if they do, this will cause ClassCastExceptions

private final Application application;
private final ConfigurationParser<JsonFlagType> configurationParser;
private final EppoConfigurationClient configurationClient;
protected final Class<SelfType> selfClass;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Made all of these protected so that a subclass can access them. This might not be necessary though.

// Optional parameters with defaults
@Nullable private String apiBaseUrl;
@Nullable private AssignmentLogger assignmentLogger;
@Nullable private CachingConfigurationStore configStore;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Made configStore required because we can't create a FileBackedConfigStore as a convenience anymore since we don't want to depend on Configuration

@NotNull ConfigurationParser<ConfigurationType, ConfigurationBuilderType, JsonFlagType> configurationParser,
@NotNull CachingConfigurationStore<ConfigurationType> configStore,
@NotNull EppoConfigurationClient configurationClient) {
if (selfClass == null) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

EppoClient.Builder checks for nulls in its build methods, so I thought it made sense to check for them also. It's better to check for final methods at the point of initialization rather than in the build methods tho. I didn't change the EppoClent.Builder behavior.

String sdkName = obfuscateConfig ? "android" : "android-debug";
String sdkVersion = BuildConfig.EPPO_VERSION;

if (configStore == null) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We can't created a FileBackedConfigStore in AndroidBaseClient anymore because we don't have a ConfigurationCodec, and we can't create a ConfigurationCode because it needs to be generic over SerializableEppoConfiguration

private AndroidBaseClient<JsonElement> client;
private AndroidBaseClient<Configuration, Configuration.Builder, JsonElement> client;

private class GsonAndroidBaseClientBuilder extends AndroidBaseClient.Builder<

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We must make an explicit class so that we can pass a class literal that captures the generic types we pass up to AndroidBaseClient.Builder. Then, all of our builder methods can downcast to GsonAndroidBaseClientBuilder properly.

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.

1 participant