diff --git a/.github/workflows/master-2.yml b/.github/workflows/master-2.yml
index b94ab7f..1f64f7f 100644
--- a/.github/workflows/master-2.yml
+++ b/.github/workflows/master-2.yml
@@ -9,7 +9,7 @@ on:
jobs:
build-scan:
name: SonarCloud Scan
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
@@ -35,7 +35,7 @@ jobs:
fail-fast: false
matrix:
java: ['11', '17', '21']
- os: [ubuntu-latest, windows-latest]
+ os: [ubuntu-22.04, windows-latest]
runs-on: ${{ matrix.os }}
steps:
diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index c8000c7..1e282a1 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -9,7 +9,7 @@ on:
jobs:
build-scan:
name: SonarCloud Scan
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
@@ -35,7 +35,7 @@ jobs:
fail-fast: false
matrix:
java: ['8', '11', '17', '21']
- os: [ubuntu-latest, windows-latest]
+ os: [ubuntu-22.04, windows-latest]
runs-on: ${{ matrix.os }}
steps:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0ee87e7..f0dc27d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -11,7 +11,7 @@ jobs:
fail-fast: false
matrix:
java: ['11', '17', '21']
- os: [ubuntu-latest, windows-latest]
+ os: [ubuntu-22.04, windows-latest]
runs-on: ${{ matrix.os }}
steps:
@@ -39,7 +39,7 @@ jobs:
publish:
name: Publish Release
needs: [build-test]
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml
index db54d6e..2f67530 100644
--- a/.github/workflows/sonar.yml
+++ b/.github/workflows/sonar.yml
@@ -11,7 +11,7 @@ on:
jobs:
sonar-analysis:
name: SonarCloud Analysis for PR
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- name: Get PR details
diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml
index 9e8bccf..a48d1fd 100644
--- a/.github/workflows/staging.yml
+++ b/.github/workflows/staging.yml
@@ -9,7 +9,7 @@ on:
required: true
default: '17'
os:
- description: 'Operating System (ubuntu-20.04, ubuntu-latest, windows-latest)'
+ description: 'Operating System (ubuntu-22.04, ubuntu-latest, windows-latest)'
required: true
default: 'ubuntu-latest'
diff --git a/pom.xml b/pom.xml
index 1bbb0aa..a87ab88 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
com.switcherapi
switcher-client
jar
- 2.4.0
+ 2.4.1-SNAPSHOT
Switcher Client
Switcher Client SDK for working with Switcher API
diff --git a/src/main/java/com/switcherapi/client/model/Entry.java b/src/main/java/com/switcherapi/client/model/Entry.java
index 56d8e29..ba3f38a 100644
--- a/src/main/java/com/switcherapi/client/model/Entry.java
+++ b/src/main/java/com/switcherapi/client/model/Entry.java
@@ -11,27 +11,29 @@ public class Entry {
private final String strategy;
private final String input;
-
- private Entry(final String strategy, final String input) {
+
+ public Entry(String strategy, String input) {
this.strategy = strategy;
this.input = input;
}
-
- private Entry(final StrategyValidator strategy, final String input) {
+
+ public Entry(StrategyValidator strategy, String input) {
this(strategy.toString(), input);
}
/**
+ * Creates a new Entry with the given strategy and input.
+ *
* @param strategy Validator used to evaluate the Switcher
* @param input follow the required format documented into each strategy type
* @return new Entry
* @see StrategyValidator
*/
- public static Entry build(final StrategyValidator strategy, final String input) {
+ public static Entry of(StrategyValidator strategy, String input) {
return new Entry(strategy, input);
}
-
- public static Entry build(final String strategy, final String input) {
+
+ public static Entry of(String strategy, String input) {
return new Entry(strategy, input);
}
diff --git a/src/main/java/com/switcherapi/client/model/SwitcherBuilder.java b/src/main/java/com/switcherapi/client/model/SwitcherBuilder.java
index 7dd36ba..a7d393c 100644
--- a/src/main/java/com/switcherapi/client/model/SwitcherBuilder.java
+++ b/src/main/java/com/switcherapi/client/model/SwitcherBuilder.java
@@ -95,7 +95,7 @@ public SwitcherBuilder restrictRelay(boolean restrictRelay) {
*/
public SwitcherBuilder check(StrategyValidator strategy, String input) {
if (StringUtils.isNotBlank(input)) {
- entry.add(Entry.build(strategy, input));
+ entry.add(Entry.of(strategy, input));
}
return this;
diff --git a/src/main/resources/META-INF/native-image/com.switcherapi/switcher-client/reflect-config.json b/src/main/resources/META-INF/native-image/com.switcherapi/switcher-client/reflect-config.json
index 700b356..a66c838 100644
--- a/src/main/resources/META-INF/native-image/com.switcherapi/switcher-client/reflect-config.json
+++ b/src/main/resources/META-INF/native-image/com.switcherapi/switcher-client/reflect-config.json
@@ -8,7 +8,10 @@
"methods": [
{
"name": "",
- "parameterTypes": []
+ "parameterTypes": [
+ "java.lang.String",
+ "java.lang.String"
+ ]
}
]
},
@@ -21,7 +24,9 @@
"methods": [
{
"name": "",
- "parameterTypes": []
+ "parameterTypes": [
+ "com.switcherapi.client.model.Entry[]"
+ ]
}
]
},
@@ -34,7 +39,14 @@
"methods": [
{
"name": "",
- "parameterTypes": []
+ "parameterTypes": [
+ "java.lang.String",
+ "java.lang.String",
+ "boolean",
+ "com.switcherapi.client.model.criteria.StrategyConfig[]",
+ "java.lang.String[]",
+ "com.switcherapi.client.model.criteria.Relay"
+ ]
}
]
},
@@ -73,7 +85,12 @@
"methods": [
{
"name": "",
- "parameterTypes": []
+ "parameterTypes": [
+ "java.lang.String",
+ "java.lang.String",
+ "boolean",
+ "com.switcherapi.client.model.criteria.Config[]"
+ ]
}
]
},
@@ -99,7 +116,29 @@
"methods": [
{
"name": "",
- "parameterTypes": []
+ "parameterTypes": [
+ "java.lang.String",
+ "java.lang.String",
+ "java.lang.String",
+ "boolean",
+ "java.lang.String[]"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "com.switcherapi.client.model.criteria.Relay",
+ "condition": {
+ "typeReachable": "com.switcherapi.client.model.criteria.Snapshot"
+ },
+ "allDeclaredFields": true,
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.String",
+ "boolean"
+ ]
}
]
},
diff --git a/src/test/java/com/switcherapi/client/SwitcherLocal1Test.java b/src/test/java/com/switcherapi/client/SwitcherLocal1Test.java
index a9b5d8e..9c5f184 100644
--- a/src/test/java/com/switcherapi/client/SwitcherLocal1Test.java
+++ b/src/test/java/com/switcherapi/client/SwitcherLocal1Test.java
@@ -115,7 +115,7 @@ static Stream dateTestArguments() {
@MethodSource("dateTestArguments")
void localShouldTest_dateValidation(String useCaseKey, String input, boolean expected) {
SwitcherRequest switcher = Switchers.getSwitcher(useCaseKey);
- Entry entry = Entry.build(StrategyValidator.DATE, input);
+ Entry entry = Entry.of(StrategyValidator.DATE, input);
assertEquals(expected, switcher.prepareEntry(entry).isItOn());
}
@@ -130,7 +130,7 @@ void localShouldTestChained_dateValidation(String useCaseKey, String input, bool
@Test
void localShouldReturnFalse_dateValidationWrongFormat() {
SwitcherRequest switcher = Switchers.getSwitcher(Switchers.USECASE33);
- Entry input = Entry.build(StrategyValidator.DATE, "2019/121/13");
+ Entry input = Entry.of(StrategyValidator.DATE, "2019/121/13");
switcher.prepareEntry(input);
assertThrows(SwitcherInvalidTimeFormat.class, switcher::isItOn);
@@ -157,7 +157,7 @@ static Stream valueTestArguments() {
@MethodSource("valueTestArguments")
void localShouldTest_valueValidation(String useCaseKey, String input, boolean expected) {
SwitcherRequest switcher = Switchers.getSwitcher(useCaseKey);
- Entry entry = Entry.build(StrategyValidator.VALUE, input);
+ Entry entry = Entry.of(StrategyValidator.VALUE, input);
switcher.prepareEntry(entry);
assertEquals(expected, switcher.isItOn());
@@ -198,7 +198,7 @@ static Stream numericTestArguments() {
@MethodSource("numericTestArguments")
void localShouldTest_numericValidation(String useCaseKey, String input, boolean expected) {
SwitcherRequest switcher = Switchers.getSwitcher(useCaseKey);
- Entry entry = Entry.build(StrategyValidator.NUMERIC, input);
+ Entry entry = Entry.of(StrategyValidator.NUMERIC, input);
switcher.prepareEntry(entry);
assertEquals(expected, switcher.isItOn());
@@ -215,7 +215,7 @@ void localShouldTestChained_numericValidation(String useCaseKey, String input, b
@Test
void localShouldReturnException_invalidNumericInput() {
SwitcherRequest switcher = Switchers.getSwitcher(Switchers.USECASE81);
- Entry input = Entry.build(StrategyValidator.NUMERIC, "INVALID_NUMBER");
+ Entry input = Entry.of(StrategyValidator.NUMERIC, "INVALID_NUMBER");
switcher.prepareEntry(input);
assertThrows(SwitcherInvalidNumericFormat.class, switcher::isItOn);
@@ -239,7 +239,7 @@ static Stream timeTestArguments() {
@MethodSource("timeTestArguments")
void localShouldTest_timeValidation(String useCaseKey, String input, boolean expected) {
SwitcherRequest switcher = Switchers.getSwitcher(useCaseKey);
- Entry entry = Entry.build(StrategyValidator.TIME, input);
+ Entry entry = Entry.of(StrategyValidator.TIME, input);
switcher.prepareEntry(entry);
assertEquals(expected, switcher.isItOn());
@@ -255,7 +255,7 @@ void localShouldTestChained_timeValidation(String useCaseKey, String input, bool
@Test
void localShouldReturnFalse_timeValidationWrongFormat() {
SwitcherRequest switcher = Switchers.getSwitcher(Switchers.USECASE53);
- Entry input = Entry.build(StrategyValidator.TIME, "2019-12-10");
+ Entry input = Entry.of(StrategyValidator.TIME, "2019-12-10");
switcher.prepareEntry(input);
assertThrows(SwitcherInvalidTimeFormat.class, switcher::isItOn);
@@ -279,7 +279,7 @@ static Stream networkTestArguments() {
@MethodSource("networkTestArguments")
void localShouldTest_networkValidation(String useCaseKey, String input, boolean expected) {
SwitcherRequest switcher = Switchers.getSwitcher(useCaseKey);
- Entry entry = Entry.build(StrategyValidator.NETWORK, input);
+ Entry entry = Entry.of(StrategyValidator.NETWORK, input);
switcher.prepareEntry(entry);
assertEquals(expected, switcher.isItOn());
@@ -301,7 +301,7 @@ void localShouldReturnFalse_strategyRequiresInput() {
@Test
void localShouldReturnFalse_invalidStrategyInput() {
SwitcherRequest switcher = Switchers.getSwitcher(Switchers.USECASE33);
- switcher.prepareEntry(Entry.build(StrategyValidator.INVALID, "Value"));
+ switcher.prepareEntry(Entry.of(StrategyValidator.INVALID, "Value"));
assertFalse(switcher.isItOn());
}
@@ -328,7 +328,7 @@ static Stream regexTestArguments() {
@MethodSource("regexTestArguments")
void localShouldTest_regexValidation(String useCaseKey, String input, boolean expected) {
SwitcherRequest switcher = Switchers.getSwitcher(useCaseKey);
- Entry entry = Entry.build(StrategyValidator.REGEX, input);
+ Entry entry = Entry.of(StrategyValidator.REGEX, input);
switcher.prepareEntry(entry);
assertEquals(expected, switcher.isItOn());
@@ -357,7 +357,7 @@ static Stream payloadTestArguments() {
@MethodSource("payloadTestArguments")
void localShouldTest_payloadValidation(String useCaseKey, String input, boolean expected) {
SwitcherRequest switcher = Switchers.getSwitcher(useCaseKey);
- Entry entry = Entry.build(StrategyValidator.PAYLOAD, input);
+ Entry entry = Entry.of(StrategyValidator.PAYLOAD, input);
switcher.prepareEntry(entry);
assertEquals(expected, switcher.isItOn());
diff --git a/src/test/java/com/switcherapi/client/SwitcherLocal3Test.java b/src/test/java/com/switcherapi/client/SwitcherLocal3Test.java
index a0c2bd5..52a23a1 100644
--- a/src/test/java/com/switcherapi/client/SwitcherLocal3Test.java
+++ b/src/test/java/com/switcherapi/client/SwitcherLocal3Test.java
@@ -79,7 +79,7 @@ static Stream failTestArguments() {
void localShouldReturnError(String useCaseKey, String strategyValidator,
String input, Class error) {
SwitcherRequest switcher = Switchers.getSwitcher(useCaseKey);
- switcher.prepareEntry(Entry.build(strategyValidator, input));
+ switcher.prepareEntry(Entry.of(strategyValidator, input));
assertThrows(error, switcher::isItOn);
}
diff --git a/src/test/java/com/switcherapi/client/model/ModelTest.java b/src/test/java/com/switcherapi/client/model/ModelTest.java
index 923a0e3..01ac7de 100644
--- a/src/test/java/com/switcherapi/client/model/ModelTest.java
+++ b/src/test/java/com/switcherapi/client/model/ModelTest.java
@@ -9,8 +9,8 @@ class ModelTest {
@Test
void testModelEntry() {
- Entry entry1 = Entry.build(StrategyValidator.DATE, "2019-12-10");
- Entry entry2 = Entry.build(StrategyValidator.VALUE, "Value");
+ Entry entry1 = Entry.of(StrategyValidator.DATE, "2019-12-10");
+ Entry entry2 = Entry.of(StrategyValidator.VALUE, "Value");
assertNotEquals(true, entry1.equals(entry2));
assertNotNull(entry1.toString());
diff --git a/src/test/java/metainf/nativeimage/NativeReflectConfigTest.java b/src/test/java/metainf/nativeimage/NativeReflectConfigTest.java
index d1b3e9a..dd7d2cf 100644
--- a/src/test/java/metainf/nativeimage/NativeReflectConfigTest.java
+++ b/src/test/java/metainf/nativeimage/NativeReflectConfigTest.java
@@ -4,6 +4,7 @@
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import java.lang.reflect.Array;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
@@ -38,8 +39,7 @@ void shouldApplyReflection() {
ReflectJson[] reflectJson = new Gson().fromJson(reflectContent, ReflectJson[].class);
for (ReflectJson json : reflectJson) {
- assertDoesNotThrow(() -> Class.forName(json.name),
- String.format("Class %s not reachable", json.name));
+ assertConstructorsReachable(json);
if (Objects.nonNull(json.condition)) {
assertDoesNotThrow(() -> Class.forName(json.condition.typeReachable),
@@ -48,12 +48,65 @@ void shouldApplyReflection() {
}
}
+ private void assertConstructorsReachable(ReflectJson json) {
+ if (Objects.nonNull(json.methods)) {
+ for (ReflectMethod method : json.methods) {
+ if ("".equals(method.name)) {
+ assertDoesNotThrow(() -> Class.forName(json.name).getDeclaredConstructor(getArgClasses(method.parameterTypes)),
+ String.format("Constructor (%s) not reachable in class %s",
+ String.join(", ", method.parameterTypes), json.name));
+ }
+ }
+ }
+ }
+
+ private Class>[] getArgClasses(String[] parameterTypes) throws ClassNotFoundException {
+ if (parameterTypes == null || parameterTypes.length == 0) {
+ return new Class>[0];
+ }
+
+ Class>[] classes = new Class>[parameterTypes.length];
+ for (int i = 0; i < parameterTypes.length; i++) {
+ String paramType = parameterTypes[i];
+ if (paramType.endsWith("[]")) {
+ String baseType = paramType.substring(0, paramType.length() - 2);
+ Class> baseClass = getPrimitiveOrClass(baseType);
+ classes[i] = Array.newInstance(baseClass, 0).getClass();
+ } else {
+ classes[i] = getPrimitiveOrClass(paramType);
+ }
+ }
+
+ return classes;
+ }
+
+ private Class> getPrimitiveOrClass(String typeName) throws ClassNotFoundException {
+ switch (typeName) {
+ case "boolean": return boolean.class;
+ case "byte": return byte.class;
+ case "char": return char.class;
+ case "short": return short.class;
+ case "int": return int.class;
+ case "long": return long.class;
+ case "float": return float.class;
+ case "double": return double.class;
+ case "void": return void.class;
+ default: return Class.forName(typeName);
+ }
+ }
+
static class ReflectJson {
String name;
ReflectCondition condition;
+ ReflectMethod[] methods;
}
static class ReflectCondition {
String typeReachable;
}
+
+ static class ReflectMethod {
+ String name;
+ String[] parameterTypes;
+ }
}