diff --git a/CHANGES.txt b/CHANGES.txt
index ff03376f7..8973780ef 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,7 @@
+4.18.2 (Oct 15, 2025)
+- Fixed an issue where Manager.splitNames() return incorrect formatted result using redis storage and no custom prefix.
+- Added using String only parameter for treatments in FallbackTreatmentConfiguration class.
+
4.18.1 (Sep 30, 2025)
- Fixed an issue where Streaming client hangs during token renew process.
diff --git a/client/pom.xml b/client/pom.xml
index 93bb93ee4..198f80a3d 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -5,9 +5,9 @@
io.split.client
java-client-parent
- 4.18.1
+ 4.18.2
- 4.18.1
+ 4.18.2
java-client
jar
Java Client
diff --git a/client/src/main/java/io/split/client/dtos/FallbackTreatmentsConfiguration.java b/client/src/main/java/io/split/client/dtos/FallbackTreatmentsConfiguration.java
index aa47d1163..55a0a27d1 100644
--- a/client/src/main/java/io/split/client/dtos/FallbackTreatmentsConfiguration.java
+++ b/client/src/main/java/io/split/client/dtos/FallbackTreatmentsConfiguration.java
@@ -1,5 +1,6 @@
package io.split.client.dtos;
+import java.util.HashMap;
import java.util.Map;
public class FallbackTreatmentsConfiguration {
@@ -11,9 +12,54 @@ public FallbackTreatmentsConfiguration(FallbackTreatment globalFallbackTreatment
_byFlagFallbackTreatment = byFlagFallbackTreatment;
}
+ public FallbackTreatmentsConfiguration(Map byFlagFallbackTreatment) {
+ _globalFallbackTreatment = null;
+ _byFlagFallbackTreatment = byFlagFallbackTreatment;
+ }
+
+ public FallbackTreatmentsConfiguration(HashMap byFlagFallbackTreatment) {
+ _globalFallbackTreatment = null;
+ _byFlagFallbackTreatment = buildByFlagFallbackTreatment(byFlagFallbackTreatment);
+ }
+
+ public FallbackTreatmentsConfiguration(FallbackTreatment globalFallbackTreatment) {
+ _globalFallbackTreatment = globalFallbackTreatment;
+ _byFlagFallbackTreatment = null;
+ }
+
+ public FallbackTreatmentsConfiguration(String globalFallbackTreatment, Map byFlagFallbackTreatment) {
+ _globalFallbackTreatment = new FallbackTreatment(globalFallbackTreatment);
+ _byFlagFallbackTreatment = byFlagFallbackTreatment;
+ }
+
+ public FallbackTreatmentsConfiguration(String globalFallbackTreatment) {
+ _globalFallbackTreatment = new FallbackTreatment(globalFallbackTreatment);
+ _byFlagFallbackTreatment = null;
+ }
+
+
+ public FallbackTreatmentsConfiguration(String globalFallbackTreatment, HashMap byFlagFallbackTreatment) {
+ _globalFallbackTreatment = new FallbackTreatment(globalFallbackTreatment);
+ _byFlagFallbackTreatment = buildByFlagFallbackTreatment(byFlagFallbackTreatment);
+ }
+
+ public FallbackTreatmentsConfiguration(FallbackTreatment globalFallbackTreatment, HashMap byFlagFallbackTreatment) {
+ _globalFallbackTreatment = globalFallbackTreatment;
+ _byFlagFallbackTreatment = buildByFlagFallbackTreatment(byFlagFallbackTreatment);
+ }
+
public FallbackTreatment getGlobalFallbackTreatment() {
return _globalFallbackTreatment;
}
public Map getByFlagFallbackTreatment() { return _byFlagFallbackTreatment;}
+
+ private Map buildByFlagFallbackTreatment(Map byFlagFallbackTreatment) {
+ Map result = new HashMap<>();
+ for (Map.Entry entry : byFlagFallbackTreatment.entrySet()) {
+ result.put(entry.getKey(), new FallbackTreatment(entry.getValue()));
+ }
+
+ return result;
+ }
}
diff --git a/client/src/main/java/io/split/engine/experiments/SplitFetcherImp.java b/client/src/main/java/io/split/engine/experiments/SplitFetcherImp.java
index a2d8681db..30d374cdf 100644
--- a/client/src/main/java/io/split/engine/experiments/SplitFetcherImp.java
+++ b/client/src/main/java/io/split/engine/experiments/SplitFetcherImp.java
@@ -100,7 +100,7 @@ public FetchResult forceRefresh(FetchOptions options) {
Thread.currentThread().interrupt();
return new FetchResult(false, true, new HashSet<>());
} catch (Exception e) {
- _log.error("RefreshableSplitFetcher failed: " + e.getMessage());
+ _log.error("SplitFetcherImp failed: " + e.getMessage());
if (_log.isDebugEnabled()) {
_log.debug("Reason:", e);
}
@@ -166,4 +166,4 @@ private Set runWithoutExceptionHandling(FetchOptions options) throws Int
return segments;
}
-}
\ No newline at end of file
+}
diff --git a/client/src/test/java/io/split/client/JsonLocalhostSplitFactoryTest.java b/client/src/test/java/io/split/client/JsonLocalhostSplitFactoryTest.java
index 1152615a2..2df64c08a 100644
--- a/client/src/test/java/io/split/client/JsonLocalhostSplitFactoryTest.java
+++ b/client/src/test/java/io/split/client/JsonLocalhostSplitFactoryTest.java
@@ -1,5 +1,7 @@
package io.split.client;
+import io.split.client.dtos.FallbackTreatment;
+import io.split.client.dtos.FallbackTreatmentsConfiguration;
import org.junit.Assert;
import org.junit.Test;
@@ -12,10 +14,14 @@ public class JsonLocalhostSplitFactoryTest {
@Test
public void works() throws IOException, URISyntaxException, InterruptedException, TimeoutException {
+ FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global"),
+ new HashMap() {{ put("feature", new FallbackTreatment("off-local", "{\"prop2\", \"val2\"}")); }});
+
SplitClientConfig config = SplitClientConfig.builder()
.splitFile("src/test/resources/splits_localhost.json")
.segmentDirectory("src/test/resources")
.setBlockUntilReadyTimeout(10000)
+ .fallbackTreatments(fallbackTreatmentsConfiguration)
.build();
SplitFactory splitFactory = SplitFactoryBuilder.build("localhost", config);
SplitClient client = splitFactory.client();
@@ -30,6 +36,9 @@ public void works() throws IOException, URISyntaxException, InterruptedException
Assert.assertEquals("off", client.getTreatment("bilal", "test_split"));
Assert.assertEquals("on", client.getTreatment("bilal", "push_test"));
Assert.assertEquals("on_whitelist", client.getTreatment("admin", "push_test"));
+ Assert.assertEquals("off-local", client.getTreatment("bilal", "feature"));
+ Assert.assertEquals("on-global", client.getTreatment("bilal", "feature2"));
+
client.destroy();
}
diff --git a/client/src/test/java/io/split/client/LocalhostSplitFactoryTest.java b/client/src/test/java/io/split/client/LocalhostSplitFactoryTest.java
index 8c4ad4e0c..983bf4cc4 100644
--- a/client/src/test/java/io/split/client/LocalhostSplitFactoryTest.java
+++ b/client/src/test/java/io/split/client/LocalhostSplitFactoryTest.java
@@ -1,8 +1,11 @@
package io.split.client;
import com.google.common.collect.Maps;
+import io.split.client.dtos.FallbackTreatment;
+import io.split.client.dtos.FallbackTreatmentsConfiguration;
import io.split.client.utils.LocalhostUtils;
import io.split.grammar.Treatments;
+import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -10,6 +13,7 @@
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
+import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
@@ -35,7 +39,9 @@ public void works() throws IOException, URISyntaxException, InterruptedException
LocalhostUtils.writeFile(file, map);
- SplitClientConfig config = SplitClientConfig.builder().splitFile(folder.getRoot().getAbsolutePath()).build();
+ SplitClientConfig config = SplitClientConfig.builder()
+ .splitFile(folder.getRoot().getAbsolutePath())
+ .build();
SplitFactory splitFactory = SplitFactoryBuilder.build("localhost", config);
SplitClient client = splitFactory.client();
@@ -48,4 +54,30 @@ public void works() throws IOException, URISyntaxException, InterruptedException
assertEquals("a", client.getTreatment("user1", "test"));
assertEquals("a", client.getTreatment("user2", "test"));
}
+
+ @Test
+ public void testFallbackTreatments() throws IOException, URISyntaxException, InterruptedException {
+ File file = folder.newFile(LegacyLocalhostSplitChangeFetcher.FILENAME);
+
+ Map map = Maps.newHashMap();
+ map.put(SplitAndKey.of("onboarding"), LocalhostSplit.of("on"));
+ map.put(SplitAndKey.of("onboarding", "user1"), LocalhostSplit.of("off"));
+ map.put(SplitAndKey.of("onboarding", "user2"), LocalhostSplit.of("off"));
+ map.put(SplitAndKey.of("test"), LocalhostSplit.of("a"));
+
+ LocalhostUtils.writeFile(file, map);
+
+ FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global"),
+ new HashMap() {{ put("feature", new FallbackTreatment("off-local", "{\"prop2\", \"val2\"}")); }});
+
+ SplitClientConfig config = SplitClientConfig.builder()
+ .splitFile(folder.getRoot().getAbsolutePath())
+ .fallbackTreatments(fallbackTreatmentsConfiguration)
+ .build();
+ SplitFactory splitFactory = SplitFactoryBuilder.build("localhost", config);
+ SplitClient client = splitFactory.client();
+
+ assertEquals("off-local", client.getTreatment("user1", "feature"));
+ assertEquals("on-global", client.getTreatment("user1", "feature2"));
+ }
}
\ No newline at end of file
diff --git a/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlTest.java b/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlTest.java
index abcc551fe..989da1a1e 100644
--- a/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlTest.java
+++ b/client/src/test/java/io/split/client/LocalhostSplitFactoryYamlTest.java
@@ -1,5 +1,7 @@
package io.split.client;
+import io.split.client.dtos.FallbackTreatment;
+import io.split.client.dtos.FallbackTreatmentsConfiguration;
import io.split.client.utils.LocalhostUtils;
import io.split.grammar.Treatments;
import org.junit.Rule;
@@ -11,10 +13,7 @@
import java.io.IOException;
import java.io.StringWriter;
import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@@ -106,4 +105,59 @@ public void works() throws IOException, URISyntaxException {
// unchanged
assertThat(client.getTreatment("user_b", "split_1"), is(equalTo("on")));
}
+
+ @Test
+ public void testFallbackTreatment() throws IOException, URISyntaxException {
+ File file = folder.newFile(SplitClientConfig.LOCALHOST_DEFAULT_FILE);
+
+ List