Code Monkey home page Code Monkey logo

java-client's Introduction

Split Java SDK

Build Status

Overview

This SDK is designed to work with Split, the platform for controlled rollouts, serving features to your users via feature flags to manage your complete customer experience.

Twitter Follow

Compatibility

This SDK is compatible with Java 8 and higher.

Getting started

Below is a simple example that describes the instantiation and most basic usage of our SDK:

import io.split.client.SplitFactoryBuilder;
import io.split.client.SplitClient;

public  class App {

    public static void main() {
        SplitClientConfig config = SplitClientConfig.builder()
                .setBlockUntilReadyTimeout(10000)
                .build();
        SplitFactory splitFactory = SplitFactoryBuilder.build("YOUR_SDK_KEY", config);
        SplitClient client = splitFactory.client();
        try {
            client.blockUntilReady();
        } catch (TimeoutException | InterruptedException e) {
            // log & handle
        }

        String treatment = client.getTreatment("CUSTOMER_ID", "FEATURE_FLAG_NAME");
        if (treatment.equals("on")) {
            // Feature flag is enabled for this user!
        } else if (treatment.equals("off")) {
            // Feature flag is disabled for this user!
        } else {
            // Unable to perform evaluation.
        }
    }
}

Submitting issues

The Split team monitors all issues submitted to this issue tracker. We encourage you to use this issue tracker to submit any bug reports, feedback, and feature enhancements. We'll do our best to respond in a timely manner.

Contributing

Please see Contributors Guide to find all you need to submit a Pull Request (PR).

License

Licensed under the Apache License, Version 2.0. See: Apache License.

About Split

Split is the leading Feature Delivery Platform for engineering teams that want to confidently deploy features as fast as they can develop them. Split’s fine-grained management, real-time monitoring, and data-driven experimentation ensure that new features will improve the customer experience without breaking or degrading performance. Companies like Twilio, Salesforce, GoDaddy and WePay trust Split to power their feature delivery.

To learn more about Split, contact [email protected], or get started with feature flags for free at https://www.split.io/signup.

Split has built and maintains SDKs for:

For a comprehensive list of open source projects visit our Github page.

Learn more about Split:

Visit split.io/product for an overview of Split, or visit our documentation at help.split.io for more detailed information.

java-client's People

Contributors

adilaijaz avatar adilaijaz-split avatar chillaq avatar dependabot[bot] avatar github-actions[bot] avatar goldensun8891 avatar hjewkes avatar hpark-miovision avatar israphel avatar joshrosen avatar ldecheverz-split avatar mmelograno avatar mredolatti avatar nicozelaya avatar nmayorsplit avatar patricioe avatar sande avatar sanzmauro avatar senhorcastor avatar splitadricejas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

java-client's Issues

LocalhostSplitManager always returns null when getting a split by feature name.

When using a localhost split file and calling SplitManager.split("my-feature"), null is always returned. This is due to the containsKey(featureName) is doing an equals comparison between a String (parameter) and a SplitAndKey (the map key type) which can never be true.

if (!_splitAndKeyToTreatmentMap.containsKey(featureName)) {

Contents of local split.yaml

- my-feature:
    treatment: "on"
    config: "{\"desc\" : \"this applies only to ON treatment\"}"

It seems like the if condition should be using _splitToTreatmentsMap.contains(featureName) instead of _splitAndKeyToTreatmentMap.

Info message "Streaming service temporarily unavailable, working in polling mode" multiple times per hour

We have recently integrated the SplitClient for Java into our backend service and we regularly see the following info log statement 10 or more times per hour followed by a recovery after a few milliseconds (usually ~50 to 100 millis).

Since it is logged at info level, I'm wondering if this is expected/normal, or if there is some configuration we have missed that would help alleviate this other than changing the log level for SyncManager.

2022-12-19 16:48:32.234 INFO  13167 (SPLIT-PushStatusMonitor-0) [SyncManager]  Streaming service temporarily unavailable, working in polling mode.
2022-12-19 16:48:32.284 INFO  13167 (SPLIT-PushStatusMonitor-0) [SyncManager]  Streaming up and running.

We also occassionally see this output in the logs as well, but not as frequently.

2022-12-19 16:39:16.454 INFO  13119 (SPLIT-PushStatusMonitor-0) [SyncManager]  Retryable error in streaming subsystem. Switching to polling and retrying in 1000 seconds

This is the version we are using via maven

    <dependency>
      <groupId>io.split.client</groupId>
      <artifactId>java-client</artifactId>
      <version>4.6.0</version>
    </dependency>

YamlLocalhostSplitFile has incorrect logger name

The YamlLocalhostSplitFile class is logging with a logger called LegacyLocalhostSplitFile, which is misleading since the LegacyLocalhostSplitFile also uses a logger of that name. This causes confusing log statements that make it look like the code went down the path to read the legacy splitFile, when it actually was on the newer code path.

See

public class YamlLocalhostSplitFile extends AbstractLocalhostSplitFile {
private static final Logger _log = LoggerFactory.getLogger(LegacyLocalhostSplitFile.class);

SplitFactoryBuilder does not work in localhost test mode when explicitly configuring a yaml file.

With version 3.1.0 of the java-client it is no longer possible to use SplitFactoryBuilder.local(myTestFilePath)
Instead, a new SplitClientConfig instance must be passed to the local - static method. In our CD environment we have to be able to set the path for the local test file, because we cannot store a configuration file in the userhome during the test.
No client can be created with configured split.yaml, regardless of whether the path is configured absolute or relative with

SplitClientConfig.builder() .splitFile("Testsplits.yaml") .build();

The following error is written to the log:

java.io.FileNotFoundException: \C:\ieu\Projects\GITHUB\splitio\java-client\client\target\test-classes\split.yaml (The filename, directory name, or volume label syntax is incorrect) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at java.io.FileReader.<init>(FileReader.java:72) at io.split.client.YamlLocalhostSplitFile.readOnSplits(YamlLocalhostSplitFile.java:27) at io.split.client.LocalhostSplitFactory.<init>(LocalhostSplitFactory.java:46) at io.split.client.LocalhostSplitFactory.createLocalhostSplitFactory(LocalhostSplitFactory.java:32) at io.split.client.SplitFactoryBuilder.local(SplitFactoryBuilder.java:70) at io.split.client.SplitFactoryBuilderTest.localhostModeWithAbsolutePathYaml(SplitFactoryBuilderTest.java:44)

Test for reproducing the Exception:
`public class SplitFactoryBuilderTest {

@Test
public void localhostModeWithRelativePathYaml() throws IOException {

    //-- arrange

    //-- act
    SplitClientConfig clientConfig = SplitClientConfig.builder()
            .splitFile(SplitClientConfig.LOCALHOST_DEFAULT_FILE)
            .build();

    SplitFactory splitFactory = SplitFactoryBuilder.local(clientConfig);
    SplitClient client = splitFactory.client();

    //-- assert
    assertThat(client.getTreatment("user_a", "split_1"), is(equalTo("on")));
}

@Test
public void localhostModeWithAbsolutePathYaml() throws Exception {

    //-- arrange
    URL testTogglesUrl = getClass().getClassLoader().getResource(SplitClientConfig.LOCALHOST_DEFAULT_FILE);
    String absolutePath = Paths.get(testTogglesUrl.toURI()).toFile().getAbsolutePath();

    //-- act
    SplitClientConfig clientConfig = SplitClientConfig.builder()
            .splitFile(absolutePath)
            .build();

    SplitFactory splitFactory = SplitFactoryBuilder.local(clientConfig);
    SplitClient client = splitFactory.client();

    //-- assert
    assertThat(client.getTreatment("user_a", "split_1"), is(equalTo("on")));
}

}`

Java SDK proxy endpoint support fails on unexpected headers

If the split synchronizer proxy is behind an ALB then AWS responds with some standard set cookie headers, which causes the client to fail on the expires attribute.
split.org.apache.http.client.protocol.ResponseProcessCookies: Invalid cookie header: "Set-Cookie: AWSALB=<......>; Expires=Thu, 28 Feb 2019 17:47:59 GMT; Path=/". Invalid 'expires' attribute: Thu, 28 Feb 2019 17:47:59 GMT

Split IO Initialization error

Hi, I am facing below error while using Split with java. I have also installed split certificate in the cacerts file of JRE/JDK, but its still showing this issue. Need your immediate help.
Error: [SPLIT-Initialization-0] ERROR io.split.engine.experiments.SplitFetcherImp - RefreshableSplitFetcher failed: Problem fetching splitChanges: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

SplitClient in local mode permits invalid split names

SplitClient permits using split names that are considered invalid in split.io SAAS.
Can be reproduced by adding split name 1.0.0-feature in the yml file like this:
- 1.0.0-feature: treatment: "on"
And then you can build the SplitClient:
SplitClientConfig config = SplitClientConfig.builder() .splitFile("src/main/resources/split-file-config.yml").build();
This will be successful.
While trying to create a split with that name in split.io UI will produce an error like this:
"Please rename your split. Split names must start with a letter and can contain "-_ a-z A-Z 0-9"

How It should be:
One shouldn't be able to create a SplitClient with invalid split names in local mode through yml file.
An exception should be thrown.

I hit this issue by first using the local mode then migrated to using the networked mode.

Provide external ThreadFactoryBuilder/ThreadFactory

With the release of Java 19 and the preview of virtual threads, it would be nice to be able to provide a ThreadFactoryBuilder implementation so that applications that are using virtual threads could do so without adding a strong dependency with a preview feature.

Why would it be nice to have the capability?
The Split SDK creates a number of background threads for synchronization purposes. Since all the threads are daemon and they spend most of the time in WAITING or TIMED_WAITING, it would be a great use case for virtual threads instead of having several OS threads.

Attached a screenshot of a thread dump with an example

Screen Shot 2022-11-17 at 16 33 40

Thanks.

splitFile option doesn't support a resource from a jar

This works when the resource is loaded from the filesystem when running the app through the IDE, but it doesn't when the resource is loaded from a jar. I believe splitFile should support an URI to call new File(...) with a jar: URI.

val splitFile = javaClass.classLoader.getResource("split.yml")
val splitClientConfig = SplitClientConfig.builder()
        .splitFile(splitFile?.file)
        .build()

Something like this :

val splitFile = javaClass.classLoader.getResource("split.yml")
val splitClientConfig = SplitClientConfig.builder()
        .splitFile(splitFile?.toURI())
        .build()

Support redis integration for split synchronizer

Java SDK docs state: Java SDK can connect to the Split Synchronizer only in Proxy mode, as of now it does not support the Redis integration.

We're currently using redis synchronizer for other language sdk's - it would be helpful to avoid standing up proxy mode synchronizer.

Add changelog in the release notes page

Hi everyone,
any chance to include the changelogs when a new release is published? I struggle to understand if there are breaking changes between minor bumps or figure out if a patch is worth upgrading the whole codebase (we use split in a microservice architecture).

Thank you very much in advance.

Java-client logs null pointer exception

java-client sees the following issue in version: 4.2.1:

java.lang.NullPointerException: null
    at io.split.telemetry.storage.InMemoryTelemetryStorage.recordLatency(InMemoryTelemetryStorage.java:111)
    at io.split.client.SplitClientImpl.track(SplitClientImpl.java:179)
    at io.split.client.SplitClientImpl.track(SplitClientImpl.java:128)

version: 4.2.1(latest)

library works as expected but the log has potential to cause unnecessary noise.

Shaded and non-shaded jars

Have you considered offering a non-shaded version of your library? Some people (including myself) will prefer that to the shaded version.
Should be simpler to build/maintain than the shaded version.

An error message is logged every second when startup of split client fails

We are currently adding split.io to one of our backend services, but we don't have the API key yet, so we added a dummy value.
Upon startup of the container, we observed a huge amount of error logs like this:

RefreshableSplitFetcher failed: Problem fetching splitChanges: Could not retrieve splitChanges; http return code 400

This log message is repeated every second (causing quota issues with our logging solution).
We assume that the problematic place in the code is in SyncManagerImp.start(), where upon receiving any exception, there is only a sleep of 1000ms and then a retry is performed.

The expected behavior would be to have some kind of exponential backoff in place, so that ever if Split.io is down or returns an error, our services can start up without producing tons of error logs.

Thx for having a look!

Connection timeout issue in io.split.client:java-client:4.2.1

We're using the 4.2.1 version of split.io and we have received network connectivity issues which are related to SDK. I am adding logs here for the reference:

RefreshableSplitFetcher failed: Problem fetching splitChanges: Connect to []() [] failed: connect timed out

Unrecoverable error in streaming subsystem. SDK will work in polling-mode and will not retry an SSE connection.

SDK client.destroy() does not stops all threads

I tried to use splio.io and used an invalid API key, say testKeyXYZ, I get a timeout exception which is understandable. When I try to call client.destroy() in the catch block, it calls split shutdown and the services but I keep getting the following logs in the console which I don't want.

io.split.engine.experiments.SplitFetcherImp : RefreshableSplitFetcher failed: Problem fetching splitChanges: Connection pool shut down

I tried to call destroy() on the factory as well but logs still keep on coming. Is there anything else I am missing?

Deadlock issue when tracking impressions

We have a high throughput Spring-based web application that frequently encounters a deadlock scenario in the Split SDK, ultimately requiring restarting the web application to resolve.

Specifically, all threads get stuck with the following stack trace:

deployment.redrock.ear//io.split.client.impressions.UniqueKeysTrackerImp.track(UniqueKeysTrackerImp.java:59)
deployment.redrock.ear//io.split.client.impressions.strategy.ProcessImpressionNone.process(ProcessImpressionNone.java:28)
deployment.redrock.ear//io.split.client.impressions.ImpressionsManagerImpl.track(ImpressionsManagerImpl.java:116)
deployment.redrock.ear//io.split.client.SplitClientImpl.recordStats(SplitClientImpl.java:342)
deployment.redrock.ear//io.split.client.SplitClientImpl.getTreatmentWithConfigInternal(SplitClientImpl.java:258)
deployment.redrock.ear//io.split.client.SplitClientImpl.getTreatmentWithConfig(SplitClientImpl.java:99)

We encountered this a few months before and decided to switch to use None as our impressionsMode assuming that would solve the issue (we don't care about impressions anyway). However, digging into the code it appears the ProcessImpressionsNone.java still uses the UniqueKeysTracker which is backed by a ConcurrentHashMap, ultimately deadlocking on the call to put.

To solve this issue, could we this issue be resolved in one of the two following ways:

  1. Provide us with a true "no-op" impressions tracker that disables handling impressions entirely (e.g. the process method is empty)
  2. Fix the deadlock issue within the UniqueKeysTracker - either by not using a ConcurrentHashMap or wrap the put call on the ConcurrentHashMap with some kind of timeout?

As mentioned, impressions are not incredibly important to us and the application not deadlocking is our biggest goal.

For what its worth, we are using version 4.7.0 of the client and looking at the changes since then I do not see any changes that would lead me to believe this issue has been addressed in the latest version (4.11.0).

SplitCacheConsumer.get returns a different treatment default value on 4.7.1 than 4.7.0

Hi, I am working on upgrading to 4.7.1, but one of my unit tests in my build pipeline keeps failing due to the default value being returned for the treatment is different than expected.

In our unit tests, we load mock treatments in yaml in this format:

- Treatment1:
    treatment: "on"
    keys: ["key1", "key2"]

Our failing unit test calls a function that gets the treatment value using this logic:

splitClient.getTreatment(key, featureName);

where key is key3 and featureName is Treatment1.

Digging into the java-client source for getTreatment with a debugger, I found that the treatment result is gotten from this line of code:

EvaluatorImp.TreatmentLabelAndChangeNumber result = this._evaluator.evaluateFeature(matchingKey, bucketingKey, split, attributes);

Which calls EvaluateFeature to get the cache value from SplitCacheConsumer and then uses that to get the treatment value.

When getting the treatment value, it realizes that key3 is not in the ParsedCondition if key is in segment ["key1","key3"] then split 100:on,0:null and returns the default value here: https://github.com/splitio/java-client/blob/master/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java#L104

The issue is that in version 4.7.0 the defaultTreatment gotten from SplitCacheConsumer is control while the defaultTreatment on 4.7.1 is "on".

4.7.0:
Screen Shot 2023-05-01 at 4 28 43 PM

4.7.1:
Screen Shot 2023-05-01 at 4 21 29 PM

Currently, our codebase assumes when the key is not in the set of keys for a Treatment, then the flag is considered off. Do we need to update our code/treatment config to reflect this for the new update, or is this a bug?

SplitFactoryBuilder not working in localhost mode

I see that this error is fixed but I actually have a similar issue while trying to use split.io in localhost mode. When I try to load the file based on the solution provided above I keep getting the error below.

2019-09-06 09:08:04 INFO [main] LocalhostSplitFactory:39 Starting Split in localhost mode with file at /Users/madhurmehta/Desktop/repo/deejay/deejay-ecommerce-library/out/test/resources/config/split_io_localhost.yaml

java.lang.UnsupportedOperationException: Modifier not supported

at sun.nio.fs.PollingWatchService.register(PollingWatchService.java:112)
at sun.nio.fs.UnixPath.register(UnixPath.java:897)
at io.split.client.AbstractLocalhostSplitFile.registerWatcher(AbstractLocalhostSplitFile.java:54)
at io.split.client.LocalhostSplitFactory.<init>(LocalhostSplitFactory.java:50)
at io.split.client.LocalhostSplitFactory.createLocalhostSplitFactory(LocalhostSplitFactory.java:32)
at io.split.client.SplitFactoryBuilder.local(SplitFactoryBuilder.java:70)
at com.deliverr.deejay.ecommerce.commands.ProcessOrderCreateCommandTest.setUp(ProcessOrderCreateCommandTest.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.MethodRoadie.runBefores(MethodRoadie.java:133)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)`

Below is the code that I added to get SplitClient working

URL splitFileURL = getClass().getClassLoader().getResource("./config/split_io_localhost.yaml");
  assert splitFileURL != null;
  String splitFilePath = Paths.get(splitFileURL.toURI()).toFile().getAbsolutePath();
  SplitClientConfig splitClientConfig = SplitClientConfig.builder().splitFile(splitFilePath).build();
  SplitFactory splitFactory = SplitFactoryBuilder.local(splitClientConfig);
  this.splitClient = splitFactory.client();```

Any help at this point will be really appreciated.

The Yaml file looks like this

`- my_feature:`
`      treatment: "on"`
`      keys: ["abc", "1234"]`

Logs are not being generated correctly

Hi all,

Java Client is generating some logs without details e.g.

Example 1: Pipeline

 WARN [main] (SplitClientImpl.java:252) - %s: you passed "foo" that does not exist in this environment, please double check what Splits exist in the web console.

Example 2: Pipeline

ERROR [main] (SplitClientImpl.java:303) - %s: split_names must be a non-empty array

As you can see, there is a %s.

java-client has several dependencies missed by shade plugin

The pom file for java-client 4.2.1 has several dependencies (see snippet below) that have not been included & relocated in the uber-jar, which caused some dependency headaches for us.

I've created a rough PR in #240 that shades all dependencies except for slf4j-api, which I honestly didn't know whether it makes sense to shade or not.

  <dependencies>
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>failureaccess</artifactId>
      <version>1.0.1</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>listenablefuture</artifactId>
      <version>9999.0-empty-to-avoid-conflict-with-guava</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.google.code.findbugs</groupId>
      <artifactId>jsr305</artifactId>
      <version>3.0.2</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.checkerframework</groupId>
      <artifactId>checker-qual</artifactId>
      <version>3.5.0</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.google.errorprone</groupId>
      <artifactId>error_prone_annotations</artifactId>
      <version>2.3.4</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.google.j2objc</groupId>
      <artifactId>j2objc-annotations</artifactId>
      <version>1.3</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.25</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.httpcomponents.client5</groupId>
      <artifactId>httpclient5</artifactId>
      <version>5.0.3</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.httpcomponents.core5</groupId>
      <artifactId>httpcore5</artifactId>
      <version>5.0.2</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.httpcomponents.core5</groupId>
      <artifactId>httpcore5-h2</artifactId>
      <version>5.0.2</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>1.13</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.yaml</groupId>
      <artifactId>snakeyaml</artifactId>
      <version>1.21</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

Alternative for AlwaysReturnControlSplitClient in v4.4.4

I have upgraded the io.split.client:java-client to v4.4.4 and I am facing this import issue (AlwaysReturnControlSplitClient) what's the alternative for the same

Screenshot 2023-03-28 at 7 56 58 AM

Note: i could not get much with google searches and documentation, but what i got to know is this has been removed in one of the PR

I also tried alternatives based on the below PR link and i could not succeed as well

#278

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.