From 7f0adb61d4b1c87cb3eb661b84806111723c8b95 Mon Sep 17 00:00:00 2001 From: Thomas Farr Date: Fri, 30 Aug 2024 16:32:17 +1200 Subject: [PATCH] Begin generating client implementations (#1052) * Tweak client generation to extend from existing classes Signed-off-by: Thomas Farr * Modify existing client classes to be abstract base classes Signed-off-by: Thomas Farr * Re-run generator Signed-off-by: Thomas Farr * ./gradlew spotlessApply Signed-off-by: Thomas Farr --------- Signed-off-by: Thomas Farr (cherry picked from commit dbde609368fc34b45cae5af416eb8ee8f4c9764b) --- .../client/codegen/model/Namespace.java | 62 ++++++++++++++++--- .../client/codegen/model/OperationGroup.java | 7 ++- .../client/codegen/model/RequestShape.java | 10 +-- .../client/codegen/model/SpecTransformer.java | 2 +- .../opensearch/client/codegen/model/Type.java | 4 ++ .../client/codegen/templates/Client.mustache | 23 ++++++- 6 files changed, 89 insertions(+), 19 deletions(-) diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/Namespace.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/Namespace.java index 7ca9322130..3398b98583 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/model/Namespace.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/Namespace.java @@ -10,6 +10,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -75,40 +76,83 @@ public void render(ShapeRenderingContext ctx) throws RenderException { shape.render(ctx); } + var operations = getOperationsForClient(); + if (operations.isEmpty()) return; - // TODO: Render clients when won't be partial and conflict with non-generated code - // new Client(this, false).render(outputDir, formatter); - // new Client(this, true).render(outputDir, formatter); + new Client(this, false, operations).render(ctx); + new Client(this, true, operations).render(ctx); + } + + private Collection getOperationsForClient() { + if ("core".equals(name)) return Collections.emptyList(); + return ("".equals(name) ? child("core") : this).operations.values(); + } + + private String getClientClassName(boolean async, boolean base) { + return "OpenSearch" + Strings.toPascalCase(name) + (async ? "Async" : "") + "Client" + (base ? "Base" : ""); + } + + private Type getClientType(boolean async, boolean base) { + var type = Type.builder().pkg(getPackageName()).name(getClientClassName(async, base)); + if (base) { + type.genericArgs(getClientType(async, false)); + } + return type.build(); } private static class Client extends Shape { private final boolean async; + private final Collection operations; - private Client(Namespace parent, boolean async) { - super(parent, "OpenSearch" + Strings.toPascalCase(parent.name) + (async ? "Async" : "") + "Client", null, null); + private Client(Namespace parent, boolean async, Collection operations) { + super(parent, parent.getClientClassName(async, false), null, null); this.async = async; + this.operations = operations; } @Override public Type getExtendsType() { - return Types.Client.ApiClient(Types.Client.Transport.OpenSearchTransport, getType()); + switch (parent.name) { + case "": + return parent.getClientType(async, true); + default: + return Types.Client.ApiClient(Types.Client.Transport.OpenSearchTransport, getType()); + } } public String getName() { return parent.name; } - public Collection getChildren() { - return Lists.filterMap(parent.children.values(), n -> !n.operations.isEmpty(), n -> new Client(n, async)); + public Collection getChildren() { + return Lists.filterMap(parent.children.values(), n -> !n.getOperationsForClient().isEmpty(), n -> new ClientRef(n, async)); } public Collection getOperations() { - return parent.operations.values(); + return operations; } public boolean isAsync() { return this.async; } + + private static class ClientRef { + private final Type type; + private final String name; + + public ClientRef(Namespace namespace, boolean async) { + this.type = namespace.getClientType(async, false); + this.name = namespace.name; + } + + public Type getType() { + return type; + } + + public String getName() { + return name; + } + } } } diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/OperationGroup.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/OperationGroup.java index fa158e8e5f..818a4acd40 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/model/OperationGroup.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/OperationGroup.java @@ -36,7 +36,7 @@ public static OperationGroup from(@Nonnull String operationGroup) { return new OperationGroup(operationGroup.substring(0, index), operationGroup.substring(index + 1)); } - private OperationGroup(@Nullable String namespace, @Nonnull String name) { + public OperationGroup(@Nullable String namespace, @Nonnull String name) { this.namespace = namespace; this.name = Strings.requireNonBlank(name, "name must not be blank"); } @@ -51,6 +51,11 @@ public String getName() { return name; } + @Nonnull + public String asTypedefPrefix() { + return (namespace == null ? "_global" : namespace) + "." + name; + } + @Override public String toString() { return namespace == null ? name : namespace + "." + name; diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/RequestShape.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/RequestShape.java index 3d0e25ef7e..b46ef19025 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/model/RequestShape.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/RequestShape.java @@ -37,7 +37,7 @@ public class RequestShape extends ObjectShape { private final Map fields = new TreeMap<>(); public RequestShape(@Nonnull Namespace parent, @Nonnull OperationGroup operationGroup, @Nullable String description) { - super(parent, requestClassName(operationGroup), operationGroup + ".Request", description); + super(parent, requestClassName(operationGroup), operationGroup.asTypedefPrefix() + ".Request", description); this.operationGroup = operationGroup; } @@ -72,8 +72,8 @@ public void addSupportedHttpMethod(String method) { httpMethods.add(method); } - public String getResponseType() { - return responseClassName(operationGroup); + public Type getResponseType() { + return Type.builder().pkg(getPackageName()).name(responseClassName(operationGroup)).build(); } public boolean canBeSingleton() { @@ -145,13 +145,13 @@ public boolean hasAnyRequiredFields() { } @Nonnull - public static String requestClassName(@Nonnull OperationGroup operationGroup) { + private static String requestClassName(@Nonnull OperationGroup operationGroup) { Objects.requireNonNull(operationGroup, "operationGroup must not be null"); return Strings.toPascalCase(operationGroup.getName()) + "Request"; } @Nonnull - public static String responseClassName(@Nonnull OperationGroup operationGroup) { + private static String responseClassName(@Nonnull OperationGroup operationGroup) { Objects.requireNonNull(operationGroup, "operationGroup must not be null"); return Strings.toPascalCase(operationGroup.getName()) + "Response"; } diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/SpecTransformer.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/SpecTransformer.java index e228764097..6848dc7b9c 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/model/SpecTransformer.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/SpecTransformer.java @@ -107,7 +107,7 @@ private void visit(@Nonnull OperationGroup group, @Nonnull List{{/async}} {{#camelCase}}{{id}}{{/camelCase}}() throws {{TYPES.Java.Io.IOException}}, {{TYPES.Client.OpenSearch._Types.OpenSearchException}} { + return this.transport.performRequest{{#async}}Async{{/async}}({{type}}._INSTANCE, {{type}}._ENDPOINT, this.transportOptions); + } + {{/canBeSingleton}} + {{^canBeSingleton}} /** * {{description}} */ public {{#async}}{{TYPES.Java.Util.Concurrent.CompletableFuture}}<{{/async}}{{responseType}}{{#async}}>{{/async}} {{#camelCase}}{{id}}{{/camelCase}}({{type}} request) throws {{TYPES.Java.Io.IOException}}, {{TYPES.Client.OpenSearch._Types.OpenSearchException}} { - return this.transport.performRequest{{#async}}Async{{/async}}(request, {{type}}._ENDPOINT, this.transportOptions); + @SuppressWarnings("unchecked") + {{jsonEndpointType}} endpoint = ({{jsonEndpointType}}) {{type.name}}._ENDPOINT; + + return this.transport.performRequest{{#async}}Async{{/async}}(request, endpoint, this.transportOptions); } /** @@ -44,8 +60,9 @@ */ public {{#async}}{{TYPES.Java.Util.Concurrent.CompletableFuture}}<{{/async}}{{responseType}}{{#async}}>{{/async}} {{#camelCase}}{{id}}{{/camelCase}}() throws IOException, OpenSearchException { - return {{#camelCase}}{{id}}{{/camelCase}}(new {{type.builderType}}().build()); + return this.transport.performRequest{{#async}}Async{{/async}}(new {{type.builderType}}().build(), {{type.name}}._ENDPOINT, this.transportOptions); } {{/hasAnyRequiredFields}} + {{/canBeSingleton}} {{/operations}} -} \ No newline at end of file +}