",
+ min == null ? "null" : min,
+ max == null ? "null" : max
+ );
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/OperationOptions.java b/src/main/java/com/regexsolver/api/OperationOptions.java
new file mode 100644
index 0000000..6f44003
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/OperationOptions.java
@@ -0,0 +1,78 @@
+package com.regexsolver.api;
+
+import java.util.Optional;
+
+/**
+ * Options for RegexSolver operations.
+ *
+ * Not every option is relevant to every operation: an option is ignored by any operation
+ * it does not apply to. For instance the options describing the returned term have no effect
+ * on an operation that does not return one.
+ */
+public class OperationOptions {
+
+ private Integer executionTimeout;
+ private ResponseFormat responseFormat;
+ private Boolean deterministic;
+
+ public OperationOptions() {}
+
+ public OperationOptions(
+ Integer executionTimeout,
+ ResponseFormat responseFormat
+ ) {
+ this.executionTimeout = executionTimeout;
+ this.responseFormat = responseFormat;
+ }
+
+ public static OperationOptions builder() {
+ return new OperationOptions();
+ }
+
+ /**
+ * Maximum time, in milliseconds, the engine may spend on the operation before aborting it.
+ *
+ * @param timeout the timeout in milliseconds
+ * @return these options
+ */
+ public OperationOptions executionTimeout(Integer timeout) {
+ this.executionTimeout = timeout;
+ return this;
+ }
+
+ /**
+ * Format of the term returned by the operation.
+ *
+ * @param format the requested response format
+ * @return these options
+ */
+ public OperationOptions responseFormat(ResponseFormat format) {
+ this.responseFormat = format;
+ return this;
+ }
+
+ /**
+ * When true, guarantees the returned FAIR encodes a deterministic automaton.
+ * Only valid with responseFormat = ResponseFormat.FAIR or when responseFormat is
+ * unset (in which case it defaults to ResponseFormat.FAIR). Throws otherwise.
+ *
+ * @param deterministic whether the returned FAIR must be deterministic
+ * @return these options
+ */
+ public OperationOptions deterministic(Boolean deterministic) {
+ this.deterministic = deterministic;
+ return this;
+ }
+
+ public Optional getExecutionTimeout() {
+ return Optional.ofNullable(executionTimeout);
+ }
+
+ public Optional getResponseFormat() {
+ return Optional.ofNullable(responseFormat);
+ }
+
+ public Optional getDeterministic() {
+ return Optional.ofNullable(deterministic);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/PathOrder.java b/src/main/java/com/regexsolver/api/PathOrder.java
new file mode 100644
index 0000000..ca88a81
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/PathOrder.java
@@ -0,0 +1,41 @@
+package com.regexsolver.api;
+
+import com.regexsolver.api.generated.model.GenerateStringsPathOrderDto;
+
+/**
+ * Order in which the paths of the language are scheduled when generating
+ * strings — the shapes the term allows, as opposed to the characters
+ * filling them.
+ */
+public enum PathOrder {
+ /**
+ * Expand one path in full, shortest first, before moving to the next one.
+ * The cheapest way to page through a whole language.
+ */
+ SWEEP,
+ /**
+ * Cover every path once before any path yields a second string. Best
+ * suited to deriving test cases.
+ */
+ INTERLEAVE,
+ /**
+ * Interleave with same-length paths visited in an order drawn from the
+ * seed.
+ */
+ SHUFFLED;
+
+ GenerateStringsPathOrderDto toDto() {
+ switch (this) {
+ case SWEEP:
+ return GenerateStringsPathOrderDto.SWEEP;
+ case INTERLEAVE:
+ return GenerateStringsPathOrderDto.INTERLEAVE;
+ case SHUFFLED:
+ return GenerateStringsPathOrderDto.SHUFFLED;
+ default:
+ throw new IllegalArgumentException(
+ String.format("Unsupported PathOrder %s.", this)
+ );
+ }
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/RateLimiter.java b/src/main/java/com/regexsolver/api/RateLimiter.java
new file mode 100644
index 0000000..a40ff63
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/RateLimiter.java
@@ -0,0 +1,55 @@
+package com.regexsolver.api;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Global rate limiter shared by apiToken.
+ *
+ * Holds a single deadline. {@code trigger} keeps the later of the current and
+ * the new deadline; {@code waitIfNecessary} schedules a non-blocking delay
+ * (no thread is ever parked) and re-checks the deadline after every wake, so
+ * a deadline extended by a concurrent 429 is honored.
+ */
+class RateLimiter {
+
+ private static final ConcurrentHashMap INSTANCES =
+ new ConcurrentHashMap<>();
+
+ private final AtomicReference retryAfter = new AtomicReference<>(
+ Instant.MIN
+ );
+
+ private RateLimiter() {}
+
+ public static RateLimiter getInstance(String apiToken) {
+ return INSTANCES.computeIfAbsent(apiToken, k -> new RateLimiter());
+ }
+
+ public CompletableFuture waitIfNecessary() {
+ Instant now = Instant.now();
+ Instant retryAt = retryAfter.get();
+
+ if (!retryAt.isAfter(now)) {
+ return CompletableFuture.completedFuture(null);
+ }
+ long delay = Math.max(Duration.between(now, retryAt).toMillis(), 1);
+ return CompletableFuture.runAsync(
+ () -> {},
+ CompletableFuture.delayedExecutor(delay, TimeUnit.MILLISECONDS)
+ ).thenCompose(v -> waitIfNecessary());
+ }
+
+ public void trigger(double seconds) {
+ Instant nextRetry = Instant.now().plus(
+ Duration.ofMillis((long) (seconds * 1000))
+ );
+ retryAfter.updateAndGet(current ->
+ nextRetry.isAfter(current) ? nextRetry : current
+ );
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/RegexSolver.java b/src/main/java/com/regexsolver/api/RegexSolver.java
deleted file mode 100644
index 97e2ea7..0000000
--- a/src/main/java/com/regexsolver/api/RegexSolver.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.regexsolver.api;
-
-public final class RegexSolver {
- public static void initialize(String token) {
- RegexSolverApiWrapper.initialize(token);
- }
-
- public static void initialize(String token, String baseUrl) {
- RegexSolverApiWrapper.initialize(token, baseUrl);
- }
-}
diff --git a/src/main/java/com/regexsolver/api/RegexSolverApiWrapper.java b/src/main/java/com/regexsolver/api/RegexSolverApiWrapper.java
deleted file mode 100644
index 6f1f050..0000000
--- a/src/main/java/com/regexsolver/api/RegexSolverApiWrapper.java
+++ /dev/null
@@ -1,164 +0,0 @@
-package com.regexsolver.api;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.regexsolver.api.Request.GenerateStringsRequest;
-import com.regexsolver.api.Request.MultiTermsRequest;
-import com.regexsolver.api.Response.BooleanResponse;
-import com.regexsolver.api.Response.StringsResponse;
-import com.regexsolver.api.dto.Details;
-import com.regexsolver.api.exception.ApiError;
-import com.regexsolver.api.exception.MissingAPITokenException;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.ResponseBody;
-import retrofit2.Call;
-import retrofit2.Response;
-import retrofit2.Retrofit;
-import retrofit2.converter.jackson.JacksonConverterFactory;
-import retrofit2.http.Body;
-import retrofit2.http.POST;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Objects;
-
-final class RegexSolverApiWrapper {
- private static final RegexSolverApiWrapper INSTANCE = new RegexSolverApiWrapper();
-
- private final static String DEFAULT_BASE_URL = "https://api.regexsolver.com/";
-
- private final static String USER_AGENT = "RegexSolver Java / 1.0.2";
-
- private RegexApi api;
-
- public static RegexSolverApiWrapper getInstance() {
- return INSTANCE;
- }
-
- private RegexSolverApiWrapper() {
- initializeInternal(null, DEFAULT_BASE_URL);
- }
-
- static void initialize(String token) {
- getInstance().initializeInternal(token, DEFAULT_BASE_URL);
- }
-
- static void initialize(String token, String baseUrl) {
- getInstance().initializeInternal(token, baseUrl);
- }
-
- private void initializeInternal(String token, String baseUrl) {
- Retrofit retrofit = new Retrofit.Builder()
- .client(new OkHttpClient.Builder().addInterceptor(chain -> {
- if (token == null) {
- throw new MissingAPITokenException();
- }
- Request newRequest = chain.request().newBuilder()
- .addHeader("User-Agent", USER_AGENT)
- .addHeader("Authorization", "Bearer " + token)
- .build();
- return chain.proceed(newRequest);
- }).build())
- .baseUrl(baseUrl)
- .addConverterFactory(JacksonConverterFactory.create())
- .build();
-
- api = retrofit.create(RegexApi.class);
- }
-
- public Term computeIntersection(MultiTermsRequest multiTermsRequest) throws ApiError, IOException {
- Response response = api.computeIntersection(multiTermsRequest).execute();
- if (response.isSuccessful()) {
- return response.body();
- } else {
- throw getApiError(response);
- }
- }
-
- public Term computeUnion(MultiTermsRequest multiTermsRequest) throws ApiError, IOException {
- Response response = api.computeUnion(multiTermsRequest).execute();
- if (response.isSuccessful()) {
- return response.body();
- } else {
- throw getApiError(response);
- }
- }
-
- public Term computeSubtraction(MultiTermsRequest multiTermsRequest) throws ApiError, IOException {
- Response response = api.computeSubtraction(multiTermsRequest).execute();
- if (response.isSuccessful()) {
- return response.body();
- } else {
- throw getApiError(response);
- }
- }
-
- public Details getDetails(Term term) throws ApiError, IOException {
- Response response = api.getDetails(term).execute();
- if (response.isSuccessful()) {
- return response.body();
- } else {
- throw getApiError(response);
- }
- }
-
- public boolean equivalence(MultiTermsRequest multiTermsRequest) throws ApiError, IOException {
- Response response = api.equivalence(multiTermsRequest).execute();
- if (response.isSuccessful()) {
- return response.body().value();
- } else {
- throw getApiError(response);
- }
- }
-
- public boolean subset(MultiTermsRequest multiTermsRequest) throws ApiError, IOException {
- Response response = api.subset(multiTermsRequest).execute();
- if (response.isSuccessful()) {
- return response.body().value();
- } else {
- throw getApiError(response);
- }
- }
-
- public List generateStrings(Term term, int count) throws ApiError, IOException {
- GenerateStringsRequest generateStringsRequest = new GenerateStringsRequest(term, count);
- Response response = api.generateStrings(generateStringsRequest).execute();
- if (response.isSuccessful()) {
- return response.body().value();
- } else {
- throw getApiError(response);
- }
- }
-
- private static ApiError getApiError(Response response) throws IOException {
- assert !response.isSuccessful();
- try (ResponseBody errorBody = response.errorBody()) {
- String json = Objects.requireNonNull(errorBody).string();
- ObjectMapper mapper = new ObjectMapper();
- return mapper.readValue(json, ApiError.class);
- }
- }
-
- private interface RegexApi {
- @POST("api/compute/intersection")
- Call computeIntersection(@Body MultiTermsRequest multiTermsRequest);
-
- @POST("api/compute/union")
- Call computeUnion(@Body MultiTermsRequest multiTermsRequest);
-
- @POST("api/compute/subtraction")
- Call computeSubtraction(@Body MultiTermsRequest multiTermsRequest);
-
- @POST("api/analyze/details")
- Call getDetails(@Body Term term);
-
- @POST("api/analyze/equivalence")
- Call equivalence(@Body MultiTermsRequest multiTermsRequest);
-
- @POST("api/analyze/subset")
- Call subset(@Body MultiTermsRequest multiTermsRequest);
-
- @POST("api/generate/strings")
- Call generateStrings(@Body GenerateStringsRequest request);
- }
-}
diff --git a/src/main/java/com/regexsolver/api/RegexSolverClient.java b/src/main/java/com/regexsolver/api/RegexSolverClient.java
new file mode 100644
index 0000000..145cf2f
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/RegexSolverClient.java
@@ -0,0 +1,714 @@
+package com.regexsolver.api;
+
+import java.util.List;
+
+/**
+ * The Synchronous Client for RegexSolver.
+ *
+ * Provides blocking access to all RegexSolver API endpoints.
+ */
+public final class RegexSolverClient {
+
+ private final AsyncRegexSolverClient asyncClient;
+
+ private RegexSolverClient(Builder builder) {
+ this.asyncClient = builder.asyncBuilder.build();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static final class Builder {
+
+ private final AsyncRegexSolverClient.Builder asyncBuilder =
+ AsyncRegexSolverClient.builder();
+
+ public Builder apiToken(String apiToken) {
+ asyncBuilder.apiToken(apiToken);
+ return this;
+ }
+
+ public Builder baseUrl(String baseUrl) {
+ asyncBuilder.baseUrl(baseUrl);
+ return this;
+ }
+
+ /**
+ * When true (the default), calls to concat/intersection/union
+ * carrying more terms than the account's per-request limit are
+ * transparently split into several requests and folded back into one
+ * result. Each constituent request counts against the monthly quota.
+ *
+ * @param autoBatch whether to enable auto-batching
+ * @return this builder
+ */
+ public Builder autoBatch(boolean autoBatch) {
+ asyncBuilder.autoBatch(autoBatch);
+ return this;
+ }
+
+ /**
+ * Upper bound (>= 2) on the number of terms sent in a single
+ * request, overriding the limit fetched from the API when smaller.
+ *
+ * @param maxTermsPerRequest the cap, or null to use the account limit
+ * @return this builder
+ */
+ public Builder maxTermsPerRequest(Integer maxTermsPerRequest) {
+ asyncBuilder.maxTermsPerRequest(maxTermsPerRequest);
+ return this;
+ }
+
+ public RegexSolverClient build() {
+ return new RegexSolverClient(this);
+ }
+ }
+
+ // --- ACCOUNT OPERATIONS ---
+
+ /**
+ * Fetches the plan limits applying to the account.
+ *
+ * The call never consumes request quota (it is only rate-limited) and the
+ * result is cached on the client, so calling it again is free. The cached
+ * maxTermsCount also drives auto-batching.
+ *
+ * @return The five plan limits.
+ */
+ public AccountLimits getAccountLimits() {
+ try {
+ return asyncClient.getAccountLimits().join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ // --- ANALYZE OPERATIONS ---
+
+ /**
+ * Computes how many unique strings the term matches.
+ *
+ * @param term The term to analyze.
+ * @return Cardinality object representing either an exact Integer, a BigInteger, or Infinite cardinality.
+ */
+ public Cardinality getCardinality(Term term) {
+ return getCardinality(term, (OperationOptions) null);
+ }
+
+ /**
+ * Computes how many unique strings the term matches.
+ *
+ * @param term The term to analyze.
+ * @param options Options for the operation.
+ * @return Cardinality object representing either an exact Integer, a BigInteger, or Infinite cardinality.
+ */
+ public Cardinality getCardinality(Term term, OperationOptions options) {
+ try {
+ return asyncClient.getCardinality(term, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Computes the minimum and maximum length of strings matched by the term.
+ *
+ * @param term The term to analyze.
+ * @return Length object with `min` and `max` integers. Limits are null if unbounded or undefined.
+ */
+ public Length getLength(Term term) {
+ return getLength(term, (OperationOptions) null);
+ }
+
+ /**
+ * Computes the minimum and maximum length of strings matched by the term.
+ *
+ * @param term The term to analyze.
+ * @param options Options for the operation.
+ * @return Length object with `min` and `max` integers. Limits are null if unbounded or undefined.
+ */
+ public Length getLength(Term term, OperationOptions options) {
+ try {
+ return asyncClient.getLength(term, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Checks if the term matches no strings at all.
+ *
+ * @param term The term to analyze.
+ * @return true if the language is completely empty, false otherwise.
+ */
+ public boolean isEmpty(Term term) {
+ return isEmpty(term, (OperationOptions) null);
+ }
+
+ /**
+ * Checks if the term matches no strings at all.
+ *
+ * @param term The term to analyze.
+ * @param options Options for the operation.
+ * @return true if the language is completely empty, false otherwise.
+ */
+ public boolean isEmpty(Term term, OperationOptions options) {
+ try {
+ return asyncClient.isEmpty(term, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Checks if the term matches only the empty string.
+ *
+ * @param term The term to analyze.
+ * @return true if the term strictly matches the empty string ("") and nothing else.
+ */
+ public boolean isEmptyString(Term term) {
+ return isEmptyString(term, (OperationOptions) null);
+ }
+
+ /**
+ * Checks if the term matches only the empty string.
+ *
+ * @param term The term to analyze.
+ * @param options Options for the operation.
+ * @return true if the term strictly matches the empty string ("") and nothing else.
+ */
+ public boolean isEmptyString(Term term, OperationOptions options) {
+ try {
+ return asyncClient.isEmptyString(term, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Checks if the term matches all possible strings.
+ *
+ * @param term The term to analyze.
+ * @return true if the term matches every possible string.
+ */
+ public boolean isTotal(Term term) {
+ return isTotal(term, (OperationOptions) null);
+ }
+
+ /**
+ * Checks if the term matches all possible strings.
+ *
+ * @param term The term to analyze.
+ * @param options Options for the operation.
+ * @return true if the term matches every possible string.
+ */
+ public boolean isTotal(Term term, OperationOptions options) {
+ try {
+ return asyncClient.isTotal(term, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Checks if the term's automaton is deterministic.
+ * Only a deterministic FAIR guarantees consistent string ordering across paginated generateStrings() calls; call determinize() first if this is false.
+ *
+ * @param term The term to analyze.
+ * @return true if the term's automaton is deterministic.
+ */
+ public boolean isDeterministic(Term term) {
+ return isDeterministic(term, (OperationOptions) null);
+ }
+
+ /**
+ * Checks if the term's automaton is deterministic.
+ * Only a deterministic FAIR guarantees consistent string ordering across paginated generateStrings() calls; call determinize() first if this is false.
+ *
+ * @param term The term to analyze.
+ * @param options Options for the operation.
+ * @return true if the term's automaton is deterministic.
+ */
+ public boolean isDeterministic(Term term, OperationOptions options) {
+ try {
+ return asyncClient.isDeterministic(term, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Returns a regular expression pattern that represents the term.
+ *
+ * @param term The term to extract the pattern from.
+ * @return A valid regular expression string representing the language.
+ */
+ public String getPattern(Term term) {
+ return getPattern(term, (OperationOptions) null);
+ }
+
+ /**
+ * Returns a regular expression pattern that represents the term.
+ *
+ * @param term The term to extract the pattern from.
+ * @param options Options for the operation.
+ * @return A valid regular expression string representing the language.
+ */
+ public String getPattern(Term term, OperationOptions options) {
+ try {
+ return asyncClient.getPattern(term, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Builds a Graphviz DOT representation of the term's automaton.
+ *
+ * @param term The term to visualize.
+ * @return The raw DOT syntax for Graphviz compilation.
+ */
+ public String getDot(Term term) {
+ return getDot(term, (OperationOptions) null);
+ }
+
+ /**
+ * Builds a Graphviz DOT representation of the term's automaton.
+ *
+ * @param term The term to visualize.
+ * @param options Options for the operation.
+ * @return The raw DOT syntax for Graphviz compilation.
+ */
+ public String getDot(Term term, OperationOptions options) {
+ try {
+ return asyncClient.getDot(term, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Checks if the two terms accept exactly the same language.
+ *
+ * @param term1 The first term.
+ * @param term2 The second term to compare against.
+ * @return true if they are entirely equivalent, false otherwise.
+ */
+ public boolean equivalent(Term term1, Term term2) {
+ return equivalent(term1, term2, (OperationOptions) null);
+ }
+
+ /**
+ * Checks if the two terms accept exactly the same language.
+ *
+ * @param term1 The first term.
+ * @param term2 The second term to compare against.
+ * @param options Options for the operation.
+ * @return true if they are entirely equivalent, false otherwise.
+ */
+ public boolean equivalent(
+ Term term1,
+ Term term2,
+ OperationOptions options
+ ) {
+ try {
+ return asyncClient.equivalent(term1, term2, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Checks if the first term's language is a subset of the second term's language.
+ *
+ * @param subset The term to test as the subset.
+ * @param superset The term representing the entire set space.
+ * @return true if every string matched by subset is also matched by superset.
+ */
+ public boolean subset(Term subset, Term superset) {
+ return subset(subset, superset, (OperationOptions) null);
+ }
+
+ /**
+ * Checks if the first term's language is a subset of the second term's language.
+ *
+ * @param subset The term to test as the subset.
+ * @param superset The term representing the entire set space.
+ * @param options Options for the operation.
+ * @return true if every string matched by subset is also matched by superset.
+ */
+ public boolean subset(
+ Term subset,
+ Term superset,
+ OperationOptions options
+ ) {
+ try {
+ return asyncClient.subset(subset, superset, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ // --- COMPUTE OPERATIONS ---
+
+ /**
+ * Concatenates the given terms sequentially.
+ *
+ * @param terms Variadic terms to concatenate in order.
+ * @return A newly computed concatenated term.
+ */
+ public Term concat(Term... terms) {
+ try {
+ return asyncClient.concat(terms).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Concatenates the given terms sequentially.
+ *
+ * @param terms A list of terms to concatenate in order.
+ * @return A newly computed concatenated term.
+ */
+ public Term concat(List terms) {
+ return concat(terms, (OperationOptions) null);
+ }
+
+ /**
+ * Concatenates the given terms sequentially, allowing for options specification.
+ *
+ * @param terms A list of terms to concatenate in order.
+ * @param options Options for the operation.
+ * @return A newly computed concatenated term.
+ */
+ public Term concat(List terms, OperationOptions options) {
+ try {
+ return asyncClient.concat(terms, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Computes the intersection of the given terms.
+ *
+ * @param terms Variadic terms to intersect.
+ * @return A term representing only strings matched by ALL provided terms.
+ */
+ public Term intersection(Term... terms) {
+ try {
+ return asyncClient.intersection(terms).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Computes the intersection of the given terms.
+ *
+ * @param terms A list of terms to intersect.
+ * @return A term representing only strings matched by ALL provided terms.
+ */
+ public Term intersection(List terms) {
+ return intersection(terms, (OperationOptions) null);
+ }
+
+ /**
+ * Computes the intersection of the given terms, allowing for options specification.
+ *
+ * @param terms A list of terms to intersect.
+ * @param options Options for the operation.
+ * @return A term representing only strings matched by ALL provided terms.
+ */
+ public Term intersection(List terms, OperationOptions options) {
+ try {
+ return asyncClient.intersection(terms, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Computes the union of the given terms.
+ *
+ * @param terms Variadic terms to combine.
+ * @return A term representing strings matched by ANY of the provided terms.
+ */
+ public Term union(Term... terms) {
+ try {
+ return asyncClient.union(terms).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Computes the union of the given terms.
+ *
+ * @param terms A list of terms to combine.
+ * @return A term representing strings matched by ANY of the provided terms.
+ */
+ public Term union(List terms) {
+ return union(terms, (OperationOptions) null);
+ }
+
+ /**
+ * Computes the union of the given terms, allowing for options specification.
+ *
+ * @param terms A list of terms to combine.
+ * @param options Options for the operation.
+ * @return A term representing strings matched by ANY of the provided terms.
+ */
+ public Term union(List terms, OperationOptions options) {
+ try {
+ return asyncClient.union(terms, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Computes the difference between the two provided terms.
+ *
+ * @param base The base language term to subtract from.
+ * @param excluded The term whose language should be removed from the base.
+ * @return A computed difference term.
+ */
+ public Term difference(Term base, Term excluded) {
+ return difference(base, excluded, (OperationOptions) null);
+ }
+
+ /**
+ * Computes the difference between the two provided terms.
+ *
+ * @param base The base language term to subtract from.
+ * @param excluded The term whose language should be removed from the base.
+ * @param options Options for the operation.
+ * @return A computed difference term.
+ */
+ public Term difference(Term base, Term excluded, OperationOptions options) {
+ try {
+ return asyncClient.difference(base, excluded, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Computes the complement of the given term.
+ *
+ * @param term The term to complement.
+ * @return The complemented term.
+ */
+ public Term complement(Term term) {
+ return complement(term, (OperationOptions) null);
+ }
+
+ /**
+ * Computes the complement of the given term.
+ *
+ * @param term The term to complement.
+ * @param options Options for the operation.
+ * @return The complemented term.
+ */
+ public Term complement(Term term, OperationOptions options) {
+ try {
+ return asyncClient.complement(term, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Repeats a term between a minimum and maximum number of times.
+ *
+ * @param term The term to repeat.
+ * @param min The inclusive lower bound of repetitions.
+ * @param max The inclusive upper bound. If null, repetitions are unbounded.
+ * @return A computed repeated term.
+ */
+ public Term repeat(Term term, int min, Integer max) {
+ return repeat(term, min, max, (OperationOptions) null);
+ }
+
+ /**
+ * Repeats a term between a minimum and maximum number of times.
+ *
+ * @param term The term to repeat.
+ * @param min The inclusive lower bound of repetitions.
+ * @param max The inclusive upper bound. If null, repetitions are unbounded.
+ * @param options Options for the operation.
+ * @return A computed repeated term.
+ */
+ public Term repeat(
+ Term term,
+ int min,
+ Integer max,
+ OperationOptions options
+ ) {
+ try {
+ return asyncClient.repeat(term, min, max, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ /**
+ * Computes a deterministic FAIR automaton from the given term.
+ * A deterministic FAIR guarantees consistent string ordering across paginated
+ * generateStrings() calls. Use this when isDeterministic() is false
+ * before calling generateStrings() with an offset.
+ *
+ * @param term The term to determinize.
+ * @return A deterministic FAIR.
+ */
+ public Term determinize(Term term) {
+ return determinize(term, (OperationOptions) null);
+ }
+
+ /**
+ * Computes a deterministic FAIR automaton from the given term.
+ * A deterministic FAIR guarantees consistent string ordering across paginated
+ * generateStrings() calls. Use this when isDeterministic() is false
+ * before calling generateStrings() with an offset.
+ *
+ * @param term The term to determinize.
+ * @param options Options for the operation.
+ * @return A deterministic FAIR.
+ */
+ public Term determinize(Term term, OperationOptions options) {
+ try {
+ return asyncClient.determinize(term, options).join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ // --- GENERATE OPERATIONS ---
+
+ /**
+ * Generates up to {@code limit} distinct strings matched by the term, skipping the first {@code offset} strings.
+ *
+ * @param term The term to sample generated strings from.
+ * @param limit The maximum number of unique strings to return.
+ * @param offset Number of matched strings to skip before starting to collect the results. Used for pagination.
+ * @return A list of strings that match the term.
+ */
+ public List generateStrings(Term term, int limit, int offset) {
+ return generateStrings(term, limit, offset, (OperationOptions) null);
+ }
+
+ /**
+ * Generates up to {@code limit} distinct strings matched by the term, skipping the first {@code offset} strings.
+ *
+ * @param term The term to sample generated strings from.
+ * @param limit The maximum number of unique strings to return.
+ * @param offset Number of matched strings to skip before starting to collect the results. Used for pagination.
+ * @param options Options for the operation.
+ * @return A list of strings that match the term.
+ */
+ public List generateStrings(
+ Term term,
+ int limit,
+ int offset,
+ OperationOptions options
+ ) {
+ try {
+ return asyncClient
+ .generateStrings(term, limit, offset, options)
+ .join();
+ } catch (java.util.concurrent.CompletionException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+
+ throw e;
+ }
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/Request.java b/src/main/java/com/regexsolver/api/Request.java
deleted file mode 100644
index cdd3a71..0000000
--- a/src/main/java/com/regexsolver/api/Request.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.regexsolver.api;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import java.util.List;
-
-final class Request {
-
- public static final class MultiTermsRequest {
- private final List terms;
-
- public MultiTermsRequest(@JsonProperty("terms") List terms) {
- this.terms = terms;
- }
-
- public List getTerms() {
- return terms;
- }
- }
-
- public static final class GenerateStringsRequest {
- private final Term term;
- private final int count;
-
- public GenerateStringsRequest(
- @JsonProperty("term") Term term,
- @JsonProperty("count") int count
- ) {
- this.term = term;
- this.count = count;
- }
-
- public Term getTerm() {
- return term;
- }
-
- public int getCount() {
- return count;
- }
- }
-}
diff --git a/src/main/java/com/regexsolver/api/Response.java b/src/main/java/com/regexsolver/api/Response.java
deleted file mode 100644
index 5675052..0000000
--- a/src/main/java/com/regexsolver/api/Response.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.regexsolver.api;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import java.util.List;
-
-final class Response {
- public static final class BooleanResponse implements ResponseContent {
- private final boolean value;
-
- public BooleanResponse(@JsonProperty("value") boolean value) {
- this.value = value;
- }
-
- public boolean value() {
- return value;
- }
- }
-
- public static final class StringsResponse implements ResponseContent {
- private final List value;
-
- public StringsResponse(@JsonProperty("value") List value) {
- this.value = value;
- }
-
- public List value() {
- return value;
- }
- }
-}
diff --git a/src/main/java/com/regexsolver/api/ResponseContent.java b/src/main/java/com/regexsolver/api/ResponseContent.java
deleted file mode 100644
index a7ff289..0000000
--- a/src/main/java/com/regexsolver/api/ResponseContent.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.regexsolver.api;
-
-import com.fasterxml.jackson.annotation.JsonSubTypes;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.regexsolver.api.Response.BooleanResponse;
-import com.regexsolver.api.Response.StringsResponse;
-import com.regexsolver.api.dto.Details;
-
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
-@JsonSubTypes({
- @JsonSubTypes.Type(value = Term.Fair.class, name = "fair"),
- @JsonSubTypes.Type(value = Term.Regex.class, name = "regex"),
- @JsonSubTypes.Type(value = Details.class, name = "details"),
- @JsonSubTypes.Type(value = StringsResponse.class, name = "strings"),
- @JsonSubTypes.Type(value = BooleanResponse.class, name = "boolean"),
-})
-public interface ResponseContent {
-}
diff --git a/src/main/java/com/regexsolver/api/ResponseFormat.java b/src/main/java/com/regexsolver/api/ResponseFormat.java
new file mode 100644
index 0000000..5e189d5
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/ResponseFormat.java
@@ -0,0 +1,27 @@
+package com.regexsolver.api;
+
+import com.regexsolver.api.generated.model.ResponseOptionsDto.FormatEnum;
+
+/**
+ * Used in compute operations to specify the format of the result.
+ */
+public enum ResponseFormat {
+ ANY,
+ REGEX,
+ FAIR;
+
+ FormatEnum toDto() {
+ switch (this) {
+ case ANY:
+ return FormatEnum.ANY;
+ case REGEX:
+ return FormatEnum.REGEX;
+ case FAIR:
+ return FormatEnum.FAIR;
+ default:
+ throw new IllegalArgumentException(
+ String.format("Unsupported ResponseFormat %s.", this)
+ );
+ }
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/Term.java b/src/main/java/com/regexsolver/api/Term.java
index 3673670..d8de403 100644
--- a/src/main/java/com/regexsolver/api/Term.java
+++ b/src/main/java/com/regexsolver/api/Term.java
@@ -1,217 +1,180 @@
package com.regexsolver.api;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.regexsolver.api.Request.MultiTermsRequest;
-import com.regexsolver.api.dto.Details;
-import com.regexsolver.api.exception.ApiError;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import com.regexsolver.api.generated.model.TermDto;
+import com.regexsolver.api.generated.model.TermFairDto;
+import com.regexsolver.api.generated.model.TermFairMetadataDto;
+import com.regexsolver.api.generated.model.TermRegexDto;
import java.util.Objects;
import java.util.Optional;
+import java.util.regex.Pattern;
/**
- * This abstract class represents a term on which it is possible to perform operations.
+ * Represents a mathematical term (Regex or FAIR) on which operations can be performed.
*/
-public abstract class Term implements ResponseContent {
- @JsonIgnore
- private final static String REGEX_PREFIX = "regex";
- @JsonIgnore
- private final static String FAIR_PREFIX = "fair";
- @JsonIgnore
- private final static String UNKNOWN_PREFIX = "unknown";
+public abstract class Term {
+
+ /** How the engine renders a language that matches no string at all. */
+ private static final String EMPTY_LANGUAGE_PATTERN = "[]";
private final String value;
- @JsonIgnore
- private transient String serialized = null;
+ // Shared Cache (Internal)
+ private Cardinality cardinality;
+ private Length length;
+ private Boolean empty;
+ private Boolean emptyString;
+ private Boolean total;
+ protected String pattern;
+ private String dot;
- @JsonIgnore
- private transient Details details;
+ private Pattern compiledRegex;
- /**
- * Create a new instance.
- *
- * @param value The value of the term.
- */
protected Term(String value) {
this.value = value;
}
- /**
- * Create a new instance of {@link Term.Regex}.
- *
- * @param regex The regular expression pattern.
- * @return The created instance.
- */
- public static Term.Regex regex(String regex) {
- return new Term.Regex(regex);
+ public abstract Optional getPattern();
+
+ public abstract Optional getFair();
+
+ abstract TermDto toDto();
+
+ public static Term regex(String pattern) {
+ return new RegexTerm(pattern);
}
- /**
- * Create a new instance of {@link Term.Fair}.
- *
- * @param fair The FAIR.
- * @return The created instance.
- */
- public static Term.Fair fair(String fair) {
- return new Term.Fair(fair);
+ public static Term fair(String payload) {
+ return new FairTerm(payload, Optional.empty());
}
- String getValue() {
+ // --- Shared Behavior ---
+
+ public String getValue() {
return value;
}
+ void setPropertiesMixin(TermPropertiesMixin propertiesMixin) {
+ propertiesMixin.isEmpty().ifPresent(this::setCachedEmpty);
+ propertiesMixin.isEmptyString().ifPresent(this::setCachedEmptyString);
+ propertiesMixin.isTotal().ifPresent(this::setCachedTotal);
+ }
+
/**
- * Get the details of this term.
- * Cache the result to avoid calling the API again if this method is called multiple times.
- *
- * @return The details of this term.
- * @throws IOException In case of issues requesting the API server.
- * @throws ApiError In case of error returned by the API.
+ * Client-side matching implementation.
+ * @param str The string to test against the term.
+ * @return True if matches, false if not. Throws if pattern is not set.
*/
- @JsonIgnore
- public Details getDetails() throws IOException, ApiError {
- if (details != null) {
- return details;
+ public boolean matches(String str) {
+ Optional patternOpt = getPattern();
+ if (patternOpt.isEmpty()) {
+ throw new IllegalStateException(
+ "The regex pattern of this term is not defined yet, call getPattern() on the client to set it."
+ );
+ }
+
+ // The engine renders the empty language as "[]", which java.util.regex
+ // rejects. By definition it matches nothing.
+ if (EMPTY_LANGUAGE_PATTERN.equals(patternOpt.get())) {
+ return false;
}
- details = RegexSolverApiWrapper.getInstance().getDetails(this);
- return details;
+
+ if (compiledRegex == null) {
+ compiledRegex = Pattern.compile(patternOpt.get(), Pattern.DOTALL);
+ }
+
+ return compiledRegex.matcher(str).matches();
}
- /**
- * Generate the given number of unique strings matched by this term.
- *
- * @param count The number of unique strings to generate.
- * @return A list of unique strings matched by this term.
- * @throws IOException In case of issues requesting the API server.
- * @throws ApiError In case of error returned by the API.
- */
- @JsonIgnore
- public List generateStrings(int count) throws IOException, ApiError {
- return RegexSolverApiWrapper.getInstance().generateStrings(this, count);
+ public abstract String serialize();
+
+ public static Optional deserialize(String serialized) {
+ if (serialized == null || !serialized.contains("=")) {
+ return Optional.empty();
+ }
+
+ int index = serialized.indexOf("=");
+ String typeStr = serialized.substring(0, index);
+ String val = serialized.substring(index + 1);
+
+ if ("regex".equalsIgnoreCase(typeStr)) {
+ return Optional.of(regex(val));
+ } else if ("fair".equalsIgnoreCase(typeStr)) {
+ return Optional.of(fair(val));
+ }
+ return Optional.empty();
}
- @JsonIgnore
- private List getArgs(Term... terms) {
- ArrayList args = new ArrayList<>();
- args.add(this);
- args.addAll(List.of(terms));
- return args;
+ static Term fromDto(TermDto dto) {
+ Object instance = dto.getActualInstance();
+ if (instance instanceof TermRegexDto) {
+ return Term.regex(((TermRegexDto) instance).getValue());
+ }
+ TermFairDto fairDto = (TermFairDto) instance;
+ // Keep metadata.deterministic so isDeterministic() does not need a second
+ // round trip for a FAIR the server already told us about.
+ Optional deterministic = Optional.ofNullable(fairDto.getMetadata())
+ .map(TermFairMetadataDto::getDeterministic);
+ return new FairTerm(fairDto.getValue(), deterministic);
}
- /**
- * Compute the intersection with the given terms and return the resulting term.
- *
- * @param terms The terms to compute an intersection with.
- * @return The resulting term
- * @throws IOException In case of issues requesting the API server.
- * @throws ApiError In case of error returned by the API.
- */
- @JsonIgnore
- public Term intersection(Term... terms) throws IOException, ApiError {
- return RegexSolverApiWrapper.getInstance()
- .computeIntersection(new MultiTermsRequest(getArgs(terms)));
+ // --- Shared Getters/Setters ---
+
+ Cardinality getCachedCardinality() {
+ return cardinality;
}
- /**
- * Compute the union with the given terms and return the resulting term.
- *
- * @param terms The terms to compute a union with.
- * @return The resulting term
- * @throws IOException In case of issues requesting the API server.
- * @throws ApiError In case of error returned by the API.
- */
- @JsonIgnore
- public Term union(Term... terms) throws IOException, ApiError {
- return RegexSolverApiWrapper.getInstance()
- .computeUnion(new MultiTermsRequest(getArgs(terms)));
+ void setCachedCardinality(Cardinality cardinality) {
+ setPropertiesMixin(cardinality);
+ this.cardinality = cardinality;
}
- /**
- * Compute the subtraction with the given term and return the resulting term.
- *
- * @param term The term to subtract.
- * @return The resulting term
- * @throws IOException In case of issues requesting the API server.
- * @throws ApiError In case of error returned by the API.
- */
- @JsonIgnore
- public Term subtraction(Term term) throws IOException, ApiError {
- return RegexSolverApiWrapper.getInstance()
- .computeSubtraction(new MultiTermsRequest(getArgs(term)));
+ Length getCachedLength() {
+ return length;
}
- /**
- * Check equivalence with the given term.
- *
- * @param term The term to check equivalence with.
- * @return true if the terms are equivalent, false otherwise.
- * @throws IOException In case of issues requesting the API server.
- * @throws ApiError In case of error returned by the API.
- */
- @JsonIgnore
- public boolean isEquivalentTo(Term term) throws IOException, ApiError {
- return RegexSolverApiWrapper.getInstance()
- .equivalence(new MultiTermsRequest(getArgs(term)));
+ void setCachedLength(Length length) {
+ setPropertiesMixin(length);
+ this.length = length;
}
- /**
- * Check if is a subset of the given term.
- *
- * @param term The term to check if is the superset of this.
- * @return true if this is a subset, false otherwise.
- * @throws IOException In case of issues requesting the API server.
- * @throws ApiError In case of error returned by the API.
- */
- @JsonIgnore
- public boolean isSubsetOf(Term term) throws IOException, ApiError {
- return RegexSolverApiWrapper.getInstance()
- .subset(new MultiTermsRequest(getArgs(term)));
+ Boolean getCachedEmpty() {
+ return empty;
}
- /**
- * Generate a string representation that can be parsed by {@link #deserialize(String)}.
- *
- * @return A string representation of this term.
- */
- public String serialize() {
- if (serialized != null) {
- return serialized;
- }
- String prefix;
- if (this instanceof Regex) {
- prefix = REGEX_PREFIX;
- } else if (this instanceof Fair) {
- prefix = FAIR_PREFIX;
- } else {
- prefix = UNKNOWN_PREFIX;
- }
- serialized = String.format("%s=%s", prefix, value);
- return serialized;
+ void setCachedEmpty(Boolean empty) {
+ this.empty = empty;
}
- /**
- * Parse a string representation of a {@link Term} produced by {@link #serialize()}.
- *
- * @param string A string representation produced by {@link #serialize()}.
- * @return The parsed term, or empty if the method was not able to parse.
- */
- @JsonIgnore
- public static Optional deserialize(String string) {
- if (string == null) {
- return Optional.empty();
- }
+ Boolean getCachedEmptyString() {
+ return emptyString;
+ }
- if (string.startsWith(REGEX_PREFIX)) {
- return Optional.of(regex(string.substring(REGEX_PREFIX.length() + 1)));
- } else if (string.startsWith(FAIR_PREFIX)) {
- return Optional.of(fair(string.substring(FAIR_PREFIX.length() + 1)));
- } else {
- return Optional.empty();
- }
+ void setCachedEmptyString(Boolean emptyString) {
+ this.emptyString = emptyString;
+ }
+
+ Boolean getCachedTotal() {
+ return total;
+ }
+
+ void setCachedTotal(Boolean total) {
+ this.total = total;
+ }
+
+ void setCachedPattern(String pattern) {
+ this.pattern = pattern;
+ }
+
+ String getCachedPattern() {
+ return this.pattern;
+ }
+
+ String getCachedDot() {
+ return dot;
+ }
+
+ void setCachedDot(String dot) {
+ this.dot = dot;
}
@Override
@@ -219,12 +182,12 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Term term = (Term) o;
- return Objects.equals(term.serialize(), serialize());
+ return Objects.equals(serialize(), term.serialize());
}
@Override
public int hashCode() {
- return Objects.hash(serialize());
+ return serialize().hashCode();
}
@Override
@@ -232,58 +195,82 @@ public String toString() {
return serialize();
}
- /**
- * This term represents a Fast Automaton Internal Representation (FAIR).
- *
- * You can learn more about FAIR in our documentation.
- *
- */
- public static final class Fair extends Term {
- /**
- * Create a new instance.
- *
- * @param fair The FAIR.
- */
- public Fair(@JsonProperty("value") String fair) {
- super(fair);
+ public static final class RegexTerm extends Term {
+
+ RegexTerm(String value) {
+ super(value);
}
- /**
- * Return the Fast Automaton Internal Representation (FAIR).
- *
- * @return The FAIR.
- */
- @JsonProperty("value")
- public String getFair() {
- return getValue();
+ @Override
+ public Optional getPattern() {
+ return Optional.of(getValue());
+ }
+
+ @Override
+ public Optional getFair() {
+ return Optional.empty();
+ }
+
+ @Override
+ TermDto toDto() {
+ return new TermDto(
+ new TermRegexDto()
+ .type(TermRegexDto.TypeEnum.REGEX)
+ .value(getValue())
+ );
+ }
+
+ @Override
+ public String serialize() {
+ return "regex=" + getValue();
}
}
+ public static final class FairTerm extends Term {
- /**
- * This term represents a regular expression.
- *
- * You can learn more about regular expression in our documentation
- *
- */
- public static final class Regex extends Term {
- /**
- * Create a new instance.
- *
- * @param regex The regular expression pattern.
- */
- public Regex(@JsonProperty("value") String regex) {
- super(regex);
+ private Optional deterministic = Optional.empty();
+
+ FairTerm(String value, Optional deterministic) {
+ super(value);
+ this.deterministic = deterministic;
}
/**
- * Return the regular expression pattern.
+ * Whether this FAIR encodes a deterministic automaton, or
+ * {@link java.util.Optional#empty()} if it is not known yet.
*
- * @return The regular expression pattern.
+ * @return the cached determinism flag, if known
*/
- @JsonProperty("value")
- public String getPattern() {
- return getValue();
+ public Optional getCachedDeterministic() {
+ return this.deterministic;
+ }
+
+ void setCachedDeterministic(Optional deterministic) {
+ this.deterministic = deterministic;
+ }
+
+ @Override
+ public Optional getPattern() {
+ return Optional.ofNullable(this.pattern);
+ }
+
+ @Override
+ public Optional getFair() {
+ return Optional.of(getValue());
+ }
+
+ @Override
+ TermDto toDto() {
+ return new TermDto(
+ new TermFairDto()
+ .type(TermFairDto.TypeEnum.FAIR)
+ .value(getValue())
+ );
+ }
+
+ @Override
+ public String serialize() {
+ return "fair=" + getValue();
}
}
}
diff --git a/src/main/java/com/regexsolver/api/TermPropertiesMixin.java b/src/main/java/com/regexsolver/api/TermPropertiesMixin.java
new file mode 100644
index 0000000..a3db3cd
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/TermPropertiesMixin.java
@@ -0,0 +1,41 @@
+package com.regexsolver.api;
+
+import java.util.Optional;
+
+/**
+ * A mixin providing default property inference for Term analytics.
+ *
+ * Returns {@code Optional.empty()} when a property cannot be strictly inferred from the current data alone.
+ */
+abstract class TermPropertiesMixin {
+
+ /**
+ * Infers whether the term matches no strings at all.
+ *
+ * @return An {@code Optional} containing {@code true} if it definitely matches no strings,
+ * {@code false} if it matches at least one, or {@code Optional.empty()} if it cannot be inferred.
+ */
+ public Optional isEmpty() {
+ return Optional.empty();
+ }
+
+ /**
+ * Infers whether the term matches strictly the empty string ("").
+ *
+ * @return An {@code Optional} containing {@code true} if it definitely matches only the empty string,
+ * {@code false} if it matches other strings, or {@code Optional.empty()} if it cannot be inferred.
+ */
+ public Optional isEmptyString() {
+ return Optional.empty();
+ }
+
+ /**
+ * Infers whether the term matches all possible strings.
+ *
+ * @return An {@code Optional} containing {@code true} if it definitely matches all strings,
+ * {@code false} if it misses at least one string, or {@code Optional.empty()} if it cannot be inferred.
+ */
+ public Optional isTotal() {
+ return Optional.empty();
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/dto/Cardinality.java b/src/main/java/com/regexsolver/api/dto/Cardinality.java
deleted file mode 100644
index f62261b..0000000
--- a/src/main/java/com/regexsolver/api/dto/Cardinality.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.regexsolver.api.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonSubTypes;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-
-/**
- * Abstract class that represent the number of possible values.
- */
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
-@JsonSubTypes({
- @JsonSubTypes.Type(value = Cardinality.BigInteger.class, name = "BigInteger"),
- @JsonSubTypes.Type(value = Cardinality.Infinite.class, name = "Infinite"),
- @JsonSubTypes.Type(value = Cardinality.Integer.class, name = "Integer")
-})
-public abstract class Cardinality {
- /**
- * @return true if it has a finite number of values, false otherwise.
- */
- public abstract boolean isFinite();
-
- public abstract String toString();
-
- /**
- * An infinite number of possible values.
- */
- public static final class Infinite extends Cardinality {
- @Override
- public boolean isFinite() {
- return false;
- }
-
- @Override
- public String toString() {
- return "Infinite";
- }
- }
-
- /**
- * A finite number of possible values, but the number is too big to be computed.
- */
- public static final class BigInteger extends Cardinality {
- @Override
- public boolean isFinite() {
- return true;
- }
-
- @Override
- public String toString() {
- return "BigInteger";
- }
- }
-
- /**
- * A finite number of possible values, available in {@link #getCount()}.
- */
- public static final class Integer extends Cardinality {
- private final long count;
-
- /**
- * Create a new instance.
- *
- * @param count The number of possible values.
- */
- public Integer(@JsonProperty("value") long count) {
- this.count = count;
- }
-
- @Override
- public boolean isFinite() {
- return false;
- }
-
- /**
- * @return The number of possible values.
- */
- public long getCount() {
- return count;
- }
-
- @Override
- public String toString() {
- return String.format("Integer(%s)", count);
- }
- }
-}
diff --git a/src/main/java/com/regexsolver/api/dto/Details.java b/src/main/java/com/regexsolver/api/dto/Details.java
deleted file mode 100644
index 0d78d67..0000000
--- a/src/main/java/com/regexsolver/api/dto/Details.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.regexsolver.api.dto;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.regexsolver.api.ResponseContent;
-import com.regexsolver.api.Term;
-
-import java.util.Objects;
-
-/**
- * Contains details about the requested {@link Term}.
- */
-public final class Details implements ResponseContent {
- private final Cardinality cardinality;
- private final Length length;
- private final boolean empty;
- private final boolean total;
-
- /**
- * @param cardinality the number of possible values.
- * @param length the minimum and maximum length of possible values.
- * @param empty true if is an empty set (does not contain any value), false otherwise.
- * @param total true if is a total set (contains all values), false otherwise.
- */
- public Details(
- @JsonProperty("cardinality") Cardinality cardinality,
- @JsonProperty("length") Length length,
- @JsonProperty("empty") boolean empty,
- @JsonProperty("total") boolean total
- ) {
- this.cardinality = cardinality;
- this.length = length;
- this.empty = empty;
- this.total = total;
- }
-
- /**
- * @return The number of possible values.
- */
- public Cardinality getCardinality() {
- return cardinality;
- }
-
- /**
- * @return The minimum and maximum length of possible values.
- */
- public Length getLength() {
- return length;
- }
-
- /**
- * @return true if is an empty set (does not contain any value), false otherwise.
- */
- public boolean isEmpty() {
- return empty;
- }
-
- /**
- * @return true if is a total set (contains all values), false otherwise.
- */
- public boolean isTotal() {
- return total;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) return true;
- if (obj == null || obj.getClass() != this.getClass()) return false;
- var that = (Details) obj;
- return Objects.equals(this.cardinality, that.cardinality) &&
- Objects.equals(this.length, that.length) &&
- this.empty == that.empty &&
- this.total == that.total;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(cardinality, length, empty, total);
- }
-
- @Override
- public String toString() {
- return "Details[" +
- "cardinality=" + cardinality + ", " +
- "length=" + length + ", " +
- "empty=" + empty + ", " +
- "total=" + total + ']';
- }
-}
diff --git a/src/main/java/com/regexsolver/api/dto/Length.java b/src/main/java/com/regexsolver/api/dto/Length.java
deleted file mode 100644
index 3e1200f..0000000
--- a/src/main/java/com/regexsolver/api/dto/Length.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.regexsolver.api.dto;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-
-import java.io.IOException;
-import java.util.Objects;
-import java.util.OptionalLong;
-
-/**
- * Contains the minimum and maximum length of possible values.
- */
-@JsonDeserialize(using = Length.LengthDeserializer.class)
-public final class Length {
- private final Long minimum;
- private final Long maximum;
-
- /**
- * @param minimum the minimum length of possible values, empty if is an empty set.
- * @param maximum the maximum length of possible values, empty if the maximum length is infinite or if is an empty set.
- */
- Length(Long minimum, Long maximum) {
- this.minimum = minimum;
- this.maximum = maximum;
- }
-
- /**
- * @return The minimum length of possible values, empty if is an empty set.
- */
- public OptionalLong getMinimum() {
- if (minimum == null) {
- return OptionalLong.empty();
- }
- return OptionalLong.of(minimum);
- }
-
- /**
- * @return The maximum length of possible values, empty if the maximum length is infinite or if is an empty set.
- */
- public OptionalLong getMaximum() {
- if (maximum == null) {
- return OptionalLong.empty();
- }
- return OptionalLong.of(maximum);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) return true;
- if (obj == null || obj.getClass() != this.getClass()) return false;
- var that = (Length) obj;
- return Objects.equals(this.minimum, that.minimum) &&
- Objects.equals(this.maximum, that.maximum);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(minimum, maximum);
- }
-
- @Override
- public String toString() {
- return "Length[" +
- "minimum=" + minimum + ", " +
- "maximum=" + maximum + ']';
- }
-
- static class LengthDeserializer extends JsonDeserializer {
- @Override
- public Length deserialize(JsonParser jp, DeserializationContext ctx)
- throws IOException {
- Long[] lengthArray = jp.readValueAs(Long[].class);
- if (lengthArray != null && lengthArray.length == 2) {
- return new Length(
- lengthArray[0],
- lengthArray[1]
- );
- } else {
- throw new IOException("Invalid length array.");
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/regexsolver/api/dto/package-info.java b/src/main/java/com/regexsolver/api/dto/package-info.java
deleted file mode 100644
index e518844..0000000
--- a/src/main/java/com/regexsolver/api/dto/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Contains simple objects.
- */
-package com.regexsolver.api.dto;
\ No newline at end of file
diff --git a/src/main/java/com/regexsolver/api/exception/ApiError.java b/src/main/java/com/regexsolver/api/exception/ApiError.java
deleted file mode 100644
index b18d74c..0000000
--- a/src/main/java/com/regexsolver/api/exception/ApiError.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.regexsolver.api.exception;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-/**
- * Thrown when the API returns an error.
- */
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class ApiError extends Exception {
- /**
- * Create a new instance.
- *
- * @param message The error message returned by the API.
- */
- public ApiError(@JsonProperty("message") String message) {
- super(String.format("The API returned the following error: %s", message));
- }
-}
diff --git a/src/main/java/com/regexsolver/api/exception/MissingAPITokenException.java b/src/main/java/com/regexsolver/api/exception/MissingAPITokenException.java
deleted file mode 100644
index ddac5ec..0000000
--- a/src/main/java/com/regexsolver/api/exception/MissingAPITokenException.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.regexsolver.api.exception;
-
-/**
- * Thrown if the API token has not been set as environment variable.
- */
-public class MissingAPITokenException extends RuntimeException {
- /**
- * The API token has not been set, call RegexSolverApiWrapper.initialize(\"YOUR_TOKEN\"); to set it.
- * To generate a token go to RegexSolver Console.
- */
- public MissingAPITokenException() {
- super("The API token has not been set, call RegexSolverApiWrapper.initialize(\"YOUR_TOKEN\") to set it.\n" +
- "To generate a token go to https://console.regexsolver.com/.");
- }
-}
diff --git a/src/main/java/com/regexsolver/api/exception/package-info.java b/src/main/java/com/regexsolver/api/exception/package-info.java
deleted file mode 100644
index bc21fdf..0000000
--- a/src/main/java/com/regexsolver/api/exception/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Contains exceptions that can be thrown while using the library.
- */
-package com.regexsolver.api.exception;
\ No newline at end of file
diff --git a/src/main/java/com/regexsolver/api/exceptions/ApiException.java b/src/main/java/com/regexsolver/api/exceptions/ApiException.java
new file mode 100644
index 0000000..1bc2f8b
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/ApiException.java
@@ -0,0 +1,33 @@
+package com.regexsolver.api.exceptions;
+
+/** Base exception raised when the RegexSolver API returns an error response. */
+public class ApiException extends RegexSolverException {
+
+ private final int statusCode;
+ private final String errorCode;
+ private final String body;
+
+ public ApiException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message);
+ this.statusCode = statusCode;
+ this.errorCode = errorCode;
+ this.body = body;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getErrorCode() {
+ return errorCode;
+ }
+
+ public String getBody() {
+ return body;
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/AutomatonTooManyStatesException.java b/src/main/java/com/regexsolver/api/exceptions/AutomatonTooManyStatesException.java
new file mode 100644
index 0000000..97d0dc0
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/AutomatonTooManyStatesException.java
@@ -0,0 +1,10 @@
+package com.regexsolver.api.exceptions;
+
+/**
+ * Raised when the NFA/DFA exceeds the maximum allowed number of states for your current plan.
+ */
+public class AutomatonTooManyStatesException extends BadRequestException {
+ public AutomatonTooManyStatesException(String message, int statusCode, String errorCode, String body) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/BadRequestException.java b/src/main/java/com/regexsolver/api/exceptions/BadRequestException.java
new file mode 100644
index 0000000..969c03c
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/BadRequestException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the API returns a 400 Bad Request error. */
+public class BadRequestException extends ApiException {
+
+ public BadRequestException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/FairSyntaxException.java b/src/main/java/com/regexsolver/api/exceptions/FairSyntaxException.java
new file mode 100644
index 0000000..ebfdf8c
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/FairSyntaxException.java
@@ -0,0 +1,10 @@
+package com.regexsolver.api.exceptions;
+
+/**
+ * Raised when the provided FAIR value is malformed or cannot be decoded.
+ */
+public class FairSyntaxException extends BadRequestException {
+ public FairSyntaxException(String message, int statusCode, String errorCode, String body) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/ForbiddenException.java b/src/main/java/com/regexsolver/api/exceptions/ForbiddenException.java
new file mode 100644
index 0000000..f4bee72
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/ForbiddenException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the API returns a 403 Forbidden error. */
+public class ForbiddenException extends ApiException {
+
+ public ForbiddenException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/InternalServerException.java b/src/main/java/com/regexsolver/api/exceptions/InternalServerException.java
new file mode 100644
index 0000000..0f292f7
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/InternalServerException.java
@@ -0,0 +1,17 @@
+package com.regexsolver.api.exceptions;
+
+/**
+ * Raised when the API returns a 500 Internal Server Error.
+ * Indicates an unexpected failure or panic on the RegexSolver compute servers.
+ */
+public class InternalServerException extends ApiException {
+
+ public InternalServerException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/InvalidJsonException.java b/src/main/java/com/regexsolver/api/exceptions/InvalidJsonException.java
new file mode 100644
index 0000000..e86994e
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/InvalidJsonException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the provided JSON is invalid or cannot be parsed. */
+public class InvalidJsonException extends BadRequestException {
+
+ public InvalidJsonException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/InvalidNumberOfStringsToGenerateException.java b/src/main/java/com/regexsolver/api/exceptions/InvalidNumberOfStringsToGenerateException.java
new file mode 100644
index 0000000..e138a63
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/InvalidNumberOfStringsToGenerateException.java
@@ -0,0 +1,16 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the requested number of strings to generate is below the minimum or exceeds the maximum allowed. */
+public class InvalidNumberOfStringsToGenerateException
+ extends BadRequestException
+{
+
+ public InvalidNumberOfStringsToGenerateException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/InvalidTokenException.java b/src/main/java/com/regexsolver/api/exceptions/InvalidTokenException.java
new file mode 100644
index 0000000..eb5d31b
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/InvalidTokenException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the provided authentication token is invalid. */
+public class InvalidTokenException extends UnauthorizedException {
+
+ public InvalidTokenException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/MissingOrMalformedTokenException.java b/src/main/java/com/regexsolver/api/exceptions/MissingOrMalformedTokenException.java
new file mode 100644
index 0000000..cff1b35
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/MissingOrMalformedTokenException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the provided authentication token is missing or malformed. */
+public class MissingOrMalformedTokenException extends UnauthorizedException {
+
+ public MissingOrMalformedTokenException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/NotFoundException.java b/src/main/java/com/regexsolver/api/exceptions/NotFoundException.java
new file mode 100644
index 0000000..1fd8d4e
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/NotFoundException.java
@@ -0,0 +1,16 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the API returns a 404 Not Found error.
+ * Indicates that the requested API endpoint or resource does not exist.
+ */
+public class NotFoundException extends ApiException {
+
+ public NotFoundException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/QuotaExceededException.java b/src/main/java/com/regexsolver/api/exceptions/QuotaExceededException.java
new file mode 100644
index 0000000..cdb8157
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/QuotaExceededException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when your account's monthly compute quota has been exceeded. */
+public class QuotaExceededException extends ForbiddenException {
+
+ public QuotaExceededException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/RegexSolverException.java b/src/main/java/com/regexsolver/api/exceptions/RegexSolverException.java
new file mode 100644
index 0000000..531fa0c
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/RegexSolverException.java
@@ -0,0 +1,11 @@
+package com.regexsolver.api.exceptions;
+
+/**
+ * Base exception for all RegexSolver errors.
+ */
+public class RegexSolverException extends RuntimeException {
+
+ public RegexSolverException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/RegexSyntaxException.java b/src/main/java/com/regexsolver/api/exceptions/RegexSyntaxException.java
new file mode 100644
index 0000000..5b63e64
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/RegexSyntaxException.java
@@ -0,0 +1,10 @@
+package com.regexsolver.api.exceptions;
+
+/**
+ * Raised when the provided regular expression has invalid syntax.
+ */
+public class RegexSyntaxException extends BadRequestException {
+ public RegexSyntaxException(String message, int statusCode, String errorCode, String body) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/TimeoutExceededException.java b/src/main/java/com/regexsolver/api/exceptions/TimeoutExceededException.java
new file mode 100644
index 0000000..2fed7de
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/TimeoutExceededException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the execution of the request exceeds the provided `execution_timeout` or the maximum allowed for your current plan. */
+public class TimeoutExceededException extends BadRequestException {
+
+ public TimeoutExceededException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/TimeoutTooLargeException.java b/src/main/java/com/regexsolver/api/exceptions/TimeoutTooLargeException.java
new file mode 100644
index 0000000..dff3d3d
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/TimeoutTooLargeException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the requested `execution_timeout` exceeds the maximum allowed for your current plan. */
+public class TimeoutTooLargeException extends BadRequestException {
+
+ public TimeoutTooLargeException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/TooFewTermsException.java b/src/main/java/com/regexsolver/api/exceptions/TooFewTermsException.java
new file mode 100644
index 0000000..be05235
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/TooFewTermsException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when fewer terms are provided than the operation requires. */
+public class TooFewTermsException extends BadRequestException {
+
+ public TooFewTermsException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/TooManyRequestsException.java b/src/main/java/com/regexsolver/api/exceptions/TooManyRequestsException.java
new file mode 100644
index 0000000..47b1904
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/TooManyRequestsException.java
@@ -0,0 +1,17 @@
+package com.regexsolver.api.exceptions;
+
+/**
+ * Raised when the API returns a 429 Too Many Requests error and max retries are exceeded.
+ * Indicates that your requests-per-second (req/s) rate limit has been exceeded.
+ */
+public class TooManyRequestsException extends ApiException {
+
+ public TooManyRequestsException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/TooManyTermsException.java b/src/main/java/com/regexsolver/api/exceptions/TooManyTermsException.java
new file mode 100644
index 0000000..21ac3f6
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/TooManyTermsException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the number of terms provided exceeds the maximum allowed. */
+public class TooManyTermsException extends BadRequestException {
+
+ public TooManyTermsException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/UnauthorizedException.java b/src/main/java/com/regexsolver/api/exceptions/UnauthorizedException.java
new file mode 100644
index 0000000..73e5d9d
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/UnauthorizedException.java
@@ -0,0 +1,14 @@
+package com.regexsolver.api.exceptions;
+
+/** Raised when the API returns a 401 Unauthorized error. */
+public class UnauthorizedException extends ApiException {
+
+ public UnauthorizedException(
+ String message,
+ int statusCode,
+ String errorCode,
+ String body
+ ) {
+ super(message, statusCode, errorCode, body);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/exceptions/package-info.java b/src/main/java/com/regexsolver/api/exceptions/package-info.java
new file mode 100644
index 0000000..612475e
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/exceptions/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Exception classes for the RegexSolver Java client.
+ */
+package com.regexsolver.api.exceptions;
diff --git a/src/main/java/com/regexsolver/api/generated/ApiClient.java b/src/main/java/com/regexsolver/api/generated/ApiClient.java
new file mode 100644
index 0000000..e36d17b
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/ApiClient.java
@@ -0,0 +1,486 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+package com.regexsolver.api.generated;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.net.http.HttpClient;
+import java.net.http.HttpConnectTimeoutException;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringJoiner;
+import java.util.function.Consumer;
+import java.util.Optional;
+import java.util.zip.GZIPInputStream;
+import java.util.stream.Collectors;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * Configuration and utility class for API clients.
+ *
+ * This class can be constructed and modified, then used to instantiate the
+ * various API classes. The API classes use the settings in this class to
+ * configure themselves, but otherwise do not store a link to this class.
+ *
+ * This class is mutable and not synchronized, so it is not thread-safe.
+ * The API classes generated from this are immutable and thread-safe.
+ *
+ * The setter methods of this class return the current object to facilitate
+ * a fluent style of configuration.
+ */
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class ApiClient {
+
+ protected HttpClient.Builder builder;
+ protected ObjectMapper mapper;
+ protected String scheme;
+ protected String host;
+ protected int port;
+ protected String basePath;
+ protected Consumer interceptor;
+ protected Consumer> responseInterceptor;
+ protected Consumer> asyncResponseInterceptor;
+ protected Duration readTimeout;
+ protected Duration connectTimeout;
+
+ public static String valueToString(Object value) {
+ if (value == null) {
+ return "";
+ }
+ if (value instanceof OffsetDateTime) {
+ return ((OffsetDateTime) value).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+ }
+ return value.toString();
+ }
+
+ /**
+ * URL encode a string in the UTF-8 encoding.
+ *
+ * @param s String to encode.
+ * @return URL-encoded representation of the input string.
+ */
+ public static String urlEncode(String s) {
+ return URLEncoder.encode(s, UTF_8).replaceAll("\\+", "%20");
+ }
+
+ /**
+ * Convert a URL query name/value parameter to a list of encoded {@link Pair}
+ * objects.
+ *
+ * The value can be null, in which case an empty list is returned.
+ *
+ * @param name The query name parameter.
+ * @param value The query value, which may not be a collection but may be
+ * null.
+ * @return A singleton list of the {@link Pair} objects representing the input
+ * parameters, which is encoded for use in a URL. If the value is null, an
+ * empty list is returned.
+ */
+ public static List parameterToPairs(String name, Object value) {
+ if (name == null || name.isEmpty() || value == null) {
+ return Collections.emptyList();
+ }
+ return Collections.singletonList(new Pair(urlEncode(name), urlEncode(valueToString(value))));
+ }
+
+ /**
+ * Convert a URL query name/collection parameter to a list of encoded
+ * {@link Pair} objects.
+ *
+ * @param collectionFormat The swagger collectionFormat string (csv, tsv, etc).
+ * @param name The query name parameter.
+ * @param values A collection of values for the given query name, which may be
+ * null.
+ * @return A list of {@link Pair} objects representing the input parameters,
+ * which is encoded for use in a URL. If the values collection is null, an
+ * empty list is returned.
+ */
+ public static List parameterToPairs(
+ String collectionFormat, String name, Collection> values) {
+ if (name == null || name.isEmpty() || values == null || values.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ // get the collection format (default: csv)
+ String format = collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat;
+
+ // create the params based on the collection format
+ if ("multi".equals(format)) {
+ return values.stream()
+ .map(value -> new Pair(urlEncode(name), urlEncode(valueToString(value))))
+ .collect(Collectors.toList());
+ }
+
+ String delimiter;
+ switch(format) {
+ case "csv":
+ delimiter = urlEncode(",");
+ break;
+ case "ssv":
+ delimiter = urlEncode(" ");
+ break;
+ case "tsv":
+ delimiter = urlEncode("\t");
+ break;
+ case "pipes":
+ delimiter = urlEncode("|");
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal collection format: " + collectionFormat);
+ }
+
+ StringJoiner joiner = new StringJoiner(delimiter);
+ for (Object value : values) {
+ joiner.add(urlEncode(valueToString(value)));
+ }
+
+ return Collections.singletonList(new Pair(urlEncode(name), joiner.toString()));
+ }
+
+ /**
+ * Create an instance of ApiClient.
+ */
+ public ApiClient() {
+ this.builder = createDefaultHttpClientBuilder();
+ this.mapper = createDefaultObjectMapper();
+ updateBaseUri("https://api.regexsolver.com/v1");
+ interceptor = null;
+ readTimeout = null;
+ connectTimeout = null;
+ responseInterceptor = null;
+ asyncResponseInterceptor = null;
+ }
+
+ /**
+ * Create an instance of ApiClient.
+ *
+ * @param builder Http client builder.
+ * @param mapper Object mapper.
+ * @param baseUri Base URI
+ */
+ public ApiClient(HttpClient.Builder builder, ObjectMapper mapper, String baseUri) {
+ this.builder = builder;
+ this.mapper = mapper;
+ updateBaseUri(baseUri != null ? baseUri : "https://api.regexsolver.com/v1");
+ interceptor = null;
+ readTimeout = null;
+ connectTimeout = null;
+ responseInterceptor = null;
+ asyncResponseInterceptor = null;
+ }
+
+ public static ObjectMapper createDefaultObjectMapper() {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
+ mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
+ mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+ mapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
+ mapper.registerModule(new JavaTimeModule());
+ mapper.registerModule(new RFC3339JavaTimeModule());
+ return mapper;
+ }
+
+ protected final String getDefaultBaseUri() {
+ return basePath;
+ }
+
+ public static HttpClient.Builder createDefaultHttpClientBuilder() {
+ return HttpClient.newBuilder();
+ }
+
+ public final void updateBaseUri(String baseUri) {
+ URI uri = URI.create(baseUri);
+ scheme = uri.getScheme();
+ host = uri.getHost();
+ port = uri.getPort();
+ basePath = uri.getRawPath();
+ }
+
+ /**
+ * Set a custom {@link HttpClient.Builder} object to use when creating the
+ * {@link HttpClient} that is used by the API client.
+ *
+ * @param builder Custom client builder.
+ * @return This object.
+ */
+ public ApiClient setHttpClientBuilder(HttpClient.Builder builder) {
+ this.builder = builder;
+ return this;
+ }
+
+ /**
+ * Get an {@link HttpClient} based on the current {@link HttpClient.Builder}.
+ *
+ * The returned object is immutable and thread-safe.
+ *
+ * @return The HTTP client.
+ */
+ public HttpClient getHttpClient() {
+ return builder.build();
+ }
+
+ /**
+ * Set a custom {@link ObjectMapper} to serialize and deserialize the request
+ * and response bodies.
+ *
+ * @param mapper Custom object mapper.
+ * @return This object.
+ */
+ public ApiClient setObjectMapper(ObjectMapper mapper) {
+ this.mapper = mapper;
+ return this;
+ }
+
+ /**
+ * Get a copy of the current {@link ObjectMapper}.
+ *
+ * @return A copy of the current object mapper.
+ */
+ public ObjectMapper getObjectMapper() {
+ return mapper.copy();
+ }
+
+ /**
+ * Set a custom host name for the target service.
+ *
+ * @param host The host name of the target service.
+ * @return This object.
+ */
+ public ApiClient setHost(String host) {
+ this.host = host;
+ return this;
+ }
+
+ /**
+ * Set a custom port number for the target service.
+ *
+ * @param port The port of the target service. Set this to -1 to reset the
+ * value to the default for the scheme.
+ * @return This object.
+ */
+ public ApiClient setPort(int port) {
+ this.port = port;
+ return this;
+ }
+
+ /**
+ * Set a custom base path for the target service, for example '/v2'.
+ *
+ * @param basePath The base path against which the rest of the path is
+ * resolved.
+ * @return This object.
+ */
+ public ApiClient setBasePath(String basePath) {
+ this.basePath = basePath;
+ return this;
+ }
+
+ /**
+ * Get the base URI to resolve the endpoint paths against.
+ *
+ * @return The complete base URI that the rest of the API parameters are
+ * resolved against.
+ */
+ public String getBaseUri() {
+ return scheme + "://" + host + (port == -1 ? "" : ":" + port) + basePath;
+ }
+
+ /**
+ * Set a custom scheme for the target service, for example 'https'.
+ *
+ * @param scheme The scheme of the target service
+ * @return This object.
+ */
+ public ApiClient setScheme(String scheme){
+ this.scheme = scheme;
+ return this;
+ }
+
+ /**
+ * Set a custom request interceptor.
+ *
+ * A request interceptor is a mechanism for altering each request before it
+ * is sent. After the request has been fully configured but not yet built, the
+ * request builder is passed into this function for further modification,
+ * after which it is sent out.
+ *
+ * This is useful for altering the requests in a custom manner, such as
+ * adding headers. It could also be used for logging and monitoring.
+ *
+ * @param interceptor A function invoked before creating each request. A value
+ * of null resets the interceptor to a no-op.
+ * @return This object.
+ */
+ public ApiClient setRequestInterceptor(Consumer interceptor) {
+ this.interceptor = interceptor;
+ return this;
+ }
+
+ /**
+ * Get the custom interceptor.
+ *
+ * @return The custom interceptor that was set, or null if there isn't any.
+ */
+ public Consumer getRequestInterceptor() {
+ return interceptor;
+ }
+
+ /**
+ * Set a custom response interceptor.
+ *
+ * This is useful for logging, monitoring or extraction of header variables
+ *
+ * @param interceptor A function invoked before creating each request. A value
+ * of null resets the interceptor to a no-op.
+ * @return This object.
+ */
+ public ApiClient setResponseInterceptor(Consumer> interceptor) {
+ this.responseInterceptor = interceptor;
+ return this;
+ }
+
+ /**
+ * Get the custom response interceptor.
+ *
+ * @return The custom interceptor that was set, or null if there isn't any.
+ */
+ public Consumer> getResponseInterceptor() {
+ return responseInterceptor;
+ }
+
+ /**
+ * Set a custom async response interceptor. Use this interceptor when asyncNative is set to 'true'.
+ *
+ * This is useful for logging, monitoring or extraction of header variables
+ *
+ * @param interceptor A function invoked before creating each request. A value
+ * of null resets the interceptor to a no-op.
+ * @return This object.
+ */
+ public ApiClient setAsyncResponseInterceptor(Consumer> interceptor) {
+ this.asyncResponseInterceptor = interceptor;
+ return this;
+ }
+
+ /**
+ * Get the custom async response interceptor. Use this interceptor when asyncNative is set to 'true'.
+ *
+ * @return The custom interceptor that was set, or null if there isn't any.
+ */
+ public Consumer> getAsyncResponseInterceptor() {
+ return asyncResponseInterceptor;
+ }
+
+ /**
+ * Set the read timeout for the http client.
+ *
+ * This is the value used by default for each request, though it can be
+ * overridden on a per-request basis with a request interceptor.
+ *
+ * @param readTimeout The read timeout used by default by the http client.
+ * Setting this value to null resets the timeout to an
+ * effectively infinite value.
+ * @return This object.
+ */
+ public ApiClient setReadTimeout(Duration readTimeout) {
+ this.readTimeout = readTimeout;
+ return this;
+ }
+
+ /**
+ * Get the read timeout that was set.
+ *
+ * @return The read timeout, or null if no timeout was set. Null represents
+ * an infinite wait time.
+ */
+ public Duration getReadTimeout() {
+ return readTimeout;
+ }
+ /**
+ * Sets the connect timeout (in milliseconds) for the http client.
+ *
+ * In the case where a new connection needs to be established, if
+ * the connection cannot be established within the given {@code
+ * duration}, then {@link HttpClient#send(HttpRequest,BodyHandler)
+ * HttpClient::send} throws an {@link HttpConnectTimeoutException}, or
+ * {@link HttpClient#sendAsync(HttpRequest,BodyHandler)
+ * HttpClient::sendAsync} completes exceptionally with an
+ * {@code HttpConnectTimeoutException}. If a new connection does not
+ * need to be established, for example if a connection can be reused
+ * from a previous request, then this timeout duration has no effect.
+ *
+ * @param connectTimeout connection timeout in milliseconds
+ *
+ * @return This object.
+ */
+ public ApiClient setConnectTimeout(Duration connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ this.builder.connectTimeout(connectTimeout);
+ return this;
+ }
+
+ /**
+ * Get connection timeout (in milliseconds).
+ *
+ * @return Timeout in milliseconds
+ */
+ public Duration getConnectTimeout() {
+ return connectTimeout;
+ }
+
+ /**
+ * Returns the response body InputStream, transparently decoding gzip-compressed
+ * payloads when the server sets {@code Content-Encoding: gzip}.
+ *
+ * @param response HTTP response whose body should be consumed
+ * @return Original or decompressed InputStream for the response body
+ * @throws IOException if the response body cannot be accessed or wrapping fails
+ */
+ public static InputStream getResponseBody(HttpResponse response) throws IOException {
+ if (response == null) {
+ return null;
+ }
+ InputStream body = response.body();
+ if (body == null) {
+ return null;
+ }
+ Optional encoding = response.headers().firstValue("Content-Encoding");
+ if (encoding.isPresent()) {
+ for (String token : encoding.get().split(",")) {
+ if ("gzip".equalsIgnoreCase(token.trim())) {
+ return new GZIPInputStream(body, 8192);
+ }
+ }
+ }
+ return body;
+ }
+
+}
diff --git a/src/main/java/com/regexsolver/api/generated/ApiException.java b/src/main/java/com/regexsolver/api/generated/ApiException.java
new file mode 100644
index 0000000..ce86146
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/ApiException.java
@@ -0,0 +1,92 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+
+package com.regexsolver.api.generated;
+
+import java.net.http.HttpHeaders;
+
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class ApiException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ private int code = 0;
+ private HttpHeaders responseHeaders = null;
+ private String responseBody = null;
+
+ public ApiException() {}
+
+ public ApiException(Throwable throwable) {
+ super(throwable);
+ }
+
+ public ApiException(String message) {
+ super(message);
+ }
+
+ public ApiException(String message, Throwable throwable, int code, HttpHeaders responseHeaders, String responseBody) {
+ super(message, throwable);
+ this.code = code;
+ this.responseHeaders = responseHeaders;
+ this.responseBody = responseBody;
+ }
+
+ public ApiException(String message, int code, HttpHeaders responseHeaders, String responseBody) {
+ this(message, (Throwable) null, code, responseHeaders, responseBody);
+ }
+
+ public ApiException(String message, Throwable throwable, int code, HttpHeaders responseHeaders) {
+ this(message, throwable, code, responseHeaders, null);
+ }
+
+ public ApiException(int code, HttpHeaders responseHeaders, String responseBody) {
+ this((String) null, (Throwable) null, code, responseHeaders, responseBody);
+ }
+
+ public ApiException(int code, String message) {
+ super(message);
+ this.code = code;
+ }
+
+ public ApiException(int code, String message, HttpHeaders responseHeaders, String responseBody) {
+ this(code, message);
+ this.responseHeaders = responseHeaders;
+ this.responseBody = responseBody;
+ }
+
+ /**
+ * Get the HTTP status code.
+ *
+ * @return HTTP status code
+ */
+ public int getCode() {
+ return code;
+ }
+
+ /**
+ * Get the HTTP response headers.
+ *
+ * @return Headers as an HttpHeaders object
+ */
+ public HttpHeaders getResponseHeaders() {
+ return responseHeaders;
+ }
+
+ /**
+ * Get the HTTP response body.
+ *
+ * @return Response body in the form of string
+ */
+ public String getResponseBody() {
+ return responseBody;
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/generated/ApiResponse.java b/src/main/java/com/regexsolver/api/generated/ApiResponse.java
new file mode 100644
index 0000000..435f51e
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/ApiResponse.java
@@ -0,0 +1,60 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+
+package com.regexsolver.api.generated;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * API response returned by API call.
+ *
+ * @param The type of data that is deserialized from response body
+ */
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class ApiResponse {
+ final private int statusCode;
+ final private Map> headers;
+ final private T data;
+
+ /**
+ * @param statusCode The status code of HTTP response
+ * @param headers The headers of HTTP response
+ */
+ public ApiResponse(int statusCode, Map> headers) {
+ this(statusCode, headers, null);
+ }
+
+ /**
+ * @param statusCode The status code of HTTP response
+ * @param headers The headers of HTTP response
+ * @param data The object deserialized from response bod
+ */
+ public ApiResponse(int statusCode, Map> headers, T data) {
+ this.statusCode = statusCode;
+ this.headers = headers;
+ this.data = data;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public Map> getHeaders() {
+ return headers;
+ }
+
+ public T getData() {
+ return data;
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/generated/Configuration.java b/src/main/java/com/regexsolver/api/generated/Configuration.java
new file mode 100644
index 0000000..47d3997
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/Configuration.java
@@ -0,0 +1,63 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+
+package com.regexsolver.api.generated;
+
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class Configuration {
+ public static final String VERSION = "1.1.0";
+
+ private static final AtomicReference defaultApiClient = new AtomicReference<>();
+ private static volatile Supplier apiClientFactory = ApiClient::new;
+
+ /**
+ * Get the default API client, which would be used when creating API instances without providing an API client.
+ *
+ * @return Default API client
+ */
+ public static ApiClient getDefaultApiClient() {
+ ApiClient client = defaultApiClient.get();
+ if (client == null) {
+ client = defaultApiClient.updateAndGet(val -> {
+ if (val != null) { // changed by another thread
+ return val;
+ }
+ return apiClientFactory.get();
+ });
+ }
+ return client;
+ }
+
+ /**
+ * Set the default API client, which would be used when creating API instances without providing an API client.
+ *
+ * @param apiClient API client
+ */
+ public static void setDefaultApiClient(ApiClient apiClient) {
+ defaultApiClient.set(apiClient);
+ }
+
+ /**
+ * set the callback used to create new ApiClient objects
+ */
+ public static void setApiClientFactory(Supplier factory) {
+ apiClientFactory = Objects.requireNonNull(factory);
+ }
+
+ private Configuration() {
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/regexsolver/api/generated/JSON.java b/src/main/java/com/regexsolver/api/generated/JSON.java
new file mode 100644
index 0000000..87e6757
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/JSON.java
@@ -0,0 +1,261 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+
+package com.regexsolver.api.generated;
+
+import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.regexsolver.api.generated.model.*;
+
+import java.text.DateFormat;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class JSON {
+ private ObjectMapper mapper;
+
+ public JSON() {
+ mapper = JsonMapper.builder()
+ .serializationInclusion(JsonInclude.Include.NON_NULL)
+ .disable(MapperFeature.ALLOW_COERCION_OF_SCALARS)
+ .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
+ .enable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE)
+ .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
+ .enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
+ .enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
+ .defaultDateFormat(new RFC3339DateFormat())
+ .addModule(new JavaTimeModule())
+ .build();
+ }
+
+ /**
+ * Set the date format for JSON (de)serialization with Date properties.
+ *
+ * @param dateFormat Date format
+ */
+ public void setDateFormat(DateFormat dateFormat) {
+ mapper.setDateFormat(dateFormat);
+ }
+
+ /**
+ * Get the object mapper
+ *
+ * @return object mapper
+ */
+ public ObjectMapper getMapper() { return mapper; }
+
+ /**
+ * Returns the target model class that should be used to deserialize the input data.
+ * The discriminator mappings are used to determine the target model class.
+ *
+ * @param node The input data.
+ * @param modelClass The class that contains the discriminator mappings.
+ *
+ * @return the target model class.
+ */
+ public static Class> getClassForElement(JsonNode node, Class> modelClass) {
+ ClassDiscriminatorMapping cdm = modelDiscriminators.get(modelClass);
+ if (cdm != null) {
+ return cdm.getClassForElement(node, new HashSet>());
+ }
+ return null;
+ }
+
+ /**
+ * Helper class to register the discriminator mappings.
+ */
+ @jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+ private static class ClassDiscriminatorMapping {
+ // The model class name.
+ Class> modelClass;
+ // The name of the discriminator property.
+ String discriminatorName;
+ // The discriminator mappings for a model class.
+ Map> discriminatorMappings;
+
+ // Constructs a new class discriminator.
+ ClassDiscriminatorMapping(Class> cls, String propertyName, Map> mappings) {
+ modelClass = cls;
+ discriminatorName = propertyName;
+ discriminatorMappings = new HashMap>();
+ if (mappings != null) {
+ discriminatorMappings.putAll(mappings);
+ }
+ }
+
+ // Return the name of the discriminator property for this model class.
+ String getDiscriminatorPropertyName() {
+ return discriminatorName;
+ }
+
+ // Return the discriminator value or null if the discriminator is not
+ // present in the payload.
+ String getDiscriminatorValue(JsonNode node) {
+ // Determine the value of the discriminator property in the input data.
+ if (discriminatorName != null) {
+ // Get the value of the discriminator property, if present in the input payload.
+ node = node.get(discriminatorName);
+ if (node != null && node.isValueNode()) {
+ String discrValue = node.asText();
+ if (discrValue != null) {
+ return discrValue;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the target model class that should be used to deserialize the input data.
+ * This function can be invoked for anyOf/oneOf composed models with discriminator mappings.
+ * The discriminator mappings are used to determine the target model class.
+ *
+ * @param node The input data.
+ * @param visitedClasses The set of classes that have already been visited.
+ *
+ * @return the target model class.
+ */
+ Class> getClassForElement(JsonNode node, Set> visitedClasses) {
+ if (visitedClasses.contains(modelClass)) {
+ // Class has already been visited.
+ return null;
+ }
+ // Determine the value of the discriminator property in the input data.
+ String discrValue = getDiscriminatorValue(node);
+ if (discrValue == null) {
+ return null;
+ }
+ Class> cls = discriminatorMappings.get(discrValue);
+ // It may not be sufficient to return this cls directly because that target class
+ // may itself be a composed schema, possibly with its own discriminator.
+ visitedClasses.add(modelClass);
+ for (Class> childClass : discriminatorMappings.values()) {
+ ClassDiscriminatorMapping childCdm = modelDiscriminators.get(childClass);
+ if (childCdm == null) {
+ continue;
+ }
+ if (!discriminatorName.equals(childCdm.discriminatorName)) {
+ discrValue = getDiscriminatorValue(node);
+ if (discrValue == null) {
+ continue;
+ }
+ }
+ if (childCdm != null) {
+ // Recursively traverse the discriminator mappings.
+ Class> childDiscr = childCdm.getClassForElement(node, visitedClasses);
+ if (childDiscr != null) {
+ return childDiscr;
+ }
+ }
+ }
+ return cls;
+ }
+ }
+
+ /**
+ * Returns true if inst is an instance of modelClass in the OpenAPI model hierarchy.
+ *
+ * The Java class hierarchy is not implemented the same way as the OpenAPI model hierarchy,
+ * so it's not possible to use the instanceof keyword.
+ *
+ * @param modelClass A OpenAPI model class.
+ * @param inst The instance object.
+ * @param visitedClasses The set of classes that have already been visited.
+ *
+ * @return true if inst is an instance of modelClass in the OpenAPI model hierarchy.
+ */
+ public static boolean isInstanceOf(Class> modelClass, Object inst, Set> visitedClasses) {
+ if (modelClass.isInstance(inst)) {
+ // This handles the 'allOf' use case with single parent inheritance.
+ return true;
+ }
+ if (visitedClasses.contains(modelClass)) {
+ // This is to prevent infinite recursion when the composed schemas have
+ // a circular dependency.
+ return false;
+ }
+ visitedClasses.add(modelClass);
+
+ // Traverse the oneOf/anyOf composed schemas.
+ Map> descendants = modelDescendants.get(modelClass);
+ if (descendants != null) {
+ for (Class> childType : descendants.values()) {
+ if (isInstanceOf(childType, inst, visitedClasses)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A map of discriminators for all model classes.
+ */
+ private static Map, ClassDiscriminatorMapping> modelDiscriminators = new HashMap<>();
+
+ /**
+ * A map of oneOf/anyOf descendants for each model class.
+ */
+ private static Map, Map>> modelDescendants = new HashMap<>();
+
+ /**
+ * Register a model class discriminator.
+ *
+ * @param modelClass the model class
+ * @param discriminatorPropertyName the name of the discriminator property
+ * @param mappings a map with the discriminator mappings.
+ */
+ public static void registerDiscriminator(Class> modelClass, String discriminatorPropertyName, Map> mappings) {
+ ClassDiscriminatorMapping m = new ClassDiscriminatorMapping(modelClass, discriminatorPropertyName, mappings);
+ modelDiscriminators.put(modelClass, m);
+ }
+
+ /**
+ * Register the oneOf/anyOf descendants of the modelClass.
+ *
+ * @param modelClass the model class
+ * @param descendants a map of oneOf/anyOf descendants.
+ */
+ public static void registerDescendants(Class> modelClass, Map> descendants) {
+ modelDescendants.put(modelClass, descendants);
+ }
+
+ private static JSON json;
+
+ static {
+ json = new JSON();
+ }
+
+ /**
+ * Get the default JSON instance.
+ *
+ * @return the default JSON instance
+ */
+ public static JSON getDefault() {
+ return json;
+ }
+
+ /**
+ * Set the default JSON instance.
+ *
+ * @param json JSON instance to be used
+ */
+ public static void setDefault(JSON json) {
+ JSON.json = json;
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/generated/Pair.java b/src/main/java/com/regexsolver/api/generated/Pair.java
new file mode 100644
index 0000000..021d2db
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/Pair.java
@@ -0,0 +1,37 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+
+package com.regexsolver.api.generated;
+
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class Pair {
+ private final String name;
+ private final String value;
+
+ public Pair(String name, String value) {
+ this.name = isValidString(name) ? name : "";
+ this.value = isValidString(value) ? value : "";
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ private static boolean isValidString(String arg) {
+ return arg != null;
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/generated/RFC3339DateFormat.java b/src/main/java/com/regexsolver/api/generated/RFC3339DateFormat.java
new file mode 100644
index 0000000..ad89cfe
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/RFC3339DateFormat.java
@@ -0,0 +1,57 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+package com.regexsolver.api.generated;
+
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.util.Date;
+import java.text.DecimalFormat;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+import com.fasterxml.jackson.databind.util.StdDateFormat;
+
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class RFC3339DateFormat extends DateFormat {
+ private static final long serialVersionUID = 1L;
+ private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC");
+
+ private final StdDateFormat fmt = new StdDateFormat()
+ .withTimeZone(TIMEZONE_Z)
+ .withColonInTimeZone(true);
+
+ public RFC3339DateFormat() {
+ this.calendar = new GregorianCalendar();
+ this.numberFormat = new DecimalFormat();
+ }
+
+ @Override
+ public Date parse(String source) {
+ return parse(source, new ParsePosition(0));
+ }
+
+ @Override
+ public Date parse(String source, ParsePosition pos) {
+ return fmt.parse(source, pos);
+ }
+
+ @Override
+ public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
+ return fmt.format(date, toAppendTo, fieldPosition);
+ }
+
+ @Override
+ public Object clone() {
+ return super.clone();
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/generated/RFC3339InstantDeserializer.java b/src/main/java/com/regexsolver/api/generated/RFC3339InstantDeserializer.java
new file mode 100644
index 0000000..7b9f9ce
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/RFC3339InstantDeserializer.java
@@ -0,0 +1,100 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+package com.regexsolver.api.generated;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeFeature;
+import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer;
+
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class RFC3339InstantDeserializer extends InstantDeserializer {
+ private static final long serialVersionUID = 1L;
+ private final static boolean DEFAULT_NORMALIZE_ZONE_ID = JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID.enabledByDefault();
+ private final static boolean DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
+ = JavaTimeFeature.ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS.enabledByDefault();
+
+ public static final RFC3339InstantDeserializer INSTANT = new RFC3339InstantDeserializer<>(
+ Instant.class, DateTimeFormatter.ISO_INSTANT,
+ Instant::from,
+ a -> Instant.ofEpochMilli( a.value ),
+ a -> Instant.ofEpochSecond( a.integer, a.fraction ),
+ null,
+ true, // yes, replace zero offset with Z
+ DEFAULT_NORMALIZE_ZONE_ID,
+ DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
+ );
+
+ public static final RFC3339InstantDeserializer OFFSET_DATE_TIME = new RFC3339InstantDeserializer<>(
+ OffsetDateTime.class, DateTimeFormatter.ISO_OFFSET_DATE_TIME,
+ OffsetDateTime::from,
+ a -> OffsetDateTime.ofInstant( Instant.ofEpochMilli( a.value ), a.zoneId ),
+ a -> OffsetDateTime.ofInstant( Instant.ofEpochSecond( a.integer, a.fraction ), a.zoneId ),
+ (d, z) -> ( d.isEqual( OffsetDateTime.MIN ) || d.isEqual( OffsetDateTime.MAX ) ?
+ d :
+ d.withOffsetSameInstant( z.getRules().getOffset( d.toLocalDateTime() ) ) ),
+ true, // yes, replace zero offset with Z
+ DEFAULT_NORMALIZE_ZONE_ID,
+ DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
+ );
+
+ public static final RFC3339InstantDeserializer ZONED_DATE_TIME = new RFC3339InstantDeserializer<>(
+ ZonedDateTime.class, DateTimeFormatter.ISO_ZONED_DATE_TIME,
+ ZonedDateTime::from,
+ a -> ZonedDateTime.ofInstant( Instant.ofEpochMilli( a.value ), a.zoneId ),
+ a -> ZonedDateTime.ofInstant( Instant.ofEpochSecond( a.integer, a.fraction ), a.zoneId ),
+ ZonedDateTime::withZoneSameInstant,
+ false, // keep zero offset and Z separate since zones explicitly supported
+ DEFAULT_NORMALIZE_ZONE_ID,
+ DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
+ );
+
+ protected RFC3339InstantDeserializer(
+ Class supportedType,
+ DateTimeFormatter formatter,
+ Function parsedToValue,
+ Function fromMilliseconds,
+ Function fromNanoseconds,
+ BiFunction adjust,
+ boolean replaceZeroOffsetAsZ,
+ boolean normalizeZoneId,
+ boolean readNumericStringsAsTimestamp) {
+ super(
+ supportedType,
+ formatter,
+ parsedToValue,
+ fromMilliseconds,
+ fromNanoseconds,
+ adjust,
+ replaceZeroOffsetAsZ,
+ normalizeZoneId,
+ readNumericStringsAsTimestamp
+ );
+ }
+
+ @Override
+ protected T _fromString(JsonParser p, DeserializationContext ctxt, String string0) throws IOException {
+ return super._fromString(p, ctxt, string0.replace( ' ', 'T' ));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/regexsolver/api/generated/RFC3339JavaTimeModule.java b/src/main/java/com/regexsolver/api/generated/RFC3339JavaTimeModule.java
new file mode 100644
index 0000000..aa14b1e
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/RFC3339JavaTimeModule.java
@@ -0,0 +1,39 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+package com.regexsolver.api.generated;
+
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZonedDateTime;
+
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.Module.SetupContext;
+
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class RFC3339JavaTimeModule extends SimpleModule {
+ private static final long serialVersionUID = 1L;
+
+ public RFC3339JavaTimeModule() {
+ super("RFC3339JavaTimeModule");
+ }
+
+ @Override
+ public void setupModule(SetupContext context) {
+ super.setupModule(context);
+
+ addDeserializer(Instant.class, RFC3339InstantDeserializer.INSTANT);
+ addDeserializer(OffsetDateTime.class, RFC3339InstantDeserializer.OFFSET_DATE_TIME);
+ addDeserializer(ZonedDateTime.class, RFC3339InstantDeserializer.ZONED_DATE_TIME);
+ }
+
+}
diff --git a/src/main/java/com/regexsolver/api/generated/ServerConfiguration.java b/src/main/java/com/regexsolver/api/generated/ServerConfiguration.java
new file mode 100644
index 0000000..86872b4
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/ServerConfiguration.java
@@ -0,0 +1,72 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+
+package com.regexsolver.api.generated;
+
+import java.util.Map;
+
+/**
+ * Representing a Server configuration.
+ */
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class ServerConfiguration {
+ public String URL;
+ public String description;
+ public Map variables;
+
+ /**
+ * @param URL A URL to the target host.
+ * @param description A description of the host designated by the URL.
+ * @param variables A map between a variable name and its value. The value is used for substitution in the server's URL template.
+ */
+ public ServerConfiguration(String URL, String description, Map variables) {
+ this.URL = URL;
+ this.description = description;
+ this.variables = variables;
+ }
+
+ /**
+ * Format URL template using given variables.
+ *
+ * @param variables A map between a variable name and its value.
+ * @return Formatted URL.
+ */
+ public String URL(Map variables) {
+ String url = this.URL;
+
+ // go through variables and replace placeholders
+ for (Map.Entry variable: this.variables.entrySet()) {
+ String name = variable.getKey();
+ ServerVariable serverVariable = variable.getValue();
+ String value = serverVariable.defaultValue;
+
+ if (variables != null && variables.containsKey(name)) {
+ value = variables.get(name);
+ if (serverVariable.enumValues.size() > 0 && !serverVariable.enumValues.contains(value)) {
+ throw new IllegalArgumentException("The variable " + name + " in the server URL has invalid value " + value + ".");
+ }
+ }
+ url = url.replace("{" + name + "}", value);
+ }
+ return url;
+ }
+
+ /**
+ * Format URL template using default server variables.
+ *
+ * @return Formatted URL.
+ */
+ public String URL() {
+ return URL(null);
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/generated/ServerVariable.java b/src/main/java/com/regexsolver/api/generated/ServerVariable.java
new file mode 100644
index 0000000..43b8681
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/ServerVariable.java
@@ -0,0 +1,37 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+
+package com.regexsolver.api.generated;
+
+import java.util.HashSet;
+
+/**
+ * Representing a Server Variable for server URL template substitution.
+ */
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class ServerVariable {
+ public String description;
+ public String defaultValue;
+ public HashSet enumValues = null;
+
+ /**
+ * @param description A description for the server variable.
+ * @param defaultValue The default value to use for substitution.
+ * @param enumValues An enumeration of string values to be used if the substitution options are from a limited set.
+ */
+ public ServerVariable(String description, String defaultValue, HashSet enumValues) {
+ this.description = description;
+ this.defaultValue = defaultValue;
+ this.enumValues = enumValues;
+ }
+}
diff --git a/src/main/java/com/regexsolver/api/generated/api/AccountApi.java b/src/main/java/com/regexsolver/api/generated/api/AccountApi.java
new file mode 100644
index 0000000..e396454
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/api/AccountApi.java
@@ -0,0 +1,288 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+package com.regexsolver.api.generated.api;
+
+import com.regexsolver.api.generated.ApiClient;
+import com.regexsolver.api.generated.ApiException;
+import com.regexsolver.api.generated.ApiResponse;
+import com.regexsolver.api.generated.Configuration;
+import com.regexsolver.api.generated.Pair;
+
+import com.regexsolver.api.generated.model.ErrorResponse401Dto;
+import com.regexsolver.api.generated.model.ErrorResponseDto;
+import com.regexsolver.api.generated.model.Limits200ResponseDto;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.http.HttpRequest;
+import java.nio.channels.Channels;
+import java.nio.channels.Pipe;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+
+import java.util.ArrayList;
+import java.util.StringJoiner;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import java.util.concurrent.CompletableFuture;
+
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class AccountApi {
+ /**
+ * Utility class for extending HttpRequest.Builder functionality.
+ */
+ private static class HttpRequestBuilderExtensions {
+ /**
+ * Adds additional headers to the provided HttpRequest.Builder. Useful for adding method/endpoint specific headers.
+ *
+ * @param builder the HttpRequest.Builder to which headers will be added
+ * @param headers a map of header names and values to add; may be null
+ * @return the same HttpRequest.Builder instance with the additional headers set
+ */
+ static HttpRequest.Builder withAdditionalHeaders(HttpRequest.Builder builder, Map headers) {
+ if (headers != null) {
+ for (Map.Entry entry : headers.entrySet()) {
+ builder.header(entry.getKey(), entry.getValue());
+ }
+ }
+ return builder;
+ }
+ }
+ private final HttpClient memberVarHttpClient;
+ private final ObjectMapper memberVarObjectMapper;
+ private final String memberVarBaseUri;
+ private final Consumer memberVarInterceptor;
+ private final Duration memberVarReadTimeout;
+ private final Consumer> memberVarResponseInterceptor;
+ private final Consumer> memberVarAsyncResponseInterceptor;
+
+ public AccountApi() {
+ this(Configuration.getDefaultApiClient());
+ }
+
+ public AccountApi(ApiClient apiClient) {
+ memberVarHttpClient = apiClient.getHttpClient();
+ memberVarObjectMapper = apiClient.getObjectMapper();
+ memberVarBaseUri = apiClient.getBaseUri();
+ memberVarInterceptor = apiClient.getRequestInterceptor();
+ memberVarReadTimeout = apiClient.getReadTimeout();
+ memberVarResponseInterceptor = apiClient.getResponseInterceptor();
+ memberVarAsyncResponseInterceptor = apiClient.getAsyncResponseInterceptor();
+ }
+
+
+ private ApiException getApiException(String operationId, HttpResponse response) {
+ try {
+ InputStream responseBody = ApiClient.getResponseBody(response);
+ String body = null;
+ if (responseBody != null) {
+ body = new String(responseBody.readAllBytes());
+ responseBody.close();
+ }
+ String message = formatExceptionMessage(operationId, response.statusCode(), body);
+ return new ApiException(response.statusCode(), message, response.headers(), body);
+ } catch (IOException e) {
+ return new ApiException(e);
+ }
+ }
+
+ private String formatExceptionMessage(String operationId, int statusCode, String body) {
+ if (body == null || body.isEmpty()) {
+ body = "[no body]";
+ }
+ return operationId + " call failed with: " + statusCode + " - " + body;
+ }
+
+ /**
+ * Download file from the given response.
+ *
+ * @param response Response
+ * @return File
+ * @throws ApiException If fail to read file content from response and write to disk
+ */
+ public File downloadFileFromResponse(HttpResponse response, InputStream responseBody) throws ApiException {
+ if (responseBody == null) {
+ throw new ApiException(new IOException("Response body is empty"));
+ }
+ try {
+ File file = prepareDownloadFile(response);
+ java.nio.file.Files.copy(responseBody, file.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+ return file;
+ } catch (IOException e) {
+ throw new ApiException(e);
+ }
+ }
+
+ /**
+ * Prepare the file for download from the response.
+ *
+ * @param response a {@link java.net.http.HttpResponse} object.
+ * @return a {@link java.io.File} object.
+ * @throws java.io.IOException if any.
+ */
+ private File prepareDownloadFile(HttpResponse response) throws IOException {
+ String filename = null;
+ java.util.Optional contentDisposition = response.headers().firstValue("Content-Disposition");
+ if (contentDisposition.isPresent() && !"".equals(contentDisposition.get())) {
+ // Get filename from the Content-Disposition header.
+ java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?");
+ java.util.regex.Matcher matcher = pattern.matcher(contentDisposition.get());
+ if (matcher.find())
+ filename = matcher.group(1);
+ }
+ File file = null;
+ if (filename != null) {
+ java.nio.file.Path tempDir = java.nio.file.Files.createTempDirectory("swagger-gen-native");
+ java.nio.file.Path filePath = java.nio.file.Files.createFile(tempDir.resolve(filename));
+ file = filePath.toFile();
+ tempDir.toFile().deleteOnExit(); // best effort cleanup
+ file.deleteOnExit(); // best effort cleanup
+ } else {
+ file = java.nio.file.Files.createTempFile("download-", "").toFile();
+ file.deleteOnExit(); // best effort cleanup
+ }
+ return file;
+ }
+
+ /**
+ * Limits
+ * Return the plan limits applying to the account.
+ * @return CompletableFuture<Limits200ResponseDto>
+ * @throws ApiException if fails to make API call
+ */
+ public CompletableFuture limits() throws ApiException {
+ return limits(null);
+ }
+
+ /**
+ * Limits
+ * Return the plan limits applying to the account.
+ * @param headers Optional headers to include in the request
+ * @return CompletableFuture<Limits200ResponseDto>
+ * @throws ApiException if fails to make API call
+ */
+ public CompletableFuture limits(Map headers) throws ApiException {
+ try {
+ return limitsWithHttpInfo(headers)
+ .thenApply(ApiResponse::getData);
+ }
+ catch (ApiException e) {
+ return CompletableFuture.failedFuture(e);
+ }
+ }
+
+ /**
+ * Limits
+ * Return the plan limits applying to the account.
+ * @return CompletableFuture<ApiResponse<Limits200ResponseDto>>
+ * @throws ApiException if fails to make API call
+ */
+ public CompletableFuture> limitsWithHttpInfo() throws ApiException {
+ return limitsWithHttpInfo(null);
+ }
+
+ /**
+ * Limits
+ * Return the plan limits applying to the account.
+ * @param headers Optional headers to include in the request
+ * @return CompletableFuture<ApiResponse<Limits200ResponseDto>>
+ * @throws ApiException if fails to make API call
+ */
+ public CompletableFuture> limitsWithHttpInfo(Map headers) throws ApiException {
+ try {
+ HttpRequest.Builder localVarRequestBuilder = limitsRequestBuilder(headers);
+ return memberVarHttpClient.sendAsync(
+ localVarRequestBuilder.build(),
+ HttpResponse.BodyHandlers.ofInputStream()).thenComposeAsync(localVarResponse -> {
+ if (memberVarAsyncResponseInterceptor != null) {
+ memberVarAsyncResponseInterceptor.accept(localVarResponse);
+ }
+ if (localVarResponse.statusCode()/ 100 != 2) {
+ return CompletableFuture.failedFuture(getApiException("limits", localVarResponse));
+ }
+ try {
+ InputStream localVarResponseBody = ApiClient.getResponseBody(localVarResponse);
+ try {
+ if (localVarResponseBody == null) {
+ return CompletableFuture.completedFuture(
+ new ApiResponse(
+ localVarResponse.statusCode(),
+ localVarResponse.headers().map(),
+ null
+ )
+ );
+ }
+
+
+ String responseBody = new String(localVarResponseBody.readAllBytes());
+ Limits200ResponseDto responseValue = responseBody.isBlank()? null: memberVarObjectMapper.readValue(responseBody, new TypeReference() {});
+
+ return CompletableFuture.completedFuture(
+ new ApiResponse(
+ localVarResponse.statusCode(),
+ localVarResponse.headers().map(),
+ responseValue
+ )
+ );
+ } finally {
+ if (localVarResponseBody != null) {
+ localVarResponseBody.close();
+ }
+ }
+ } catch (IOException e) {
+ return CompletableFuture.failedFuture(new ApiException(e));
+ }
+ }
+ );
+ }
+ catch (ApiException e) {
+ return CompletableFuture.failedFuture(e);
+ }
+ }
+
+ private HttpRequest.Builder limitsRequestBuilder(Map headers) throws ApiException {
+
+ HttpRequest.Builder localVarRequestBuilder = HttpRequest.newBuilder();
+
+ String localVarPath = "/account/limits";
+
+ localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath));
+
+ localVarRequestBuilder.header("Accept", "application/json");
+
+ localVarRequestBuilder.method("GET", HttpRequest.BodyPublishers.noBody());
+ if (memberVarReadTimeout != null) {
+ localVarRequestBuilder.timeout(memberVarReadTimeout);
+ }
+ // Add custom headers if provided
+ localVarRequestBuilder = HttpRequestBuilderExtensions.withAdditionalHeaders(localVarRequestBuilder, headers);
+ if (memberVarInterceptor != null) {
+ memberVarInterceptor.accept(localVarRequestBuilder);
+ }
+ return localVarRequestBuilder;
+ }
+
+}
diff --git a/src/main/java/com/regexsolver/api/generated/api/AnalyzeApi.java b/src/main/java/com/regexsolver/api/generated/api/AnalyzeApi.java
new file mode 100644
index 0000000..ee7f989
--- /dev/null
+++ b/src/main/java/com/regexsolver/api/generated/api/AnalyzeApi.java
@@ -0,0 +1,1497 @@
+/*
+ * RegexSolver API
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
+ *
+ * The version of the OpenAPI document: 1.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+package com.regexsolver.api.generated.api;
+
+import com.regexsolver.api.generated.ApiClient;
+import com.regexsolver.api.generated.ApiException;
+import com.regexsolver.api.generated.ApiResponse;
+import com.regexsolver.api.generated.Configuration;
+import com.regexsolver.api.generated.Pair;
+
+import com.regexsolver.api.generated.model.Cardinality200ResponseDto;
+import com.regexsolver.api.generated.model.Dot200ResponseDto;
+import com.regexsolver.api.generated.model.Empty200ResponseDto;
+import com.regexsolver.api.generated.model.ErrorResponse400Dto;
+import com.regexsolver.api.generated.model.ErrorResponse401Dto;
+import com.regexsolver.api.generated.model.ErrorResponse403Dto;
+import com.regexsolver.api.generated.model.ErrorResponseDto;
+import com.regexsolver.api.generated.model.Length200ResponseDto;
+import com.regexsolver.api.generated.model.TermRequestDto;
+import com.regexsolver.api.generated.model.TwoTermsRequestDto;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.http.HttpRequest;
+import java.nio.channels.Channels;
+import java.nio.channels.Pipe;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+
+import java.util.ArrayList;
+import java.util.StringJoiner;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import java.util.concurrent.CompletableFuture;
+
+@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2026-08-04T20:54:20.558114023+02:00[Europe/Zurich]", comments = "Generator version: 7.21.0")
+public class AnalyzeApi {
+ /**
+ * Utility class for extending HttpRequest.Builder functionality.
+ */
+ private static class HttpRequestBuilderExtensions {
+ /**
+ * Adds additional headers to the provided HttpRequest.Builder. Useful for adding method/endpoint specific headers.
+ *
+ * @param builder the HttpRequest.Builder to which headers will be added
+ * @param headers a map of header names and values to add; may be null
+ * @return the same HttpRequest.Builder instance with the additional headers set
+ */
+ static HttpRequest.Builder withAdditionalHeaders(HttpRequest.Builder builder, Map headers) {
+ if (headers != null) {
+ for (Map.Entry entry : headers.entrySet()) {
+ builder.header(entry.getKey(), entry.getValue());
+ }
+ }
+ return builder;
+ }
+ }
+ private final HttpClient memberVarHttpClient;
+ private final ObjectMapper memberVarObjectMapper;
+ private final String memberVarBaseUri;
+ private final Consumer memberVarInterceptor;
+ private final Duration memberVarReadTimeout;
+ private final Consumer> memberVarResponseInterceptor;
+ private final Consumer> memberVarAsyncResponseInterceptor;
+
+ public AnalyzeApi() {
+ this(Configuration.getDefaultApiClient());
+ }
+
+ public AnalyzeApi(ApiClient apiClient) {
+ memberVarHttpClient = apiClient.getHttpClient();
+ memberVarObjectMapper = apiClient.getObjectMapper();
+ memberVarBaseUri = apiClient.getBaseUri();
+ memberVarInterceptor = apiClient.getRequestInterceptor();
+ memberVarReadTimeout = apiClient.getReadTimeout();
+ memberVarResponseInterceptor = apiClient.getResponseInterceptor();
+ memberVarAsyncResponseInterceptor = apiClient.getAsyncResponseInterceptor();
+ }
+
+
+ private ApiException getApiException(String operationId, HttpResponse response) {
+ try {
+ InputStream responseBody = ApiClient.getResponseBody(response);
+ String body = null;
+ if (responseBody != null) {
+ body = new String(responseBody.readAllBytes());
+ responseBody.close();
+ }
+ String message = formatExceptionMessage(operationId, response.statusCode(), body);
+ return new ApiException(response.statusCode(), message, response.headers(), body);
+ } catch (IOException e) {
+ return new ApiException(e);
+ }
+ }
+
+ private String formatExceptionMessage(String operationId, int statusCode, String body) {
+ if (body == null || body.isEmpty()) {
+ body = "[no body]";
+ }
+ return operationId + " call failed with: " + statusCode + " - " + body;
+ }
+
+ /**
+ * Download file from the given response.
+ *
+ * @param response Response
+ * @return File
+ * @throws ApiException If fail to read file content from response and write to disk
+ */
+ public File downloadFileFromResponse(HttpResponse response, InputStream responseBody) throws ApiException {
+ if (responseBody == null) {
+ throw new ApiException(new IOException("Response body is empty"));
+ }
+ try {
+ File file = prepareDownloadFile(response);
+ java.nio.file.Files.copy(responseBody, file.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
+ return file;
+ } catch (IOException e) {
+ throw new ApiException(e);
+ }
+ }
+
+ /**
+ * Prepare the file for download from the response.
+ *
+ * @param response a {@link java.net.http.HttpResponse} object.
+ * @return a {@link java.io.File} object.
+ * @throws java.io.IOException if any.
+ */
+ private File prepareDownloadFile(HttpResponse response) throws IOException {
+ String filename = null;
+ java.util.Optional contentDisposition = response.headers().firstValue("Content-Disposition");
+ if (contentDisposition.isPresent() && !"".equals(contentDisposition.get())) {
+ // Get filename from the Content-Disposition header.
+ java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?");
+ java.util.regex.Matcher matcher = pattern.matcher(contentDisposition.get());
+ if (matcher.find())
+ filename = matcher.group(1);
+ }
+ File file = null;
+ if (filename != null) {
+ java.nio.file.Path tempDir = java.nio.file.Files.createTempDirectory("swagger-gen-native");
+ java.nio.file.Path filePath = java.nio.file.Files.createFile(tempDir.resolve(filename));
+ file = filePath.toFile();
+ tempDir.toFile().deleteOnExit(); // best effort cleanup
+ file.deleteOnExit(); // best effort cleanup
+ } else {
+ file = java.nio.file.Files.createTempFile("download-", "").toFile();
+ file.deleteOnExit(); // best effort cleanup
+ }
+ return file;
+ }
+
+ /**
+ * Cardinality
+ * Compute how many strings the term matches.
+ * @param termRequestDto (required)
+ * @return CompletableFuture<Cardinality200ResponseDto>
+ * @throws ApiException if fails to make API call
+ */
+ public CompletableFuture cardinality(@jakarta.annotation.Nonnull TermRequestDto termRequestDto) throws ApiException {
+ return cardinality(termRequestDto, null);
+ }
+
+ /**
+ * Cardinality
+ * Compute how many strings the term matches.
+ * @param termRequestDto (required)
+ * @param headers Optional headers to include in the request
+ * @return CompletableFuture<Cardinality200ResponseDto>
+ * @throws ApiException if fails to make API call
+ */
+ public CompletableFuture cardinality(@jakarta.annotation.Nonnull TermRequestDto termRequestDto, Map headers) throws ApiException {
+ try {
+ return cardinalityWithHttpInfo(termRequestDto, headers)
+ .thenApply(ApiResponse::getData);
+ }
+ catch (ApiException e) {
+ return CompletableFuture.failedFuture(e);
+ }
+ }
+
+ /**
+ * Cardinality
+ * Compute how many strings the term matches.
+ * @param termRequestDto (required)
+ * @return CompletableFuture<ApiResponse<Cardinality200ResponseDto>>
+ * @throws ApiException if fails to make API call
+ */
+ public CompletableFuture> cardinalityWithHttpInfo(@jakarta.annotation.Nonnull TermRequestDto termRequestDto) throws ApiException {
+ return cardinalityWithHttpInfo(termRequestDto, null);
+ }
+
+ /**
+ * Cardinality
+ * Compute how many strings the term matches.
+ * @param termRequestDto (required)
+ * @param headers Optional headers to include in the request
+ * @return CompletableFuture<ApiResponse<Cardinality200ResponseDto>>
+ * @throws ApiException if fails to make API call
+ */
+ public CompletableFuture> cardinalityWithHttpInfo(@jakarta.annotation.Nonnull TermRequestDto termRequestDto, Map headers) throws ApiException {
+ try {
+ HttpRequest.Builder localVarRequestBuilder = cardinalityRequestBuilder(termRequestDto, headers);
+ return memberVarHttpClient.sendAsync(
+ localVarRequestBuilder.build(),
+ HttpResponse.BodyHandlers.ofInputStream()).thenComposeAsync(localVarResponse -> {
+ if (memberVarAsyncResponseInterceptor != null) {
+ memberVarAsyncResponseInterceptor.accept(localVarResponse);
+ }
+ if (localVarResponse.statusCode()/ 100 != 2) {
+ return CompletableFuture.failedFuture(getApiException("cardinality", localVarResponse));
+ }
+ try {
+ InputStream localVarResponseBody = ApiClient.getResponseBody(localVarResponse);
+ try {
+ if (localVarResponseBody == null) {
+ return CompletableFuture.completedFuture(
+ new ApiResponse(
+ localVarResponse.statusCode(),
+ localVarResponse.headers().map(),
+ null
+ )
+ );
+ }
+
+
+ String responseBody = new String(localVarResponseBody.readAllBytes());
+ Cardinality200ResponseDto responseValue = responseBody.isBlank()? null: memberVarObjectMapper.readValue(responseBody, new TypeReference() {});
+
+ return CompletableFuture.completedFuture(
+ new ApiResponse(
+ localVarResponse.statusCode(),
+ localVarResponse.headers().map(),
+ responseValue
+ )
+ );
+ } finally {
+ if (localVarResponseBody != null) {
+ localVarResponseBody.close();
+ }
+ }
+ } catch (IOException e) {
+ return CompletableFuture.failedFuture(new ApiException(e));
+ }
+ }
+ );
+ }
+ catch (ApiException e) {
+ return CompletableFuture.failedFuture(e);
+ }
+ }
+
+ private HttpRequest.Builder cardinalityRequestBuilder(@jakarta.annotation.Nonnull TermRequestDto termRequestDto, Map headers) throws ApiException {
+ // verify the required parameter 'termRequestDto' is set
+ if (termRequestDto == null) {
+ throw new ApiException(400, "Missing the required parameter 'termRequestDto' when calling cardinality");
+ }
+
+ HttpRequest.Builder localVarRequestBuilder = HttpRequest.newBuilder();
+
+ String localVarPath = "/analyze/cardinality";
+
+ localVarRequestBuilder.uri(URI.create(memberVarBaseUri + localVarPath));
+
+ localVarRequestBuilder.header("Content-Type", "application/json");
+ localVarRequestBuilder.header("Accept", "application/json");
+
+ try {
+ byte[] localVarPostBody = memberVarObjectMapper.writeValueAsBytes(termRequestDto);
+ localVarRequestBuilder.method("POST", HttpRequest.BodyPublishers.ofByteArray(localVarPostBody));
+ } catch (IOException e) {
+ throw new ApiException(e);
+ }
+ if (memberVarReadTimeout != null) {
+ localVarRequestBuilder.timeout(memberVarReadTimeout);
+ }
+ // Add custom headers if provided
+ localVarRequestBuilder = HttpRequestBuilderExtensions.withAdditionalHeaders(localVarRequestBuilder, headers);
+ if (memberVarInterceptor != null) {
+ memberVarInterceptor.accept(localVarRequestBuilder);
+ }
+ return localVarRequestBuilder;
+ }
+
+ /**
+ * Deterministic
+ * Check if the term's automaton is deterministic. Only a deterministic FAIR guarantees consistent string ordering across paginated /generate/strings requests; call /compute/determinize first if this is false.
+ * @param termRequestDto (required)
+ * @return CompletableFuture<Empty200ResponseDto>
+ * @throws ApiException if fails to make API call
+ */
+ public CompletableFuture deterministic(@jakarta.annotation.Nonnull TermRequestDto termRequestDto) throws ApiException {
+ return deterministic(termRequestDto, null);
+ }
+
+ /**
+ * Deterministic
+ * Check if the term's automaton is deterministic. Only a deterministic FAIR guarantees consistent string ordering across paginated /generate/strings requests; call /compute/determinize first if this is false.
+ * @param termRequestDto (required)
+ * @param headers Optional headers to include in the request
+ * @return CompletableFuture<Empty200ResponseDto>
+ * @throws ApiException if fails to make API call
+ */
+ public CompletableFuture