From d18321c1bbf01dfb5004990e07a2738820dc2b51 Mon Sep 17 00:00:00 2001 From: Mouaad Aallam Date: Mon, 11 Sep 2023 18:08:18 +0200 Subject: [PATCH] rafactor(java): improve `oneOf` types DX (#1990) --- .../java/com/algolia/config/AlgoliaAgent.java | 8 +- .../java/com/algolia/config/ClientConfig.java | 14 +-- .../com/algolia/config/ClientOptions.java | 18 +-- .../main/java/com/algolia/config/Host.java | 10 +- .../com/algolia/internal/HttpRequester.java | 20 ++- .../com/algolia/internal/JsonSerializer.java | 10 +- .../interceptors/AuthInterceptor.java | 4 +- .../interceptors/GzipRequestInterceptor.java | 6 +- .../interceptors/HeaderInterceptor.java | 4 +- .../internal/interceptors/LogInterceptor.java | 10 +- .../internal/interceptors/RetryStrategy.java | 16 +-- .../interceptors/UserAgentInterceptor.java | 4 +- .../java/com/algolia/utils/Parameters.java | 16 +++ generators/build.gradle | 5 - .../algolia/codegen/AlgoliaJavaGenerator.java | 40 +----- .../codegen/AlgoliaKotlinGenerator.java | 90 +------------ .../algolia/codegen/GenericPropagator.java | 31 +++-- .../cts/tests/ParametersWithDataType.java | 83 ++++++++---- .../com/algolia/codegen/utils/OneOfUtils.java | 119 ++++++++++++++++++ .../java/com/algolia/playground/Insights.java | 4 +- .../java/com/algolia/playground/Search.java | 11 +- specs/common/schemas/SearchParams.yml | 2 + templates/java/api.mustache | 70 +++++------ templates/java/api_helpers.mustache | 101 ++------------- templates/java/generic_type.mustache | 2 +- templates/java/model.mustache | 3 +- templates/java/modelEnum.mustache | 6 +- templates/java/oneof_interface.mustache | 93 +++++++------- templates/java/pojo.mustache | 3 +- .../java/tests/maybeConvertOneOf.mustache | 2 +- templates/kotlin/model.mustache | 2 +- 31 files changed, 390 insertions(+), 417 deletions(-) create mode 100644 clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/utils/Parameters.java create mode 100644 generators/src/main/java/com/algolia/codegen/utils/OneOfUtils.java diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/AlgoliaAgent.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/AlgoliaAgent.java index 1d6e5e6ab0..bb8ab8d9ad 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/AlgoliaAgent.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/AlgoliaAgent.java @@ -3,7 +3,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; public final class AlgoliaAgent { @@ -17,7 +17,7 @@ public AlgoliaAgent(String clientVersion) { this.addSegment(new Segment("JVM", System.getProperty("java.version"))); } - public AlgoliaAgent addSegment(@NotNull Segment seg) { + public AlgoliaAgent addSegment(@Nonnull Segment seg) { String segment = seg.toString(); if (!segments.contains(segment)) { segments.add(segment); @@ -26,14 +26,14 @@ public AlgoliaAgent addSegment(@NotNull Segment seg) { return this; } - public AlgoliaAgent addSegments(@NotNull List segments) { + public AlgoliaAgent addSegments(@Nonnull List segments) { for (Segment segment : segments) { addSegment(segment); } return this; } - public AlgoliaAgent removeSegment(@NotNull Segment seg) { + public AlgoliaAgent removeSegment(@Nonnull Segment seg) { segments.remove(seg.toString()); return this; } diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/ClientConfig.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/ClientConfig.java index 7fb25fd904..95333420dc 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/ClientConfig.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/ClientConfig.java @@ -2,20 +2,20 @@ import java.time.Duration; import java.util.Map; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; public interface ClientConfig { - public @NotNull LogLevel getLogLevel(); + public @Nonnull LogLevel getLogLevel(); public Logger getLogger(); - public @NotNull Duration getConnectTimeout(); + public @Nonnull Duration getConnectTimeout(); - public @NotNull Duration getWriteTimeout(); + public @Nonnull Duration getWriteTimeout(); - public @NotNull Duration getReadTimeout(); + public @Nonnull Duration getReadTimeout(); - public @NotNull Map getDefaultHeaders(); + public @Nonnull Map getDefaultHeaders(); - public @NotNull CompressionType getCompressionType(); + public @Nonnull CompressionType getCompressionType(); } diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/ClientOptions.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/ClientOptions.java index 9bd8c07676..7ac6baf80d 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/ClientOptions.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/ClientOptions.java @@ -10,7 +10,7 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.function.Consumer; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; public final class ClientOptions implements ClientConfig { @@ -53,7 +53,7 @@ public ClientOptions() { this.executor = builder.executor != null ? builder.executor : ExecutorUtils.newThreadPool(); } - @NotNull + @Nonnull public List getAlgoliaAgentSegments() { return algoliaAgentSegments; } @@ -62,32 +62,32 @@ public List getHosts() { return hosts; } - @NotNull + @Nonnull public LogLevel getLogLevel() { return logLevel; } - @NotNull + @Nonnull public Duration getConnectTimeout() { return connectTimeout; } - @NotNull + @Nonnull public Duration getWriteTimeout() { return writeTimeout; } - @NotNull + @Nonnull public Duration getReadTimeout() { return readTimeout; } - @NotNull + @Nonnull public Map getDefaultHeaders() { return defaultHeaders; } - @NotNull + @Nonnull public CompressionType getCompressionType() { return compressionType; } @@ -96,7 +96,7 @@ public Requester getCustomRequester() { return customRequester; } - @NotNull + @Nonnull public Logger getLogger() { return logger; } diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/Host.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/Host.java index bb70436f8e..b96b75a105 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/Host.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/config/Host.java @@ -1,7 +1,7 @@ package com.algolia.config; import java.util.Set; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; public final class Host { @@ -11,7 +11,7 @@ public final class Host { private final String scheme; - public Host(@NotNull String url, @NotNull Set callType) { + public Host(@Nonnull String url, @Nonnull Set callType) { this(url, callType, "https"); } @@ -21,17 +21,17 @@ public Host(String url, Set callType, String scheme) { this.scheme = scheme; } - @NotNull + @Nonnull public String getUrl() { return url; } - @NotNull + @Nonnull public Set getCallTypes() { return callTypes; } - @NotNull + @Nonnull public String getScheme() { return scheme; } diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/HttpRequester.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/HttpRequester.java index 86b68f9539..5b3bc91af7 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/HttpRequester.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/HttpRequester.java @@ -14,11 +14,10 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; +import javax.annotation.Nonnull; import okhttp3.*; import okhttp3.internal.http.HttpMethod; import okio.BufferedSink; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * HttpRequester is responsible for making HTTP requests using the OkHttp client. It provides a @@ -62,7 +61,7 @@ public T execute(HttpRequest httpRequest, RequestOptions requestOptions, Typ } /** Core method to execute an HTTP request and handle the response. */ - private T execute(@NotNull HttpRequest httpRequest, RequestOptions requestOptions, JavaType returnType) { + private T execute(@Nonnull HttpRequest httpRequest, RequestOptions requestOptions, JavaType returnType) { if (isClosed.get()) { throw new IllegalStateException("HttpRequester is closed"); } @@ -99,8 +98,8 @@ private T execute(@NotNull HttpRequest httpRequest, RequestOptions requestOp } /** Constructs the URL for the HTTP request. */ - @NotNull - private static HttpUrl createHttpUrl(@NotNull HttpRequest request, RequestOptions requestOptions) { + @Nonnull + private static HttpUrl createHttpUrl(@Nonnull HttpRequest request, RequestOptions requestOptions) { HttpUrl.Builder urlBuilder = new HttpUrl.Builder() .scheme("https") .host("algolia.com") // will be overridden by the retry strategy @@ -126,25 +125,24 @@ private RequestBody createRequestBody(HttpRequest httpRequest) { } /** Serializes the request body into JSON format. */ - @NotNull + @Nonnull private RequestBody buildRequestBody(Object requestBody) { return new RequestBody() { - @Nullable @Override public MediaType contentType() { return JSON_MEDIA_TYPE; } @Override - public void writeTo(@NotNull BufferedSink bufferedSink) { + public void writeTo(@Nonnull BufferedSink bufferedSink) { serializer.serialize(bufferedSink.outputStream(), requestBody); } }; } /** Constructs the headers for the HTTP request. */ - @NotNull - private Headers createHeaders(@NotNull HttpRequest request, RequestOptions requestOptions) { + @Nonnull + private Headers createHeaders(@Nonnull HttpRequest request, RequestOptions requestOptions) { Headers.Builder builder = new Headers.Builder(); request.getHeaders().forEach(builder::add); if (requestOptions != null) { @@ -154,7 +152,7 @@ private Headers createHeaders(@NotNull HttpRequest request, RequestOptions reque } /** Returns a suitable OkHttpClient instance based on the provided request options. */ - @NotNull + @Nonnull private OkHttpClient getOkHttpClient(RequestOptions requestOptions) { // Return the default client if no request options are provided. if (requestOptions == null) return httpClient; diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/JsonSerializer.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/JsonSerializer.java index ff520fc0cb..15f989c9e2 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/JsonSerializer.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/JsonSerializer.java @@ -10,7 +10,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.function.Consumer; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; /** * Utility class for JSON serialization and deserialization using Jackson. It provides functionality @@ -29,7 +29,7 @@ public static Builder builder() { * * @param mapper The Jackson ObjectMapper to be used for JSON operations. */ - JsonSerializer(@NotNull ObjectMapper mapper) { + JsonSerializer(@Nonnull ObjectMapper mapper) { this.mapper = mapper; } @@ -39,7 +39,7 @@ public static Builder builder() { * @param stream output steam. * @param object The Java object to serialize. */ - public void serialize(OutputStream stream, @NotNull Object object) { + public void serialize(OutputStream stream, @Nonnull Object object) { try { mapper.writeValue(stream, object); } catch (IOException e) { @@ -63,7 +63,7 @@ public T deserialize(InputStream stream, JavaType returnType) { * @param innerType The parameterized type. * @return A JavaType representation of the parameterized class. */ - public JavaType getJavaType(@NotNull Class returnType, @NotNull Class innerType) { + public JavaType getJavaType(@Nonnull Class returnType, @Nonnull Class innerType) { return mapper.getTypeFactory().constructParametricType(returnType, innerType); } @@ -73,7 +73,7 @@ public JavaType getJavaType(@NotNull Class returnType, @NotNull Class inne * @param returnType The main class type. * @return A JavaType representation of the parameterized class. */ - public JavaType getJavaType(@NotNull TypeReference returnType) { + public JavaType getJavaType(@Nonnull TypeReference returnType) { return mapper.getTypeFactory().constructType(returnType); } diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/AuthInterceptor.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/AuthInterceptor.java index 926d181821..14c25d6a01 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/AuthInterceptor.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/AuthInterceptor.java @@ -1,10 +1,10 @@ package com.algolia.internal.interceptors; import java.io.IOException; +import javax.annotation.Nonnull; import okhttp3.Headers; import okhttp3.Interceptor; import okhttp3.Response; -import org.jetbrains.annotations.NotNull; public final class AuthInterceptor implements Interceptor { @@ -19,7 +19,7 @@ public AuthInterceptor(String applicationId, String apiKey) { this.apiKey = apiKey; } - @NotNull + @Nonnull @Override public Response intercept(Chain chain) throws IOException { okhttp3.Request originalRequest = chain.request(); diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/GzipRequestInterceptor.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/GzipRequestInterceptor.java index 36c5b57bc0..71da413a5e 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/GzipRequestInterceptor.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/GzipRequestInterceptor.java @@ -1,16 +1,16 @@ package com.algolia.internal.interceptors; import java.io.IOException; +import javax.annotation.Nonnull; import okhttp3.*; import okio.BufferedSink; import okio.GzipSink; import okio.Okio; -import org.jetbrains.annotations.NotNull; /** This interceptor compresses the HTTP request body. */ public final class GzipRequestInterceptor implements Interceptor { - @NotNull + @Nonnull @Override public Response intercept(Interceptor.Chain chain) throws IOException { Request originalRequest = chain.request(); @@ -39,7 +39,7 @@ public long contentLength() { } @Override - public void writeTo(@NotNull BufferedSink sink) throws IOException { + public void writeTo(@Nonnull BufferedSink sink) throws IOException { BufferedSink gzipSink = Okio.buffer(new GzipSink(sink)); body.writeTo(gzipSink); gzipSink.close(); diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/HeaderInterceptor.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/HeaderInterceptor.java index 3de8532e0a..a8b1fdb9a1 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/HeaderInterceptor.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/HeaderInterceptor.java @@ -3,10 +3,10 @@ import java.io.IOException; import java.util.Collections; import java.util.Map; +import javax.annotation.Nonnull; import okhttp3.Headers; import okhttp3.Interceptor; import okhttp3.Response; -import org.jetbrains.annotations.NotNull; public final class HeaderInterceptor implements Interceptor { @@ -16,7 +16,7 @@ public HeaderInterceptor(Map headers) { this.headers = Collections.unmodifiableMap(headers); } - @NotNull + @Nonnull @Override public Response intercept(Chain chain) throws IOException { okhttp3.Request request = chain.request(); diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/LogInterceptor.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/LogInterceptor.java index 60e5c30420..48f136e1c2 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/LogInterceptor.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/LogInterceptor.java @@ -3,10 +3,10 @@ import com.algolia.config.LogLevel; import com.algolia.config.Logger; import java.io.IOException; +import javax.annotation.Nonnull; import okhttp3.Interceptor; import okhttp3.Response; import okhttp3.logging.HttpLoggingInterceptor; -import org.jetbrains.annotations.NotNull; /** * An interceptor that facilitates HTTP logging based on the provided logging level. This class @@ -28,11 +28,11 @@ public LogInterceptor(Logger logger, LogLevel logLevel) { this.logger = new HttpLoggingInterceptor(logr).setLevel(level); } - public HttpLoggingInterceptor.Logger toLogger(@NotNull Logger logger) { + public HttpLoggingInterceptor.Logger toLogger(@Nonnull Logger logger) { return logger::log; } - public HttpLoggingInterceptor.Level toLevel(@NotNull LogLevel logLevel) { + public HttpLoggingInterceptor.Level toLevel(@Nonnull LogLevel logLevel) { switch (logLevel) { case NONE: return HttpLoggingInterceptor.Level.NONE; @@ -47,9 +47,9 @@ public HttpLoggingInterceptor.Level toLevel(@NotNull LogLevel logLevel) { } } - @NotNull + @Nonnull @Override - public Response intercept(@NotNull Chain chain) throws IOException { + public Response intercept(@Nonnull Chain chain) throws IOException { return logger.intercept(chain); } } diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/RetryStrategy.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/RetryStrategy.java index 2695823381..14881fc1ec 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/RetryStrategy.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/RetryStrategy.java @@ -17,11 +17,11 @@ import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import javax.annotation.Nonnull; import okhttp3.HttpUrl; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; -import org.jetbrains.annotations.NotNull; /** * A retry strategy that implements {@link Interceptor}, responsible for routing requests to hosts @@ -42,9 +42,9 @@ public RetryStrategy(List hosts) { this.hosts = Collections.unmodifiableList(hosts); } - @NotNull + @Nonnull @Override - public Response intercept(@NotNull Chain chain) { + public Response intercept(@Nonnull Chain chain) { Request request = chain.request(); UseReadTransporter useReadTransporter = (UseReadTransporter) request.tag(); CallType callType = (useReadTransporter != null || request.method().equals("GET")) ? CallType.READ : CallType.WRITE; @@ -61,8 +61,8 @@ public Response intercept(@NotNull Chain chain) { } /** Processes the request for a given host. */ - @NotNull - private Response processRequest(@NotNull Chain chain, @NotNull Request request, StatefulHost host) throws IOException { + @Nonnull + private Response processRequest(@Nonnull Chain chain, @Nonnull Request request, StatefulHost host) throws IOException { HttpUrl newUrl = request.url().newBuilder().scheme(host.getScheme()).host(host.getHost()).build(); Request newRequest = request.newBuilder().url(newUrl).build(); chain.withConnectTimeout(chain.connectTimeoutMillis() * (host.getRetryCount() + 1), TimeUnit.MILLISECONDS); @@ -71,8 +71,8 @@ private Response processRequest(@NotNull Chain chain, @NotNull Request request, } /** Handles the response from the host. */ - @NotNull - private Response handleResponse(StatefulHost host, @NotNull Response response) throws IOException { + @Nonnull + private Response handleResponse(StatefulHost host, @Nonnull Response response) throws IOException { if (response.isSuccessful()) { host.reset(); return response; @@ -89,7 +89,7 @@ private Response handleResponse(StatefulHost host, @NotNull Response response) t } /** Determines if a response should be retried. */ - private boolean isRetryable(@NotNull Response response) { + private boolean isRetryable(@Nonnull Response response) { int statusCode = response.code(); return (statusCode < 200 || statusCode >= 300) && (statusCode < 400 || statusCode >= 500); } diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/UserAgentInterceptor.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/UserAgentInterceptor.java index 7a9f5c0713..c371a2b06c 100644 --- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/UserAgentInterceptor.java +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/internal/interceptors/UserAgentInterceptor.java @@ -2,9 +2,9 @@ import com.algolia.config.AlgoliaAgent; import java.io.IOException; +import javax.annotation.Nonnull; import okhttp3.Interceptor; import okhttp3.Response; -import org.jetbrains.annotations.NotNull; public final class UserAgentInterceptor implements Interceptor { @@ -14,7 +14,7 @@ public UserAgentInterceptor(AlgoliaAgent agent) { this.agent = agent; } - @NotNull + @Nonnull @Override public Response intercept(Chain chain) throws IOException { okhttp3.Request originalRequest = chain.request(); diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/utils/Parameters.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/utils/Parameters.java new file mode 100644 index 0000000000..09598cd1a3 --- /dev/null +++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/utils/Parameters.java @@ -0,0 +1,16 @@ +package com.algolia.utils; + +import com.algolia.exceptions.AlgoliaRuntimeException; + +public class Parameters { + + private Parameters() { + // Empty. + } + + public static void requireNonNull(Object param, String error) { + if (param == null) { + throw new AlgoliaRuntimeException(error); + } + } +} diff --git a/generators/build.gradle b/generators/build.gradle index 61c7c098cf..456203b6ec 100644 --- a/generators/build.gradle +++ b/generators/build.gradle @@ -6,11 +6,6 @@ group = 'org.openapitools' version = '1.0.0' description = 'algolia-java-openapi-generator' -java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 -} - repositories { mavenCentral() } diff --git a/generators/src/main/java/com/algolia/codegen/AlgoliaJavaGenerator.java b/generators/src/main/java/com/algolia/codegen/AlgoliaJavaGenerator.java index 0a13696a20..61c89ee551 100644 --- a/generators/src/main/java/com/algolia/codegen/AlgoliaJavaGenerator.java +++ b/generators/src/main/java/com/algolia/codegen/AlgoliaJavaGenerator.java @@ -1,11 +1,11 @@ package com.algolia.codegen; import com.algolia.codegen.exceptions.*; +import com.algolia.codegen.utils.OneOfUtils; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.servers.Server; import java.util.*; -import java.util.stream.Collectors; import org.openapitools.codegen.*; import org.openapitools.codegen.languages.JavaClientCodegen; import org.openapitools.codegen.model.ModelMap; @@ -72,44 +72,8 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation @Override public Map postProcessAllModels(Map objs) { Map models = super.postProcessAllModels(objs); - - for (ModelsMap modelContainer : models.values()) { - // modelContainers always have 1 and only 1 model in our specs - CodegenModel model = modelContainer.getModels().get(0).getModel(); - - if (!model.oneOf.isEmpty()) { - List> oneOfList = new ArrayList(); - - for (String oneOf : model.oneOf) { - HashMap oneOfModel = new HashMap(); - oneOfModel.put("type", oneOf); - oneOfModel.put("name", oneOf.replace("<", "Of").replace(">", "")); - oneOfModel.put("isList", oneOf.contains("List")); - ModelsMap modelsMap = models.get(oneOf); - if (modelsMap != null) { - oneOfModel.put("isObject", true); - CodegenModel compoundModel = modelsMap.getModels().get(0).getModel(); - List values = (List) compoundModel.vendorExtensions.get("x-discriminator-fields"); - if (values != null) { - List> newValues = values - .stream() - .map(value -> Collections.singletonMap("field", value)) - .collect(Collectors.toList()); - oneOfModel.put("discriminators", newValues); - } - } - oneOfList.add(oneOfModel); - } - - model.vendorExtensions.put("x-is-one-of-interface", true); - model.vendorExtensions.put("x-one-of-list", oneOfList); - - model.vendorExtensions.put("x-one-of-explicit-name", Utils.shouldUseExplicitOneOfName(model.oneOf)); - } - } - + OneOfUtils.updateModelsOneOf(models, modelPackage); GenericPropagator.propagateGenericsToModels(models); - return models; } diff --git a/generators/src/main/java/com/algolia/codegen/AlgoliaKotlinGenerator.java b/generators/src/main/java/com/algolia/codegen/AlgoliaKotlinGenerator.java index 9039b78b33..d533c9e2f1 100644 --- a/generators/src/main/java/com/algolia/codegen/AlgoliaKotlinGenerator.java +++ b/generators/src/main/java/com/algolia/codegen/AlgoliaKotlinGenerator.java @@ -1,13 +1,13 @@ package com.algolia.codegen; import com.algolia.codegen.exceptions.GeneratorException; +import com.algolia.codegen.utils.OneOfUtils; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.servers.Server; import java.io.File; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.openapitools.codegen.*; import org.openapitools.codegen.languages.KotlinClientCodegen; @@ -163,7 +163,7 @@ private List extractSegments(String input) { @Override public Map postProcessAllModels(Map objs) { Map models = super.postProcessAllModels(objs); - modelsOneOf(models); + OneOfUtils.updateModelsOneOf(models, modelPackage); GenericPropagator.propagateGenericsToModels(models); jsonParent(models); typealias(models); @@ -191,92 +191,6 @@ private static void jsonParent(Map models) { } } - private void modelsOneOf(Map models) { - for (ModelsMap modelContainer : models.values()) { - // modelContainers always have 1 and only 1 model in our specs - CodegenModel model = modelContainer.getModels().get(0).getModel(); - if (model.oneOf.isEmpty()) continue; - - List> oneOfList = new ArrayList<>(); - for (String oneOf : model.oneOf) { - Map oneOfModel = new HashMap<>(); - oneOfModel.put("type", oneOf); - oneOfModel.put("name", oneOf.replace("<", "Of").replace(">", "")); - oneOfModel.put("listElementType", oneOf.replace("List<", "").replace(">", "")); - oneOfModel.put("isList", oneOf.contains("List")); - - // Mark compounds - // 1. Find child model - ModelsMap modelsMap = models.get(oneOf); - if (modelsMap != null) { - oneOfModel.put("isObject", true); - // 2. add the child to parent model - CodegenModel compoundModel = modelsMap.getModels().get(0).getModel(); - oneOfModel.put("child", compoundModel.classname); - - // 3. mark the child and add its parent (may have many) - compoundModel.vendorExtensions.put("x-one-of-element", true); - HashMap parentInfo = new HashMap<>(); - parentInfo.put("parent_classname", model.classname); - compoundParent(compoundModel).add(parentInfo); - List values = (List) compoundModel.vendorExtensions.get("x-discriminator-fields"); - if (values != null) { - List> newValues = values - .stream() - .map(value -> Collections.singletonMap("field", value)) - .collect(Collectors.toList()); - oneOfModel.put("discriminators", newValues); - } - } - oneOfList.add(oneOfModel); - } - - List sealedChilds = new ArrayList<>(); - for (String oneOf : model.oneOf) { - ModelsMap modelsMap = models.get(oneOf); - if (modelsMap != null) { - CodegenModel compoundModel = modelsMap.getModels().get(0).getModel(); - compoundModel.vendorExtensions.put("x-one-of-explicit-name", compoundModel.classname); - compoundModel.vendorExtensions.put("x-fully-qualified-classname", modelPackage + "." + compoundModel.classname); - compoundModel.vendorExtensions.put("x-classname-or-alias", compoundModel.classname + "Impl"); - sealedChilds.add(compoundModel); - } else { - CodegenModel newModel = new CodegenModel(); - String name = oneOf.replace("<", "Of").replace(">", ""); - newModel.setClassname(name + "Wrapper"); - newModel.setDescription(model.classname + " as " + oneOf); - CodegenProperty property = new CodegenProperty(); - property.setName("value"); - property.setRequired(true); - property.setDatatypeWithEnum(oneOf); - newModel.setVars(Collections.singletonList(property)); - newModel.vendorExtensions.put("x-is-number", newModel.isNumber); - newModel.vendorExtensions.put("x-one-of-explicit-name", isNumberType(oneOf) ? "Number" : name); - newModel.vendorExtensions.put("x-fully-qualified-classname", newModel.classname); - sealedChilds.add(newModel); - } - } - - model.vendorExtensions.put("x-sealed-childs", sealedChilds); - - model.vendorExtensions.put("x-is-one-of-interface", true); - model.vendorExtensions.put("x-one-of-list", oneOfList); - model.vendorExtensions.put("x-one-of-explicit-name", Utils.shouldUseExplicitOneOfName(model.oneOf)); - } - } - - private boolean isNumberType(String typeName) { - return typeName.equals("Int") || typeName.equals("Double") || typeName.equals("Long"); - } - - private Set> compoundParent(CodegenModel model) { - Set> parents = (Set>) model.vendorExtensions.get("x-one-of-element-parents"); - if (parents != null) return parents; - parents = new HashSet<>(); - model.vendorExtensions.put("x-one-of-element-parents", parents); - return parents; - } - @Override public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List models) { OperationsMap operations = super.postProcessOperationsWithModels(objs, models); diff --git a/generators/src/main/java/com/algolia/codegen/GenericPropagator.java b/generators/src/main/java/com/algolia/codegen/GenericPropagator.java index a19a8b76ba..b700522a9f 100644 --- a/generators/src/main/java/com/algolia/codegen/GenericPropagator.java +++ b/generators/src/main/java/com/algolia/codegen/GenericPropagator.java @@ -1,9 +1,10 @@ package com.algolia.codegen; -import com.algolia.codegen.exceptions.*; import java.util.*; import org.openapitools.codegen.*; -import org.openapitools.codegen.model.*; +import org.openapitools.codegen.model.ModelMap; +import org.openapitools.codegen.model.ModelsMap; +import org.openapitools.codegen.model.OperationsMap; public class GenericPropagator { @@ -13,10 +14,10 @@ public class GenericPropagator { private GenericPropagator() {} private static void setVendorExtension(IJsonSchemaValidationProperties property, String key, Object value) { - if (property instanceof CodegenModel) { - ((CodegenModel) property).vendorExtensions.put(key, value); - } else if (property instanceof CodegenProperty) { - ((CodegenProperty) property).vendorExtensions.put(key, value); + if (property instanceof CodegenModel model) { + model.vendorExtensions.put(key, value); + } else if (property instanceof CodegenProperty prop) { + prop.vendorExtensions.put(key, value); } } @@ -66,15 +67,19 @@ private static CodegenModel propertyToModel(Map models, Co private static boolean markPropagatedGeneric(IJsonSchemaValidationProperties model) { CodegenProperty items = model.getItems(); + // Skip one-of types + if (model instanceof CodegenModel codegenModel && !codegenModel.oneOf.isEmpty()) { + return false; + } // if items itself isn't generic, we recurse on its items and properties until we reach the // end or find a generic property if (items != null && ((boolean) items.vendorExtensions.getOrDefault("x-is-generic", false) || markPropagatedGeneric(items))) { setPropagatedGeneric(model); return true; } - for (CodegenProperty var : model.getVars()) { - // same thing for the var, if it's not a generic, we recurse on it until we find one - if ((boolean) var.vendorExtensions.getOrDefault("x-is-generic", false) || markPropagatedGeneric(var)) { + for (CodegenProperty variable : model.getVars()) { + // same thing for the variable, if it's not a generic, we recurse on it until we find one + if ((boolean) variable.vendorExtensions.getOrDefault("x-is-generic", false) || markPropagatedGeneric(variable)) { setPropagatedGeneric(model); return true; } @@ -92,9 +97,9 @@ private static boolean propagateGenericRecursive(Map model setHasChildGeneric(property); return true; } - for (CodegenProperty var : property.getVars()) { - // same thing for the var - if (hasGeneric(var) || propagateGenericRecursive(models, var) || hasGeneric(propertyToModel(models, var))) { + for (CodegenProperty variable : property.getVars()) { + // same thing for the variable + if (hasGeneric(variable) || propagateGenericRecursive(models, variable) || hasGeneric(propertyToModel(models, variable))) { setHasChildGeneric(property); return true; } @@ -177,7 +182,7 @@ public static void propagateGenericsToOperations(OperationsMap operations, List< ope.vendorExtensions.put("x-is-generic", true); // we use {{#optionalParams.0}} to check for optionalParams, so we loose the // vendorExtensions at the operation level - if (ope.optionalParams.size() > 0) { + if (!ope.optionalParams.isEmpty()) { ope.optionalParams.get(0).vendorExtensions.put("x-is-generic", true); } } diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/ParametersWithDataType.java b/generators/src/main/java/com/algolia/codegen/cts/tests/ParametersWithDataType.java index eaa6c700d4..7bad87546a 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/tests/ParametersWithDataType.java +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/ParametersWithDataType.java @@ -284,13 +284,15 @@ private void handleModel( IJsonSchemaValidationProperties current = match; String typeName = getTypeName(current); StringBuilder capitalizedTypeName = new StringBuilder(typeName); + boolean isList = false; while (current.getItems() != null) { current = current.getItems(); typeName += "Of" + getTypeName(current); capitalizedTypeName.append("Of").append(StringUtils.capitalize(getTypeName(current))); + isList = true; } - boolean useExplicitName = false; + boolean useExplicitName; CodegenComposedSchemas composedSchemas = model.getComposedSchemas(); if (composedSchemas != null && composedSchemas.getOneOf() != null && composedSchemas.getOneOf().size() > 0) { useExplicitName = @@ -303,6 +305,7 @@ private void handleModel( oneOfModel.put("type", typeName); oneOfModel.put("type-capitalized", capitalizedTypeName.toString()); oneOfModel.put("x-one-of-explicit-name", useExplicitName); + oneOfModel.put("hasWrapper", isList || isString(current) || isNumber(current) || isBoolean(current)); testOutput.put("oneOfModel", oneOfModel); return; } @@ -412,53 +415,83 @@ private void handlePrimitive(Object param, Map testOutput, IJson } private String getTypeName(IJsonSchemaValidationProperties param) { - if (param instanceof CodegenParameter) { - return ((CodegenParameter) param).dataType; + if (param instanceof CodegenParameter parameter) { + return parameter.dataType; } - if (param instanceof CodegenProperty) { - return ((CodegenProperty) param).dataType; + if (param instanceof CodegenProperty parameter) { + return parameter.dataType; } - if (param instanceof CodegenModel) { - return ((CodegenModel) param).classname; + if (param instanceof CodegenModel parameter) { + return parameter.classname; } - if (param instanceof CodegenResponse) { - return ((CodegenResponse) param).dataType; + if (param instanceof CodegenResponse parameter) { + return parameter.dataType; } return null; } private boolean isAnyType(IJsonSchemaValidationProperties param) { - if (param instanceof CodegenParameter) { - return ((CodegenParameter) param).isAnyType; + if (param instanceof CodegenParameter parameter) { + return parameter.isAnyType; } - if (param instanceof CodegenProperty) { - return ((CodegenProperty) param).isAnyType; + if (param instanceof CodegenProperty parameter) { + return parameter.isAnyType; } - if (param instanceof CodegenResponse) { - return ((CodegenResponse) param).isAnyType; + if (param instanceof CodegenResponse parameter) { + return parameter.isAnyType; } return false; } private boolean isEnum(IJsonSchemaValidationProperties param) { - if (param instanceof CodegenParameter) { - return ((CodegenParameter) param).isEnum; + if (param instanceof CodegenParameter parameter) { + return parameter.isEnum; } - if (param instanceof CodegenProperty) { - return ((CodegenProperty) param).isEnum; + if (param instanceof CodegenProperty parameter) { + return parameter.isEnum; } - if (param instanceof CodegenModel) { - return ((CodegenModel) param).isEnum; + if (param instanceof CodegenModel parameter) { + return parameter.isEnum; } return false; } private boolean isPrimitiveType(IJsonSchemaValidationProperties param) { - if (param instanceof CodegenParameter) { - return ((CodegenParameter) param).isPrimitiveType; + if (param instanceof CodegenParameter parameter) { + return parameter.isPrimitiveType; } - if (param instanceof CodegenProperty) { - return ((CodegenProperty) param).isPrimitiveType; + if (param instanceof CodegenProperty parameter) { + return parameter.isPrimitiveType; + } + return false; + } + + private boolean isNumber(IJsonSchemaValidationProperties param) { + if (param instanceof CodegenParameter parameter) { + return parameter.isNumber; + } + if (param instanceof CodegenProperty parameter) { + return parameter.isNumber; + } + return false; + } + + private boolean isString(IJsonSchemaValidationProperties param) { + if (param instanceof CodegenParameter parameter) { + return parameter.isString; + } + if (param instanceof CodegenProperty parameter) { + return parameter.isString; + } + return false; + } + + private boolean isBoolean(IJsonSchemaValidationProperties param) { + if (param instanceof CodegenParameter parameter) { + return parameter.isBoolean; + } + if (param instanceof CodegenProperty parameter) { + return parameter.isBoolean; } return false; } diff --git a/generators/src/main/java/com/algolia/codegen/utils/OneOfUtils.java b/generators/src/main/java/com/algolia/codegen/utils/OneOfUtils.java new file mode 100644 index 0000000000..29beae477b --- /dev/null +++ b/generators/src/main/java/com/algolia/codegen/utils/OneOfUtils.java @@ -0,0 +1,119 @@ +package com.algolia.codegen.utils; + +import com.algolia.codegen.Utils; +import java.util.*; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenProperty; +import org.openapitools.codegen.model.ModelsMap; + +public class OneOfUtils { + + private OneOfUtils() { + // Empty. + } + + public static void updateModelsOneOf(Map models, String modelPackage) { + for (ModelsMap modelContainer : models.values()) { + // modelContainers always have 1 and only 1 model in our specs + var model = modelContainer.getModels().get(0).getModel(); + if (model.oneOf.isEmpty()) continue; + markOneOfChildren(models, model); + generateSealedChildren(models, modelPackage, model); + model.vendorExtensions.put("x-is-one-of", true); + model.vendorExtensions.put("x-one-of-explicit-name", Utils.shouldUseExplicitOneOfName(model.oneOf)); + } + } + + private static void generateSealedChildren(Map models, String modelPackage, CodegenModel model) { + var sealedChilds = new ArrayList<>(); + for (String oneOf : model.oneOf) { + ModelsMap modelsMap = models.get(oneOf); + if (modelsMap != null) { + CodegenModel compoundModel = modelsMap.getModels().get(0).getModel(); + compoundModel.vendorExtensions.put("x-one-of-explicit-name", compoundModel.classname); + compoundModel.vendorExtensions.put("x-fully-qualified-classname", modelPackage + "." + compoundModel.classname); + compoundModel.vendorExtensions.put("x-classname-or-alias", compoundModel.classname + "Impl"); + sealedChilds.add(compoundModel); + } else { + CodegenModel newModel = new CodegenModel(); + String name = oneOf.replace("<", "Of").replace(">", ""); + newModel.setClassname(name + "Wrapper"); + newModel.setDescription(model.classname + " as " + oneOf); + CodegenProperty property = new CodegenProperty(); + property.setName("value"); + property.setRequired(true); + property.setDatatypeWithEnum(oneOf); + newModel.setVars(Collections.singletonList(property)); + newModel.vendorExtensions.put("x-is-number", newModel.isNumber); + newModel.vendorExtensions.put("x-one-of-explicit-name", isNumberType(oneOf) ? "Number" : name); + newModel.vendorExtensions.put("x-fully-qualified-classname", newModel.classname); + sealedChilds.add(newModel); + } + } + model.vendorExtensions.put("x-sealed-childs", sealedChilds); + } + + private static void markOneOfChildren(Map models, CodegenModel model) { + var oneOfList = new ArrayList>(); + for (String oneOf : model.oneOf) { + var oneOfModel = new HashMap(); + oneOfModel.put("type", oneOf); + oneOfModel.put("name", oneOf.replace("<", "Of").replace(">", "")); + oneOfModel.put("listElementType", oneOf.replace("List<", "").replace(">", "")); + oneOfModel.put("isList", oneOf.contains("List")); + markCompounds(models, oneOf, oneOfModel, model); + oneOfList.add(oneOfModel); + } + oneOfList.sort(comparator); // have fields with "discriminators" in the start of the list + model.vendorExtensions.put("x-one-of-list", oneOfList); + } + + private static void markCompounds(Map models, String oneOf, Map oneOfModel, CodegenModel model) { + // 1. Find child model + var modelsMap = models.get(oneOf); + if (modelsMap == null) return; + oneOfModel.put("isObject", true); + + // 2. add the child to parent model + var compoundModel = modelsMap.getModels().get(0).getModel(); + oneOfModel.put("child", compoundModel.classname); + + // 3. mark the child and add its parent (may have many) + compoundModel.vendorExtensions.put("x-one-of-element", true); + var parentInfo = new HashMap(); + parentInfo.put("parent_classname", model.classname); + compoundParent(compoundModel).add(parentInfo); + //noinspection unchecked + var values = (List) compoundModel.vendorExtensions.get("x-discriminator-fields"); + if (values != null) { + List> newValues = values.stream().map(value -> Collections.singletonMap("field", value)).toList(); + oneOfModel.put("discriminators", newValues); + } + } + + private static Set> compoundParent(CodegenModel model) { + //noinspection unchecked + var parents = (Set>) model.vendorExtensions.get("x-one-of-element-parents"); + if (parents != null) return parents; + parents = new HashSet<>(); + model.vendorExtensions.put("x-one-of-element-parents", parents); + return parents; + } + + private static boolean isNumberType(String typeName) { + return typeName.equals("Int") || typeName.equals("Double") || typeName.equals("Long"); + } + + private static final Comparator> comparator = (mapA, mapB) -> { + boolean hasDiscriminatorA = mapA.containsKey("discriminators"); + boolean hasDiscriminatorB = mapB.containsKey("discriminators"); + // Maps with "discriminators" come first + if (hasDiscriminatorA && !hasDiscriminatorB) { + return -1; + } else if (!hasDiscriminatorA && hasDiscriminatorB) { + return 1; + } else { + return 0; + } + }; +} diff --git a/playground/java/src/main/java/com/algolia/playground/Insights.java b/playground/java/src/main/java/com/algolia/playground/Insights.java index e80eecc086..f2185d5eab 100644 --- a/playground/java/src/main/java/com/algolia/playground/Insights.java +++ b/playground/java/src/main/java/com/algolia/playground/Insights.java @@ -26,12 +26,12 @@ public static void main(String[] args) throws Exception { var client = new InsightsClient(appId, apiKey, options); var params = new InsightsEvents(); - var event = EventsItems.of(new ClickedObjectIDs() + var event = new ClickedObjectIDs() .setEventType(ClickEvent.CLICK) .setUserToken("user") .setIndex(indexName) .setObjectIDs(List.of("id123")) - .setEventName("click")); + .setEventName("click"); params.addEvents(event); var result = client.pushEvents(params); System.out.println(result); diff --git a/playground/java/src/main/java/com/algolia/playground/Search.java b/playground/java/src/main/java/com/algolia/playground/Search.java index 5370949260..401143b9ee 100644 --- a/playground/java/src/main/java/com/algolia/playground/Search.java +++ b/playground/java/src/main/java/com/algolia/playground/Search.java @@ -33,6 +33,7 @@ public static void main(String[] args) throws Exception { var options = new ClientOptions.Builder() .addAlgoliaAgentSegment("Playground", "1.0.0") + .setLogLevel(LogLevel.BODY) .build(); var client = new SearchClient(appId, apiKey, options); @@ -49,7 +50,11 @@ public static void main(String[] args) throws Exception { } private static void singleSearch(SearchClient client, String indexName, String query) { - SearchResponse actorSearchResponse = client.searchSingleIndex(indexName, SearchParams.of(new SearchParamsObject().setQuery(query)), Actor.class); + SearchParamsObject params = new SearchParamsObject() + .setQuery(query) + .setAroundPrecision(AroundPrecision.of(1000)) + .setAroundRadius(AroundRadiusAll.ALL); + SearchResponse actorSearchResponse = client.searchSingleIndex(indexName, params, Actor.class); System.out.println("-> Single Index Search:"); for (var hit : actorSearchResponse.getHits()) { System.out.println("> " + hit.name); @@ -63,14 +68,14 @@ private static void multiSearch(String indexName, String query, SearchClient cli .setQuery(query) .addAttributesToSnippet("title") .addAttributesToSnippet("alternative_titles"); - List requests = List.of(SearchQuery.of(searchQuery)); + List requests = List.of(searchQuery); searchMethodParams.setRequests(requests); var responses = client.search(searchMethodParams); var results = responses.getResults(); System.out.println("-> Multi Index Search:"); for (var result : results) { - var response = (SearchResponse) result.get(); + var response = (SearchResponse) result; for (var hit : response.getHits()) { var record = (Map) hit; System.out.println("> " + record.get("name")); diff --git a/specs/common/schemas/SearchParams.yml b/specs/common/schemas/SearchParams.yml index 0cab31ecd8..768d880cd2 100644 --- a/specs/common/schemas/SearchParams.yml +++ b/specs/common/schemas/SearchParams.yml @@ -197,6 +197,8 @@ baseSearchParamsWithoutQuery: searchParamsString: type: object additionalProperties: false + x-discriminator-fields: + - params properties: params: $ref: '#/paramsAsString' diff --git a/templates/java/api.mustache b/templates/java/api.mustache index db91328ae7..797f0b129c 100644 --- a/templates/java/api.mustache +++ b/templates/java/api.mustache @@ -28,6 +28,8 @@ import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.concurrent.CompletableFuture; +import javax.annotation.Nonnull; + {{#operations}} public class {{classname}} extends ApiClient { {{#hasRegionalHost}} @@ -106,34 +108,34 @@ public class {{classname}} extends ApiClient { {{#operation}} /** * {{{notes}}}{{#allParams}} - * @param {{paramName}} {{{description}}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}}{{#vendorExtensions.x-is-generic}} - * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/vendorExtensions.x-is-generic}} + * @param {{paramName}} {{{description}}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}} + {{#vendorExtensions}}{{#x-is-generic}}* @param innerType The class held by the index, could be your custom class or {@link Object}.{{/x-is-generic}}{{/vendorExtensions}} * @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions. {{> api_javadoc}} - public {{> return_type}} {{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}{{#vendorExtensions.x-is-generic}}Class innerType, {{/vendorExtensions.x-is-generic}}RequestOptions requestOptions) throws AlgoliaRuntimeException { - return LaunderThrowable.await({{operationId}}Async({{#allParams}}{{paramName}}, {{/allParams}}{{#vendorExtensions.x-is-generic}}innerType, {{/vendorExtensions.x-is-generic}}requestOptions)); + public {{> return_type}} {{operationId}}({{#requiredParams}}@Nonnull {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#hasRequiredParams}}{{#hasOptionalParams}},{{/hasOptionalParams}}{{/hasRequiredParams}}{{#optionalParams}} {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/optionalParams}}{{#vendorExtensions}}{{#x-is-generic}}, Class innerType{{/x-is-generic}}{{/vendorExtensions}}{{#hasParams}}, {{/hasParams}}RequestOptions requestOptions) throws AlgoliaRuntimeException { + return LaunderThrowable.await({{operationId}}Async({{#allParams}}{{paramName}}, {{/allParams}}{{#vendorExtensions}}{{#x-is-generic}}innerType, {{/x-is-generic}}{{/vendorExtensions}}requestOptions)); } {{! This case only sets `requestOptions` as optional }} /** * {{{notes}}}{{#allParams}} - * @param {{paramName}} {{{description}}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}}{{#vendorExtensions.x-is-generic}} - * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/vendorExtensions.x-is-generic}} + * @param {{paramName}} {{{description}}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}} + {{#vendorExtensions}}{{#x-is-generic}}* @param innerType The class held by the index, could be your custom class or {@link Object}.{{/x-is-generic}}{{/vendorExtensions}} {{> api_javadoc}} - public {{> return_type}} {{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#vendorExtensions.x-is-generic}}, Class innerType{{/vendorExtensions.x-is-generic}}) throws AlgoliaRuntimeException { - {{#returnType}}return {{/returnType}}this.{{operationId}}({{#allParams}}{{paramName}}, {{/allParams}}{{#vendorExtensions.x-is-generic}}innerType, {{/vendorExtensions.x-is-generic}}null); + public {{> return_type}} {{operationId}}({{#requiredParams}}@Nonnull {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#hasRequiredParams}}{{#hasOptionalParams}},{{/hasOptionalParams}}{{/hasRequiredParams}}{{#optionalParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/optionalParams}}{{#vendorExtensions}}{{#x-is-generic}}, Class innerType{{/x-is-generic}}{{/vendorExtensions}}) throws AlgoliaRuntimeException { + {{#returnType}}return {{/returnType}}this.{{operationId}}({{#allParams}}{{paramName}}, {{/allParams}}{{#vendorExtensions}}{{#x-is-generic}}innerType, {{/x-is-generic}}{{/vendorExtensions}}null); } {{! This case sets `requiredParams` + `requestOptions` }} {{#optionalParams.0}} /** * {{{notes}}}{{#requiredParams}} - * @param {{paramName}} {{{description}}} (required){{/requiredParams}}{{#vendorExtensions.x-is-generic}} - * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/vendorExtensions.x-is-generic}} + * @param {{paramName}} {{{description}}} (required){{/requiredParams}} + {{#vendorExtensions}}{{#x-is-generic}}* @param innerType The class held by the index, could be your custom class or {@link Object}.{{/x-is-generic}}{{/vendorExtensions}} * @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions. {{> api_javadoc}} - public {{> return_type}} {{operationId}}({{#requiredParams}}{{{dataType}}} {{paramName}}, {{/requiredParams}}{{#vendorExtensions.x-is-generic}}Class innerType, {{/vendorExtensions.x-is-generic}}RequestOptions requestOptions) throws AlgoliaRuntimeException { - {{#returnType}}return {{/returnType}}this.{{operationId}}({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#requiredParams.0}},{{/requiredParams.0}}{{#optionalParams}}null{{^-last}},{{/-last}}{{/optionalParams}}, {{#vendorExtensions.x-is-generic}}innerType, {{/vendorExtensions.x-is-generic}}requestOptions); + public {{> return_type}} {{operationId}}({{#requiredParams}}@Nonnull {{{dataType}}} {{paramName}}, {{/requiredParams}}{{#vendorExtensions}}{{#x-is-generic}}Class innerType, {{/x-is-generic}}{{/vendorExtensions}}RequestOptions requestOptions) throws AlgoliaRuntimeException { + {{#returnType}}return {{/returnType}}this.{{operationId}}({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#requiredParams.0}},{{/requiredParams.0}}{{#optionalParams}}null{{^-last}},{{/-last}}{{/optionalParams}}, {{#vendorExtensions}}{{#x-is-generic}}innerType, {{/x-is-generic}}{{/vendorExtensions}}requestOptions); } {{/optionalParams.0}} @@ -141,26 +143,24 @@ public class {{classname}} extends ApiClient { {{#optionalParams.0}} /** * {{{notes}}}{{#requiredParams}} - * @param {{paramName}} {{{description}}} (required){{/requiredParams}}{{#vendorExtensions.x-is-generic}} - * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/vendorExtensions.x-is-generic}} + * @param {{paramName}} {{{description}}} (required){{/requiredParams}} + {{#vendorExtensions}}{{#x-is-generic}}* @param innerType The class held by the index, could be your custom class or {@link Object}.{{/x-is-generic}}{{/vendorExtensions}} {{> api_javadoc}} - public {{> return_type}} {{operationId}}({{#requiredParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#vendorExtensions.x-is-generic}}, Class innerType{{/vendorExtensions.x-is-generic}}) throws AlgoliaRuntimeException { - {{#returnType}}return {{/returnType}}this.{{operationId}}({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#requiredParams.0}},{{/requiredParams.0}}{{#optionalParams}}null{{^-last}},{{/-last}}{{/optionalParams}}, {{#vendorExtensions.x-is-generic}}innerType, {{/vendorExtensions.x-is-generic}}null); + public {{> return_type}} {{operationId}}({{#requiredParams}}@Nonnull {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#vendorExtensions}}{{#x-is-generic}}, Class innerType{{/x-is-generic}}{{/vendorExtensions}}) throws AlgoliaRuntimeException { + {{#returnType}}return {{/returnType}}this.{{operationId}}({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#requiredParams.0}},{{/requiredParams.0}}{{#optionalParams}}null{{^-last}},{{/-last}}{{/optionalParams}}, {{#vendorExtensions}}{{#x-is-generic}}innerType, {{/x-is-generic}}{{/vendorExtensions}}null); } {{/optionalParams.0}} /** * (asynchronously) * {{notes}}{{#allParams}} - * @param {{paramName}} {{{description}}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}}{{#vendorExtensions.x-is-generic}} - * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/vendorExtensions.x-is-generic}} + * @param {{paramName}} {{{description}}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}}{{#vendorExtensions}}{{#x-is-generic}} + * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/x-is-generic}}{{/vendorExtensions}} * @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions. {{> api_javadoc}} - public {{> return_type_async}} {{operationId}}Async({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}{{#vendorExtensions.x-is-generic}}Class innerType, {{/vendorExtensions.x-is-generic}}RequestOptions requestOptions) throws AlgoliaRuntimeException { + public {{> return_type_async}} {{operationId}}Async({{#requiredParams}}@Nonnull {{{dataType}}} {{paramName}},{{/requiredParams}}{{#optionalParams}}{{{dataType}}} {{paramName}}, {{/optionalParams}}{{#vendorExtensions}}{{#x-is-generic}}Class innerType, {{/x-is-generic}}{{/vendorExtensions}}RequestOptions requestOptions) throws AlgoliaRuntimeException { {{#allParams}}{{#required}} - if ({{paramName}} == null) { - throw new AlgoliaRuntimeException("Parameter `{{paramName}}` is required when calling `{{operationId}}`."); - } + Parameters.requireNonNull({{paramName}}, "Parameter `{{paramName}}` is required when calling `{{operationId}}`."); {{/required}}{{/allParams}} HttpRequest request = HttpRequest.builder() @@ -171,18 +171,18 @@ public class {{classname}} extends ApiClient { {{#headerParams}}.addHeader("{{baseName}}", {{paramName}}){{/headerParams}} {{#vendorExtensions}}{{#queryParams}}{{^x-is-custom-request}}.addQueryParameter("{{baseName}}", {{paramName}}){{/x-is-custom-request}}{{#x-is-custom-request}}.addQueryParameters(parameters){{/x-is-custom-request}}{{/queryParams}}{{/vendorExtensions}} .build(); - return executeAsync(request, requestOptions, {{#vendorExtensions.x-is-generic}}{{{returnType}}}.class, innerType{{/vendorExtensions.x-is-generic}}{{^vendorExtensions.x-is-generic}}new TypeReference<{{{returnType}}}>() {}{{/vendorExtensions.x-is-generic}}); + return executeAsync(request, requestOptions, {{#vendorExtensions}}{{#x-is-generic}}{{{returnType}}}.class, innerType{{/x-is-generic}}{{/vendorExtensions}}{{^vendorExtensions.x-is-generic}}new TypeReference<{{{returnType}}}>(){}{{/vendorExtensions.x-is-generic}}); } {{! This case only sets `requestOptions` as optional }} /** * (asynchronously) * {{notes}}{{#allParams}} - * @param {{paramName}} {{{description}}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}}{{#vendorExtensions.x-is-generic}} - * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/vendorExtensions.x-is-generic}} + * @param {{paramName}} {{{description}}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}{{/allParams}}{{#vendorExtensions}}{{#x-is-generic}} + * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/x-is-generic}}{{/vendorExtensions}} {{> api_javadoc}} - public {{> return_type_async}} {{operationId}}Async({{#allParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#vendorExtensions.x-is-generic}}, Class innerType{{/vendorExtensions.x-is-generic}}) throws AlgoliaRuntimeException { - {{#returnType}}return {{/returnType}}this.{{operationId}}Async({{#allParams}}{{paramName}}, {{/allParams}}{{#vendorExtensions.x-is-generic}}innerType, {{/vendorExtensions.x-is-generic}}null); + public {{> return_type_async}} {{operationId}}Async({{#requiredParams}}@Nonnull {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#hasRequiredParams}}{{#hasOptionalParams}},{{/hasOptionalParams}}{{/hasRequiredParams}}{{#optionalParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/optionalParams}}{{#vendorExtensions}}{{#x-is-generic}}, Class innerType{{/x-is-generic}}{{/vendorExtensions}}) throws AlgoliaRuntimeException { + {{#returnType}}return {{/returnType}}this.{{operationId}}Async({{#allParams}}{{paramName}}, {{/allParams}}{{#vendorExtensions}}{{#x-is-generic}}innerType, {{/x-is-generic}}{{/vendorExtensions}}null); } {{! This case sets `requiredParams` + `requestOptions` }} @@ -190,12 +190,12 @@ public class {{classname}} extends ApiClient { /** * (asynchronously) * {{notes}}{{#requiredParams}} - * @param {{paramName}} {{{description}}} (required){{/requiredParams}}{{#vendorExtensions.x-is-generic}} - * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/vendorExtensions.x-is-generic}} + * @param {{paramName}} {{{description}}} (required){{/requiredParams}}{{#vendorExtensions}}{{#x-is-generic}} + * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/x-is-generic}}{{/vendorExtensions}} * @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions. {{> api_javadoc}} - public {{> return_type_async}} {{operationId}}Async({{#requiredParams}}{{{dataType}}} {{paramName}}, {{/requiredParams}}{{#vendorExtensions.x-is-generic}}Class innerType, {{/vendorExtensions.x-is-generic}}RequestOptions requestOptions) throws AlgoliaRuntimeException { - {{#returnType}}return {{/returnType}}this.{{operationId}}Async({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#requiredParams.0}},{{/requiredParams.0}}{{#optionalParams}}null{{^-last}},{{/-last}}{{/optionalParams}}, {{#vendorExtensions.x-is-generic}}innerType, {{/vendorExtensions.x-is-generic}}requestOptions); + public {{> return_type_async}} {{operationId}}Async({{#requiredParams}}@Nonnull {{{dataType}}} {{paramName}}, {{/requiredParams}}{{#vendorExtensions}}{{#x-is-generic}}Class innerType, {{/x-is-generic}}{{/vendorExtensions}}RequestOptions requestOptions) throws AlgoliaRuntimeException { + {{#returnType}}return {{/returnType}}this.{{operationId}}Async({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#requiredParams.0}},{{/requiredParams.0}}{{#optionalParams}}null{{^-last}},{{/-last}}{{/optionalParams}}, {{#vendorExtensions}}{{#x-is-generic}}innerType, {{/x-is-generic}}{{/vendorExtensions}}requestOptions); } {{/optionalParams.0}} @@ -204,11 +204,11 @@ public class {{classname}} extends ApiClient { /** * (asynchronously) * {{notes}}{{#requiredParams}} - * @param {{paramName}} {{{description}}} (required){{/requiredParams}}{{#vendorExtensions.x-is-generic}} - * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/vendorExtensions.x-is-generic}} + * @param {{paramName}} {{{description}}} (required){{/requiredParams}}{{#vendorExtensions}}{{#x-is-generic}} + * @param innerType The class held by the index, could be your custom class or {@link Object}.{{/x-is-generic}}{{/vendorExtensions}} {{> api_javadoc}} - public {{> return_type_async}} {{operationId}}Async({{#requiredParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#vendorExtensions.x-is-generic}}, Class innerType{{/vendorExtensions.x-is-generic}}) throws AlgoliaRuntimeException { - {{#returnType}}return {{/returnType}}this.{{operationId}}Async({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#requiredParams.0}},{{/requiredParams.0}}{{#optionalParams}}null{{^-last}},{{/-last}}{{/optionalParams}}, {{#vendorExtensions.x-is-generic}}innerType, {{/vendorExtensions.x-is-generic}}null); + public {{> return_type_async}} {{operationId}}Async({{#requiredParams}}@Nonnull {{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#vendorExtensions}}{{#x-is-generic}}, Class innerType{{/x-is-generic}}{{/vendorExtensions}}) throws AlgoliaRuntimeException { + {{#returnType}}return {{/returnType}}this.{{operationId}}Async({{#requiredParams}}{{paramName}}{{^-last}}, {{/-last}}{{/requiredParams}}{{#requiredParams.0}},{{/requiredParams.0}}{{#optionalParams}}null{{^-last}},{{/-last}}{{/optionalParams}}, {{#vendorExtensions}}{{#x-is-generic}}innerType, {{/x-is-generic}}{{/vendorExtensions}}null); } {{/optionalParams.0}} {{/operation}} diff --git a/templates/java/api_helpers.mustache b/templates/java/api_helpers.mustache index 02f539ab76..a70696ceb5 100644 --- a/templates/java/api_helpers.mustache +++ b/templates/java/api_helpers.mustache @@ -2,7 +2,6 @@ /** * Helper: Wait for a task to complete with `indexName` and `taskID`. * - * @summary Wait for a task to complete. * @param indexName The `indexName` where the operation was performed. * @param taskID The `taskID` returned in the method response. * @param maxRetries The maximum number of retry. 50 by default. (optional) @@ -10,17 +9,17 @@ * @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions. (optional) */ public void waitForTask(String indexName, Long taskID, int maxRetries, IntUnaryOperator timeout, RequestOptions requestOptions) { - TaskUtils.retryUntil(() -> { - return this.getTask(indexName, taskID, requestOptions); - }, (GetTaskResponse task) -> { - return task.getStatus() == TaskStatus.PUBLISHED; - }, maxRetries, timeout); + TaskUtils.retryUntil( + () -> this.getTask(indexName, taskID, requestOptions), + (GetTaskResponse task) -> task.getStatus() == TaskStatus.PUBLISHED, + maxRetries, + timeout + ); } /** * Helper: Wait for a task to complete with `indexName` and `taskID`. * - * @summary Wait for a task to complete. * @param indexName The `indexName` where the operation was performed. * @param taskID The `taskID` returned in the method response. * @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions. (optional) @@ -32,7 +31,6 @@ public void waitForTask(String indexName, Long taskID, RequestOptions requestOpt /** * Helper: Wait for a task to complete with `indexName` and `taskID`. * - * @summary Wait for a task to complete. * @param indexName The `indexName` where the operation was performed. * @param taskID The `taskID` returned in the method response. * @param maxRetries The maximum number of retry. 50 by default. (optional) @@ -45,7 +43,6 @@ public void waitForTask(String indexName, Long taskID, int maxRetries, IntUnaryO /** * Helper: Wait for a task to complete with `indexName` and `taskID`. * - * @summary Wait for a task to complete. * @param indexName The `indexName` where the operation was performed. * @param taskID The `taskID` returned in the method response. */ @@ -56,7 +53,6 @@ public void waitForTask(String indexName, Long taskID) { /** * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`. * - * @summary Wait for an API key task to be processed. * @param operation The `operation` that was done on a `key`. * @param key The `key` that has been added, deleted or updated. * @param apiKey Necessary to know if an `update` operation has been processed, compare fields of the response with it. @@ -79,9 +75,7 @@ public GetApiKeyResponse waitForApiKey( // when updating an api key, we poll the api until we receive a different key return TaskUtils.retryUntil( - () -> { - return this.getApiKey(key, requestOptions); - }, + () -> this.getApiKey(key, requestOptions), (GetApiKeyResponse respKey) -> { // we need to convert to an ApiKey object to use the `equals` method ApiKey sameType = new ApiKey() @@ -138,7 +132,6 @@ public GetApiKeyResponse waitForApiKey( /** * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`. * - * @summary Wait for an API key task to be processed. * @param operation The `operation` that was done on a `key`. (ADD or DELETE only) * @param key The `key` that has been added, deleted or updated. * @param maxRetries The maximum number of retry. 50 by default. (optional) @@ -152,7 +145,6 @@ public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, in /** * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`. * - * @summary Wait for an API key task to be processed. * @param operation The `operation` that was done on a `key`. * @param key The `key` that has been added, deleted or updated. * @param apiKey Necessary to know if an `update` operation has been processed, compare fields of the response with it. @@ -165,7 +157,6 @@ public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, Ap /** * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`. * - * @summary Wait for an API key task to be processed. * @param operation The `operation` that was done on a `key`. (ADD or DELETE only) * @param key The `key` that has been added, deleted or updated. * @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions. (optional) @@ -177,7 +168,6 @@ public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, Re /** * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`. * - * @summary Wait for an API key task to be processed. * @param operation The `operation` that was done on a `key`. * @param key The `key` that has been added, deleted or updated. * @param apiKey Necessary to know if an `update` operation has been processed, compare fields of the response with it. @@ -191,7 +181,6 @@ public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, Ap /** * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`. * - * @summary Wait for an API key task to be processed. * @param operation The `operation` that was done on a `key`. (ADD or DELETE only) * @param key The `key` that has been added, deleted or updated. * @param maxRetries The maximum number of retry. 50 by default. (optional) @@ -204,7 +193,6 @@ public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, in /** * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`. * - * @summary Wait for an API key task to be processed. * @param operation The `operation` that was done on a `key`. * @param key The `key` that has been added, deleted or updated. * @param apiKey Necessary to know if an `update` operation has been processed, compare fields of the response with it. @@ -216,7 +204,6 @@ public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, Ap /** * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`. * - * @summary Wait for an API key task to be processed. * @param operation The `operation` that was done on a `key`. (ADD or DELETE only) * @param key The `key` that has been added, deleted or updated. */ @@ -227,7 +214,6 @@ public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key) { /** * Helper: Returns an iterator on top of the `browse` method. * - * @summary Returns an iterator on `browse`. * @param indexName The index in which to perform the request. * @param params The `browse` parameters. * @param innerType The class held by the index, could be your custom class or {@link Object}. @@ -238,21 +224,18 @@ public Iterable browseObjects(String indexName, BrowseParamsObject params return AlgoliaIterableHelper.createIterable( () -> { - BrowseResponse response = this.browse(indexName, BrowseParams.of(params), innerType, requestOptions); + BrowseResponse response = this.browse(indexName, params, innerType, requestOptions); params.setCursor(response.getCursor()); currentCursor.value = response.getCursor(); return response.getHits().iterator(); }, - () -> { - return currentCursor.value != null; - } + () -> currentCursor.value != null ); } /** * Helper: Returns an iterator on top of the `browse` method. * - * @summary Returns an iterator on `browse`. * @param indexName The index in which to perform the request. * @param params The `browse` parameters. * @param innerType The class held by the index, could be your custom class or {@link Object}. @@ -264,7 +247,6 @@ public Iterable browseObjects(String indexName, BrowseParamsObject params /** * Helper: Returns an iterator on top of the `searchSynonyms` method. * - * @summary Returns an iterator on `searchSynonyms`. * @param indexName The index in which to perform the request. * @param type The synonym type. (optional) * @param params The `searchSynonyms` parameters. (optional) @@ -280,16 +262,13 @@ public Iterable browseSynonyms(String indexName, SynonymType type, S currentPage.value = response.getNbHits() < hitsPerPage ? null : currentPage.value + 1; return response.getHits().iterator(); }, - () -> { - return currentPage.value != null; - } + () -> currentPage.value != null ); } /** * Helper: Returns an iterator on top of the `searchSynonyms` method. * - * @summary Returns an iterator on `searchSynonyms`. * @param indexName The index in which to perform the request. * @param type The synonym type. (optional) * @param params The `searchSynonyms` parameters .(optional) @@ -302,7 +281,6 @@ public Iterable browseSynonyms(String indexName, SynonymType type, S /** * Helper: Returns an iterator on top of the `searchSynonyms` method. * - * @summary Returns an iterator on `searchSynonyms`. * @param indexName The index in which to perform the request. */ public Iterable browseSynonyms(String indexName) { @@ -312,7 +290,6 @@ public Iterable browseSynonyms(String indexName) { /** * Helper: Returns an iterator on top of the `searchRules` method. * - * @summary Returns an iterator on `searchRules`. * @param indexName The index in which to perform the request. * @param params The `searchRules` parameters. (optional) * @param requestOptions The requestOptions to send along with the query, they will be merged with the transporter requestOptions. (optional) @@ -328,16 +305,13 @@ public Iterable browseRules(String indexName, SearchRulesParams params, Re currentPage.value = response.getNbHits() < hitsPerPage ? null : currentPage.value + 1; return response.getHits().iterator(); }, - () -> { - return currentPage.value != null; - } + () -> currentPage.value != null ); } /** * Helper: Returns an iterator on top of the `searchRules` method. * - * @summary Returns an iterator on `searchRules`. * @param indexName The index in which to perform the request. * @param params The `searchRules` parameters. (optional) */ @@ -348,60 +322,9 @@ public Iterable browseRules(String indexName, SearchRulesParams params) { /** * Helper: Returns an iterator on top of the `searchRules` method. * - * @summary Returns an iterator on `searchRules`. * @param indexName The index in which to perform the request. */ public Iterable browseRules(String indexName) { - return browseRules(indexName, null, null); -} - -/** - * (asynchronously) Send multiple search queries to one or more indices. - * - * @param searchMethodParams Query requests and strategies. Results will be received in the same - * order as the queries. (required) - * @throws AlgoliaRuntimeException If it fails to process the API call - */ -public CompletableFuture> searchAsync(SearchMethodParams searchMethodParams, RequestOptions requestOptions) - throws AlgoliaRuntimeException { - return this.searchAsync(searchMethodParams, Object.class, requestOptions); -} - -/** - * (asynchronously) Send multiple search queries to one or more indices. - * - * @param searchMethodParams Query requests and strategies. Results will be received in the same - * order as the queries. (required) - * @throws AlgoliaRuntimeException If it fails to process the API call - */ -public CompletableFuture> searchAsync(SearchMethodParams searchMethodParams) - throws AlgoliaRuntimeException { - return this.searchAsync(searchMethodParams, Object.class, null); -} - -/** - * Send multiple search queries to one or more indices. - * - * @param searchMethodParams Query requests and strategies. Results will be received in the same - * order as the queries. (required) - * @param requestOptions The requestOptions to send along with the query, they will be merged with - * the transporter requestOptions. - * @throws AlgoliaRuntimeException If it fails to process the API call - */ -public SearchResponses search(SearchMethodParams searchMethodParams, RequestOptions requestOptions) - throws AlgoliaRuntimeException { - return this.search(searchMethodParams, Object.class, requestOptions); -} - -/** - * Send multiple search queries to one or more indices. - * - * @param searchMethodParams Query requests and strategies. Results will be received in the same - * order as the queries. (required) - * @throws AlgoliaRuntimeException If it fails to process the API call - */ -public SearchResponses search(SearchMethodParams searchMethodParams) - throws AlgoliaRuntimeException { - return this.search(searchMethodParams, Object.class, null); + return browseRules(indexName, new SearchRulesParams(), null); } {{/isSearchClient}} diff --git a/templates/java/generic_type.mustache b/templates/java/generic_type.mustache index b1c6411db8..2514c04a1c 100644 --- a/templates/java/generic_type.mustache +++ b/templates/java/generic_type.mustache @@ -1,4 +1,4 @@ {{#vendorExtensions}} - {{#isContainer}}{{#x-has-child-generic}}List<{{{complexType}}}>{{/x-has-child-generic}}{{^x-has-child-generic}}{{#x-propagated-generic}}List{{/x-propagated-generic}}{{^x-propagated-generic}}{{{datatypeWithEnum}}}{{/x-propagated-generic}}{{/x-has-child-generic}}{{/isContainer}} + {{#isContainer}}{{#x-has-child-generic}}List<{{{complexType}}}>List<{{{complexType}}}>{{/x-has-child-generic}}{{^x-has-child-generic}}{{#x-propagated-generic}}List{{/x-propagated-generic}}{{^x-propagated-generic}}{{{datatypeWithEnum}}}{{/x-propagated-generic}}{{/x-has-child-generic}}{{/isContainer}} {{^isContainer}}{{#x-is-generic}}T{{/x-is-generic}}{{^x-is-generic}}{{{datatypeWithEnum}}}{{/x-is-generic}}{{/isContainer}} {{/vendorExtensions}} diff --git a/templates/java/model.mustache b/templates/java/model.mustache index ede048f4fb..0cc317badb 100644 --- a/templates/java/model.mustache +++ b/templates/java/model.mustache @@ -10,9 +10,10 @@ import {{import}}; import java.io.Serializable; {{/serializableModel}} import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.annotation.*; {{#models}} {{#model}} -{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{>pojo}}{{/vendorExtensions.x-is-one-of-interface}}{{/isEnum}} +{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{#vendorExtensions.x-is-one-of}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of}}{{^vendorExtensions.x-is-one-of}}{{>pojo}}{{/vendorExtensions.x-is-one-of}}{{/isEnum}} {{/model}} {{/models}} diff --git a/templates/java/modelEnum.mustache b/templates/java/modelEnum.mustache index 6ed179c82a..1564f57003 100644 --- a/templates/java/modelEnum.mustache +++ b/templates/java/modelEnum.mustache @@ -1,10 +1,8 @@ -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonValue; - /** * {{{description}}}{{^description}}Gets or Sets {{{name}}}{{/description}} */ -{{>additionalEnumTypeAnnotations}}public enum {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} { + {{#vendorExtensions.x-one-of-element}}@JsonDeserialize(as = {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.class){{/vendorExtensions.x-one-of-element}} +{{>additionalEnumTypeAnnotations}}public enum {{{datatypeWithEnum}}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}{{#vendorExtensions.x-one-of-element}} implements {{#vendorExtensions.x-one-of-element-parents}}{{parent_classname}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-one-of-element-parents}}{{/vendorExtensions.x-one-of-element}} { {{#allowableValues}}{{#enumVars}} {{#enumDescription}}/** * {{{.}}} diff --git a/templates/java/oneof_interface.mustache b/templates/java/oneof_interface.mustache index 118fbc51df..8f1ffd11bd 100644 --- a/templates/java/oneof_interface.mustache +++ b/templates/java/oneof_interface.mustache @@ -1,13 +1,11 @@ -import com.algolia.utils.CompoundType; -import com.algolia.utils.JSON; +import com.algolia.exceptions.AlgoliaRuntimeException; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.annotation.*; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.algolia.exceptions.AlgoliaRuntimeException; +import com.algolia.utils.CompoundType; + import java.io.IOException; import java.util.List; import java.util.logging.Logger; @@ -18,54 +16,69 @@ import java.util.logging.Logger; */{{#isDeprecated}} @Deprecated{{/isDeprecated}} @JsonDeserialize(using = {{classname}}.Deserializer.class) -@JsonSerialize(using = {{classname}}.Serializer.class) {{>additionalModelTypeAnnotations}} -public interface {{classname}} extends CompoundType { - - {{#vendorExtensions.x-one-of-list}} - static {{classname}}<{{{type}}}> of{{#vendorExtensions.x-one-of-explicit-name}}{{{name}}}{{/vendorExtensions.x-one-of-explicit-name}}({{{type}}} inside) { - return new {{classname}}{{name}}(inside); +public interface {{classname}} { + + {{#vendorExtensions}} + {{#x-one-of-list}} + {{^child}} + /** {{classname}} as {{{type}}} wrapper. */ + static {{classname}} of{{#x-one-of-explicit-name}}{{name}}{{/x-one-of-explicit-name}}({{{type}}} value) { + return new {{name}}Wrapper(value); } + {{/child}} + {{/x-one-of-list}} - {{/vendorExtensions.x-one-of-list}} + {{#x-one-of-list}} + {{^child}} - class Serializer extends StdSerializer<{{classname}}> { - public Serializer(Class<{{classname}}> t) { - super(t); + /** {{classname}} as {{{type}}} wrapper. */ + @JsonSerialize(using = {{name}}Wrapper.Serializer.class) + class {{name}}Wrapper implements {{classname}}{ + private final {{{type}}} value; + + {{name}}Wrapper({{{type}}} value) { + this.value = value; } - public Serializer() { - this(null); + public {{{type}}} getValue() { + return value; } - @Override - public void serialize({{classname}} value, JsonGenerator jgen, SerializerProvider provider) throws IOException { - jgen.writeObject(value.get()); + static class Serializer extends JsonSerializer<{{name}}Wrapper> { + + @Override + public void serialize({{name}}Wrapper value, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeObject(value.getValue()); + } } } + {{/child}} + {{/x-one-of-list}} + {{/vendorExtensions}} - class Deserializer extends StdDeserializer<{{classname}}> { + class Deserializer extends JsonDeserializer<{{classname}}> { private static final Logger LOGGER = Logger.getLogger(Deserializer.class.getName()); - public Deserializer() { - this({{classname}}.class); - } - - public Deserializer(Class vc) { - super(vc); - } - - @Override + @Override public {{classname}} deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { JsonNode tree = jp.readValueAsTree(); {{#vendorExtensions.x-one-of-list}} // deserialize {{{type}}} if (tree.{{#isObject}}isObject(){{/isObject}}{{#isList}}isArray(){{/isList}}{{^isObject}}{{^isList}}isValueNode(){{/isList}}{{/isObject}}{{#discriminators}} && tree.has("{{field}}"){{/discriminators}}) { - try(JsonParser parser = tree.traverse(jp.getCodec())) { - {{{type}}} value = parser.readValueAs(new TypeReference<{{{type}}}>() {}); + try(JsonParser parser = tree.traverse(jp.getCodec())) { + {{#isObject}} + return parser.readValueAs({{{type}}}.class); + {{/isObject}} + {{#isList}} + return parser.readValueAs(new TypeReference<{{{type}}}>(){}); + {{/isList}} + {{^isObject}}{{^isList}} + {{{type}}} value = parser.readValueAs({{{type}}}.class); return {{{classname}}}.of{{#vendorExtensions.x-one-of-explicit-name}}{{{name}}}{{/vendorExtensions.x-one-of-explicit-name}}(value); + {{/isList}}{{/isObject}} } catch (Exception e) { // deserialization failed, continue LOGGER.finest("Failed to deserialize oneOf {{{type}}} (error: " + e.getMessage() + ") (type: {{{type}}})"); @@ -90,17 +103,3 @@ public interface {{classname}} extends CompoundType { } } -{{#vendorExtensions.x-one-of-list}} -class {{classname}}{{name}} implements {{classname}}<{{{type}}}> { - private final {{{type}}} value; - - {{classname}}{{name}}({{{type}}} value) { - this.value = value; - } - - @Override - public {{{type}}} get() { - return value; - } -} -{{/vendorExtensions.x-one-of-list}} diff --git a/templates/java/pojo.mustache b/templates/java/pojo.mustache index c9d4134386..d704849820 100644 --- a/templates/java/pojo.mustache +++ b/templates/java/pojo.mustache @@ -5,7 +5,8 @@ @Deprecated{{/isDeprecated}} {{>additionalModelTypeAnnotations}} -public class {{classname}}{{#vendorExtensions.x-has-child-generic}}{{/vendorExtensions.x-has-child-generic}} { +{{#vendorExtensions.x-one-of-element}}@JsonDeserialize(as = {{classname}}.class){{/vendorExtensions.x-one-of-element}} +public class {{classname}}{{#vendorExtensions.x-has-child-generic}}{{/vendorExtensions.x-has-child-generic}}{{#vendorExtensions.x-one-of-element}} implements {{#vendorExtensions.x-one-of-element-parents}}{{parent_classname}}{{^-last}}, {{/-last}}{{/vendorExtensions.x-one-of-element-parents}}{{/vendorExtensions.x-one-of-element}} { {{#serializableModel}} private static final long serialVersionUID = 1L; diff --git a/templates/java/tests/maybeConvertOneOf.mustache b/templates/java/tests/maybeConvertOneOf.mustache index 3959bd7f52..c2ea3a09f4 100644 --- a/templates/java/tests/maybeConvertOneOf.mustache +++ b/templates/java/tests/maybeConvertOneOf.mustache @@ -1 +1 @@ -{{#oneOfModel}}{{{parentClassName}}}.of{{#x-one-of-explicit-name}}{{{type}}}{{/x-one-of-explicit-name}}({{{key}}}{{suffix}}){{/oneOfModel}}{{^oneOfModel}}{{{key}}}{{suffix}}{{/oneOfModel}} \ No newline at end of file +{{#oneOfModel}}{{^hasWrapper}}{{{key}}}{{suffix}}{{/hasWrapper}}{{#hasWrapper}}{{{parentClassName}}}.of{{#x-one-of-explicit-name}}{{{type}}}{{/x-one-of-explicit-name}}({{{key}}}{{suffix}}){{/hasWrapper}}{{/oneOfModel}}{{^oneOfModel}}{{{key}}}{{suffix}}{{/oneOfModel}} \ No newline at end of file diff --git a/templates/kotlin/model.mustache b/templates/kotlin/model.mustache index 037bef671c..d4ef548e00 100644 --- a/templates/kotlin/model.mustache +++ b/templates/kotlin/model.mustache @@ -3,6 +3,6 @@ package {{modelPackage}} {{#models}} {{#model}} -{{#vendorExtensions.x-is-type-alias}}{{> typealias}}{{/vendorExtensions.x-is-type-alias}}{{^vendorExtensions.x-is-type-alias}}{{#isEnum}}{{>enum_class}}{{/isEnum}}{{^isEnum}}{{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{#isAlias}}typealias {{classname}} = {{{dataType}}}{{/isAlias}}{{^isAlias}}{{>data_class}}{{/isAlias}}{{/vendorExtensions.x-is-one-of-interface}}{{/isEnum}}{{/vendorExtensions.x-is-type-alias}} +{{#vendorExtensions.x-is-type-alias}}{{> typealias}}{{/vendorExtensions.x-is-type-alias}}{{^vendorExtensions.x-is-type-alias}}{{#isEnum}}{{>enum_class}}{{/isEnum}}{{^isEnum}}{{#vendorExtensions.x-is-one-of}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of}}{{^vendorExtensions.x-is-one-of}}{{#isAlias}}typealias {{classname}} = {{{dataType}}}{{/isAlias}}{{^isAlias}}{{>data_class}}{{/isAlias}}{{/vendorExtensions.x-is-one-of}}{{/isEnum}}{{/vendorExtensions.x-is-type-alias}} {{/model}} {{/models}}