diff --git a/java-client/src/main/java/org/opensearch/client/transport/endpoints/BooleanEndpoint.java b/java-client/src/main/java/org/opensearch/client/transport/endpoints/BooleanEndpoint.java index a6969671ac..70200eaab4 100644 --- a/java-client/src/main/java/org/opensearch/client/transport/endpoints/BooleanEndpoint.java +++ b/java-client/src/main/java/org/opensearch/client/transport/endpoints/BooleanEndpoint.java @@ -38,6 +38,15 @@ public class BooleanEndpoint extends SimpleEndpoint { + public BooleanEndpoint( + Function method, + Function requestUrl, + Function> queryParameters, + Function> headers + ) { + super(method, requestUrl, queryParameters, headers, false, null); + } + public BooleanEndpoint( String id, Function method, diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/EnumShape.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/EnumShape.java index 90a2fae57c..1150a1813f 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/model/EnumShape.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/EnumShape.java @@ -13,7 +13,9 @@ import java.util.List; import java.util.Set; import java.util.TreeMap; +import javax.annotation.Nullable; import org.opensearch.client.codegen.utils.JavaClassKind; +import org.opensearch.client.codegen.utils.Markdown; import org.opensearch.client.codegen.utils.Strings; public class EnumShape extends Shape { @@ -38,14 +40,17 @@ public Collection getImplementsTypes() { return List.of(Types.Client.Json.JsonEnum); } - public void addVariant(String value, boolean deprecated) { + public void addVariant(String value, String description, boolean deprecated) { var variant = variants.get(value.toLowerCase()); if (variant == null) { - variant = new Variant(value, deprecated); + variant = new Variant(value, description, deprecated); variants.put(value.toLowerCase(), variant); } else { variant.addAlias(value); variant.setDeprecated(variant.isDeprecated() || deprecated); + if (description != null) { + variant.setDescription(description); + } } } @@ -61,9 +66,11 @@ public static class Variant { private final String wireName; private final Set aliases = new HashSet<>(); private boolean deprecated; + private String description; - public Variant(String wireName, boolean deprecated) { + public Variant(String wireName, String description, boolean deprecated) { this.wireName = wireName; + setDescription(description); this.deprecated = deprecated; } @@ -71,6 +78,14 @@ public String getWireName() { return wireName; } + public String getDescription() { + return description; + } + + public void setDescription(@Nullable String description) { + this.description = description != null ? Markdown.toJavaDocHtml(description) : null; + } + public Set getAliases() { return aliases; } diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/ObjectShape.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/ObjectShape.java index 3ecac3830d..9caa269bf5 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/model/ObjectShape.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/ObjectShape.java @@ -21,6 +21,7 @@ public class ObjectShape extends Shape { protected final Map bodyFields = new TreeMap<>(); protected Field additionalPropertiesField; + private String shortcutProperty; public ObjectShape(Namespace parent, String className, String typedefName, String description) { super(parent, className, typedefName, description); @@ -62,6 +63,14 @@ public Field getAdditionalPropertiesField() { return additionalPropertiesField; } + public String getShortcutProperty() { + return shortcutProperty; + } + + public void setShortcutProperty(String shortcutProperty) { + this.shortcutProperty = shortcutProperty; + } + public boolean hasFieldsToSerialize() { return !bodyFields.isEmpty() || additionalPropertiesField != null; } @@ -108,6 +117,10 @@ public Collection getAnnotations() { return (hasFieldsToSerialize() || extendsOtherShape()) && !isAbstract() ? List.of(Types.Client.Json.JsonpDeserializable) : null; } + public boolean shouldImplementPlainDeserializable() { + return Set.of("SourceField", "TypeMapping").contains(getClassName()); + } + public static class ReferencingDiscriminatedUnion { private final TaggedUnionShape union; private final String discriminatorValue; 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 f8d270e772..fc351a1156 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 @@ -35,6 +35,7 @@ public class RequestShape extends ObjectShape { private final Map pathParams = new TreeMap<>(); @Nonnull private final Map fields = new TreeMap<>(); + private boolean isBooleanRequest; public RequestShape(@Nonnull Namespace parent, @Nonnull OperationGroup operationGroup, @Nullable String description) { super(parent, requestClassName(operationGroup), operationGroup.asTypedefPrefix() + ".Request", description); @@ -72,8 +73,18 @@ public void addSupportedHttpMethod(String method) { httpMethods.add(method); } + public void setIsBooleanRequest() { + isBooleanRequest = true; + } + + public boolean isBooleanRequest() { + return isBooleanRequest; + } + public Type getResponseType() { - return Type.builder().withPackage(getPackageName()).withName(responseClassName(operationGroup)).build(); + return !isBooleanRequest + ? Type.builder().withPackage(getPackageName()).withName(responseClassName(operationGroup)).build() + : Types.Client.Transport.Endpoints.BooleanResponse; } public boolean canBeSingleton() { @@ -169,6 +180,10 @@ private static String responseClassName(@Nonnull OperationGroup operationGroup) private static String classBaseName(@Nonnull OperationGroup operationGroup) { Objects.requireNonNull(operationGroup, "operationGroup must not be null"); switch (operationGroup.toString()) { + case "indices.create": + return "CreateIndex"; + case "indices.delete": + return "DeleteIndex"; case "indices.get": return "GetIndex"; case "snapshot.clone": 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 b9452504f1..a631254623 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 @@ -28,6 +28,7 @@ import org.opensearch.client.codegen.model.overrides.Overrides; import org.opensearch.client.codegen.model.overrides.PropertyOverride; import org.opensearch.client.codegen.model.overrides.SchemaOverride; +import org.opensearch.client.codegen.model.overrides.ShouldGenerate; import org.opensearch.client.codegen.openapi.HttpStatusCode; import org.opensearch.client.codegen.openapi.In; import org.opensearch.client.codegen.openapi.JsonPointer; @@ -122,10 +123,14 @@ private void visit(@Nonnull OperationGroup group, @Nonnull List c.get(MimeType.Json)) .flatMap(OpenApiMediaType::getSchema) .map(OpenApiSchema::resolve) - .orElse(OpenApiSchema.ANONYMOUS_OBJECT); - - visitInto(bodySchema, shape); + .ifPresent(s -> visitInto(s, shape)); if (shape.getExtendsType() == null) { shape.setExtendsType(Types.Client.OpenSearch._Types.RequestBase); @@ -252,33 +255,25 @@ private Shape visit(Namespace parent, String className, String typedefName, Open var description = schema.getDescription().orElse(null); - var oneOf = schema.getOneOf(); - var isTaggedUnion = oneOf.isPresent() - && (schema.getDiscriminator().isPresent() || oneOf.orElseThrow().stream().allMatch(OpenApiSchema::hasTitle)); + var isTaggedUnion = isTaggedUnion(schema); + var isShortcutPropertyObject = isShortcutPropertyObject(schema); if (schema.isArray()) { shape = new ArrayShape(parent, className, mapType(schema), typedefName, description); visitedSchemas.putIfAbsent(schema, shape); - } else if (schema.isStringEnum() || (oneOf.isPresent() && oneOf.get().stream().allMatch(OpenApiSchema::isStringEnum))) { + } else if (isEnum(schema)) { var enumShape = new EnumShape(parent, className, typedefName, description); shape = enumShape; visitedSchemas.putIfAbsent(schema, shape); - if (oneOf.isPresent()) { - oneOf.get().forEach(s -> { - var isDeprecated = s.getVersionDeprecated().isPresent(); - s.getEnums().orElseThrow().forEach(v -> enumShape.addVariant(v, isDeprecated)); - }); - } else { - schema.getEnums().orElseThrow().forEach(v -> enumShape.addVariant(v, false)); - } + visitInto(schema, enumShape); } else if (isTaggedUnion) { var discriminatingField = schema.getDiscriminator().flatMap(OpenApiDiscriminator::getPropertyName).orElse(null); var taggedUnion = new TaggedUnionShape(parent, className, typedefName, description, discriminatingField); shape = taggedUnion; visitedSchemas.putIfAbsent(schema, shape); - oneOf.get().forEach(s -> { + schema.getOneOf().or(schema::getAnyOf).orElseThrow().forEach(s -> { String name; if (discriminatingField != null) { var props = new HashMap(); @@ -301,7 +296,7 @@ private Shape visit(Namespace parent, String className, String typedefName, Open } taggedUnion.addVariant(name, mapType(s)); }); - } else if (schema.determineSingleType().orElse(null) == OpenApiSchemaType.Object) { + } else if (isShortcutPropertyObject || schema.determineSingleType().orElse(null) == OpenApiSchemaType.Object) { if (schema.getProperties().isEmpty() && schema.getAdditionalProperties().isPresent()) { shape = new DictionaryResponseShape( parent, @@ -317,6 +312,13 @@ private Shape visit(Namespace parent, String className, String typedefName, Open shape = objShape; visitedSchemas.putIfAbsent(schema, shape); + if (isShortcutPropertyObject) { + var oneOf = schema.getOneOf().orElseThrow(); + var shortcutProperty = oneOf.get(0).getTitle().orElseThrow(); + objShape.setShortcutProperty(shortcutProperty); + schema = oneOf.get(1); + } + visitInto(schema, objShape); } } else { @@ -369,7 +371,7 @@ private void visitInto(OpenApiSchema schema, ObjectShape shape) { } } - private Set collectObjectProperties( + private static Set collectObjectProperties( OpenApiSchema schema, Map properties, List additionalProperties @@ -428,6 +430,21 @@ private Set collectObjectProperties( return schema.getRequired().orElseGet(Collections::emptySet); } + private void visitInto(OpenApiSchema schema, EnumShape shape) { + var isDeprecated = schema.getVersionDeprecated().isPresent(); + + if (schema.hasOneOf()) { + schema.getOneOf().orElseThrow().forEach(s -> visitInto(s, shape)); + } else if (schema.hasEnums()) { + var enums = schema.getEnums().orElseThrow(); + var description = enums.size() == 1 ? schema.getDescription().orElse(null) : null; + enums.forEach(v -> shape.addVariant(v, description, isDeprecated)); + } else if (schema.hasConst()) { + var value = (String) schema.getConst().orElseThrow(); + shape.addVariant(value, schema.getDescription().orElse(null), isDeprecated); + } + } + private Type mapType(OpenApiSchema schema) { return mapType(schema, false); } @@ -452,10 +469,26 @@ private Type mapTypeInner(OpenApiSchema schema) { if (schema.has$ref()) { schema = schema.resolve(); + var schemaOverrides = overrides.getSchema(schema.getPointer()); + var overriddenMappedType = schemaOverrides.flatMap(SchemaOverride::getMappedType); + + if (overriddenMappedType.isPresent()) { + return overriddenMappedType.get(); + } + if (!shouldKeepRef(schema)) { return mapType(schema); } + var shouldGenerate = schemaOverrides.map(SchemaOverride::shouldGenerate).orElse(ShouldGenerate.IfNeeded); + + if (shouldGenerate == ShouldGenerate.Never) { + return Type.builder() + .withPackage(Types.Client.OpenSearch.PACKAGE + "." + schema.getNamespace().orElseThrow()) + .withName(schema.getName().orElseThrow()) + .build(); + } + var shape = visit(schema); return shape.getType(); @@ -582,38 +615,24 @@ private boolean shouldKeepRef(OpenApiSchema schema) { if (schema.isArray() || schema.isBoolean() || schema.isInteger() || schema.isNumber()) { return false; } + if (isEnum(schema)) { + return true; + } if (schema.isString()) { - return schema.hasEnums(); + return false; } if (schema.isObject() && schema.getProperties().map(Map::isEmpty).orElse(true) && schema.getAdditionalProperties().map(s -> s.getTitle().isEmpty()).orElse(false)) { return false; } - if (schema.getOneOf().isPresent()) { - if (schema.getDiscriminator().isPresent()) { - return true; - } - var allObject = true; - var allHaveTitle = true; - var allStringEnum = true; - for (var s : schema.getOneOf().orElseThrow()) { - if (s.determineSingleType().orElse(null) != OpenApiSchemaType.Object) { - allObject = false; - } - if (s.getTitle().isEmpty()) { - allHaveTitle = false; - } - if (!s.isStringEnum()) { - allStringEnum = false; - } - } - return allObject || allHaveTitle || allStringEnum; + if (isTaggedUnion(schema)) { + return true; } - if (schema.getAllOf().isPresent()) { - return schema.determineSingleType().orElse(null) == OpenApiSchemaType.Object; + if (isShortcutPropertyObject(schema)) { + return true; } - return true; + return schema.determineSingleType().orElse(null) == OpenApiSchemaType.Object; } private static boolean isOneOfSingleAndArray(List oneOf) { @@ -628,4 +647,56 @@ private static boolean isOneOfSingleAndArray(List oneOf) { var items = second.getItems().orElseThrow(); return first.getTypes().equals(items.getTypes()) && first.get$ref().equals(items.get$ref()); } + + private static boolean isEnum(OpenApiSchema schema) { + if (schema.isString()) { + return schema.hasEnums() || schema.hasConst(); + } + if (schema.getOneOf().isPresent()) { + return schema.getOneOf().get().stream().allMatch(SpecTransformer::isEnum); + } + return false; + } + + private static boolean isShortcutPropertyObject(OpenApiSchema schema) { + var oneOf = schema.getOneOf().orElse(null); + + if (oneOf == null || oneOf.size() != 2) { + return false; + } + + var first = oneOf.get(0); + var second = oneOf.get(1); + + if (!first.hasTitle() || second.hasTitle()) { + return false; + } + + var secondType = second.determineSingleType().orElse(null); + if (secondType != OpenApiSchemaType.Object) { + return false; + } + + var properties = new HashMap(); + collectObjectProperties(second, properties, new ArrayList<>()); + + return properties.containsKey(first.getTitle().orElseThrow()); + } + + private static boolean isTaggedUnion(OpenApiSchema schema) { + if (schema.hasOneOf()) { + if (schema.getDiscriminator().isPresent()) { + return true; + } + return isTaggedUnion(schema.getOneOf().orElseThrow()); + } + if (schema.hasAnyOf()) { + return isTaggedUnion(schema.getAnyOf().orElseThrow()); + } + return false; + } + + private static boolean isTaggedUnion(List oneOfAnyOf) { + return oneOfAnyOf.stream().allMatch(OpenApiSchema::hasTitle); + } } diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/TaggedUnionShape.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/TaggedUnionShape.java index 8e317e2ef8..79ee51340c 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/model/TaggedUnionShape.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/TaggedUnionShape.java @@ -36,10 +36,6 @@ public Collection getVariants() { return variants.values(); } - public Collection getShapeVariants() { - return Lists.filter(getVariants(), v -> v.getType().isInsidePackage("org.opensearch") && !v.getType().isEnum()); - } - public Collection getNonShapeVariants() { return Lists.filter(getVariants(), v -> !v.getType().isInsidePackage("org.opensearch")); } @@ -76,14 +72,29 @@ public Type getVariantBaseType() { } public boolean canStringify() { - return !isDiscriminated() && getVariants().stream().allMatch(v -> v.getType().isString() || v.getType().isEnum()); + return !isDiscriminated() && getVariants().stream().allMatch(v -> { + var t = v.getType(); + return t.isPotentiallyBoxedPrimitive() || t.isString() || t.isEnum(); + }); + } + + public boolean hasAmbiguities() { + if (isDiscriminated()) { + return false; + } + + return getVariants().stream().filter(v -> { + var t = v.getType(); + return t.isString() || t.isEnum(); + }).count() > 1; } @Override public void render(ShapeRenderingContext ctx) throws RenderException { super.render(ctx); - if (!getShapeVariants().isEmpty()) { - new Builders(this).render(ctx); + var buildableVariants = Lists.filter(getVariants(), v -> v.getType().hasBuilder()); + if (!buildableVariants.isEmpty()) { + new Builders(this, buildableVariants).render(ctx); } if (isDiscriminated()) { new VariantInterface(this).render(ctx); @@ -130,9 +141,9 @@ private static String buildDescription(TaggedUnionShape union) { private final String unionClassName; private final Collection variants; - private Builders(TaggedUnionShape union) { + private Builders(TaggedUnionShape union, Collection variants) { super(union.getParent(), union.getClassName() + "Builders", null, buildDescription(union)); - variants = union.getShapeVariants(); + this.variants = variants; unionClassName = union.getClassName(); } diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/Types.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/Types.java index 7545444777..aab2d65e5f 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/model/Types.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/Types.java @@ -39,12 +39,20 @@ private static Map asMap(Class clazz) { return map; } + private static Type type(String name) { + return Type.builder().withName(name).build(); + } + + private static Type type(String packageName, String name) { + return Type.builder().withPackage(packageName).withName(name).build(); + } + public static final class Primitive { - public static final Type Boolean = Type.builder().withName("boolean").build(); - public static final Type Int = Type.builder().withName("int").build(); - public static final Type Long = Type.builder().withName("long").build(); - public static final Type Float = Type.builder().withName("float").build(); - public static final Type Double = Type.builder().withName("double").build(); + public static final Type Boolean = type("boolean"); + public static final Type Int = type("int"); + public static final Type Long = type("long"); + public static final Type Float = type("float"); + public static final Type Double = type("double"); } public static final class Java { @@ -52,59 +60,65 @@ public static final class Java { public static final class Io { public static final String PACKAGE = Java.PACKAGE + ".io"; - public static final Type IOException = Type.builder().withPackage(PACKAGE).withName("IOException").build(); + public static final Type IOException = type(PACKAGE, "IOException"); } public static final class Lang { public static final String PACKAGE = Java.PACKAGE + ".lang"; - public static final Type String = Type.builder().withPackage(PACKAGE).withName("String").build(); - public static final Type Character = Type.builder().withPackage(PACKAGE).withName("Character").build(); - public static final Type Boolean = Type.builder().withPackage(PACKAGE).withName("Boolean").build(); - public static final Type Byte = Type.builder().withPackage(PACKAGE).withName("Byte").build(); - public static final Type Short = Type.builder().withPackage(PACKAGE).withName("Short").build(); - public static final Type Integer = Type.builder().withPackage(PACKAGE).withName("Integer").build(); - public static final Type Long = Type.builder().withPackage(PACKAGE).withName("Long").build(); - public static final Type Float = Type.builder().withPackage(PACKAGE).withName("Float").build(); - public static final Type Double = Type.builder().withPackage(PACKAGE).withName("Double").build(); - public static final Type Object = Type.builder().withPackage(PACKAGE).withName("Object").build(); - public static final Type Number = Type.builder().withPackage(PACKAGE).withName("Number").build(); + public static final Type String = type(PACKAGE, "String"); + public static final Type Character = type(PACKAGE, "Character"); + public static final Type Boolean = type(PACKAGE, "Boolean"); + public static final Type Byte = type(PACKAGE, "Byte"); + public static final Type Short = type(PACKAGE, "Short"); + public static final Type Integer = type(PACKAGE, "Integer"); + public static final Type Long = type(PACKAGE, "Long"); + public static final Type Float = type(PACKAGE, "Float"); + public static final Type Double = type(PACKAGE, "Double"); + public static final Type Object = type(PACKAGE, "Object"); + public static final Type Number = type(PACKAGE, "Number"); } public static final class Util { public static final String PACKAGE = Java.PACKAGE + ".util"; - public static final Type Objects = Type.builder().withPackage(PACKAGE).withName("Objects").build(); - public static final Type HashMap = Type.builder().withPackage(PACKAGE).withName("HashMap").build(); + public static final Type Objects = type(PACKAGE, "Objects"); + public static final Type HashMap = type(PACKAGE, "HashMap"); public static Type Map(Type keyType, Type valueType) { - return Map.toBuilder().withTypeParameters(keyType, valueType).build(); + return Map.withTypeParameters(keyType, valueType); } - public static final Type Map = Type.builder().withPackage(PACKAGE).withName("Map").build(); + public static final Type Map = type(PACKAGE, "Map"); public static Type MapEntry(Type keyType, Type valueType) { - return Type.builder().withPackage(PACKAGE).withName("Map.Entry").withTypeParameters(keyType, valueType).build(); + return MapEntry.withTypeParameters(keyType, valueType); } + public static final Type MapEntry = type(PACKAGE, "Map.Entry"); + public static Type List(Type valueType) { - return Type.builder().withPackage(PACKAGE).withName("List").withTypeParameters(valueType).build(); + return List.withTypeParameters(valueType); } + public static final Type List = type(PACKAGE, "List"); + public static final class Concurrent { public static final String PACKAGE = Util.PACKAGE + ".concurrent"; - public static final Type CompletableFuture = Type.builder().withPackage(PACKAGE).withName("CompletableFuture").build(); + public static final Type CompletableFuture = type(PACKAGE, "CompletableFuture"); } public static final class Function { public static final String PACKAGE = Util.PACKAGE + ".function"; public static Type Function(Type argType, Type returnType) { - return Type.builder().withPackage(PACKAGE).withName("Function").withTypeParameters(argType, returnType).build(); + return Function.withTypeParameters(argType, returnType); } + + public static final Type Function = type(PACKAGE, "Function"); } public static final class Stream { public static final String PACKAGE = Util.PACKAGE + ".stream"; - public static final Type Collectors = Type.builder().withPackage(PACKAGE).withName("Collectors").build(); + public static final Type Collectors = type(PACKAGE, "Collectors"); } } } @@ -114,9 +128,9 @@ public static final class Javax { public static final class Annotation { public static final String PACKAGE = Javax.PACKAGE + ".annotation"; - public static final Type Generated = Type.builder().withPackage(PACKAGE).withName("Generated").build(); - public static final Type Nonnull = Type.builder().withPackage(PACKAGE).withName("Nonnull").build(); - public static final Type Nullable = Type.builder().withPackage(PACKAGE).withName("Nullable").build(); + public static final Type Generated = type(PACKAGE, "Generated"); + public static final Type Nonnull = type(PACKAGE, "Nonnull"); + public static final Type Nullable = type(PACKAGE, "Nullable"); } } @@ -127,23 +141,21 @@ public static Type ApiClient(Type transport, Type client) { return ApiClient.withTypeParameters(transport, client); } - public static final Type ApiClient = Type.builder().withPackage(PACKAGE).withName("ApiClient").build(); + public static final Type ApiClient = type(PACKAGE, "ApiClient"); public static final class Json { public static final String PACKAGE = Client.PACKAGE + ".json"; - public static final Type JsonData = Type.builder().withPackage(PACKAGE).withName("JsonData").build(); - public static final Type JsonpDeserializable = Type.builder().withPackage(PACKAGE).withName("JsonpDeserializable").build(); - public static final Type JsonpDeserializer = Type.builder().withPackage(PACKAGE).withName("JsonpDeserializer").build(); - public static final Type JsonEnum = Type.builder().withPackage(PACKAGE).withName("JsonEnum").build(); - public static final Type JsonpMapper = Type.builder().withPackage(PACKAGE).withName("JsonpMapper").build(); - public static final Type JsonpSerializable = Type.builder().withPackage(PACKAGE).withName("JsonpSerializable").build(); - public static final Type ObjectBuilderDeserializer = Type.builder() - .withPackage(PACKAGE) - .withName("ObjectBuilderDeserializer") - .build(); - public static final Type ObjectDeserializer = Type.builder().withPackage(PACKAGE).withName("ObjectDeserializer").build(); - public static final Type PlainJsonSerializable = Type.builder().withPackage(PACKAGE).withName("PlainJsonSerializable").build(); - public static final Type UnionDeserializer = Type.builder().withPackage(PACKAGE).withName("UnionDeserializer").build(); + public static final Type JsonData = type(PACKAGE, "JsonData"); + public static final Type JsonpDeserializable = type(PACKAGE, "JsonpDeserializable"); + public static final Type JsonpDeserializer = type(PACKAGE, "JsonpDeserializer"); + public static final Type JsonEnum = type(PACKAGE, "JsonEnum"); + public static final Type JsonpMapper = type(PACKAGE, "JsonpMapper"); + public static final Type JsonpSerializable = type(PACKAGE, "JsonpSerializable"); + public static final Type ObjectBuilderDeserializer = type(PACKAGE, "ObjectBuilderDeserializer"); + public static final Type ObjectDeserializer = type(PACKAGE, "ObjectDeserializer"); + public static final Type PlainDeserializable = type(PACKAGE, "PlainDeserializable"); + public static final Type PlainJsonSerializable = type(PACKAGE, "PlainJsonSerializable"); + public static final Type UnionDeserializer = type(PACKAGE, "UnionDeserializer"); } public static final class OpenSearch { @@ -151,54 +163,57 @@ public static final class OpenSearch { public static final class _Types { public static final String PACKAGE = OpenSearch.PACKAGE + "._types"; - public static final Type ErrorResponse = Type.builder().withPackage(PACKAGE).withName("ErrorResponse").build(); - public static final Type OpenSearchException = Type.builder().withPackage(PACKAGE).withName("OpenSearchException").build(); - public static final Type RequestBase = Type.builder().withPackage(PACKAGE).withName("RequestBase").build(); - public static final Type Time = Type.builder().withPackage(PACKAGE).withName("Time").build(); + public static final Type ErrorResponse = type(PACKAGE, "ErrorResponse"); + public static final Type OpenSearchException = type(PACKAGE, "OpenSearchException"); + public static final Type RequestBase = type(PACKAGE, "RequestBase"); + public static final Type Time = type(PACKAGE, "Time"); } } public static final class Transport { public static final String PACKAGE = Client.PACKAGE + ".transport"; - public static final Type Endpoint = Type.builder().withPackage(PACKAGE).withName("Endpoint").build(); + public static final Type Endpoint = type(PACKAGE, "Endpoint"); public static Type JsonEndpoint(Type requestType, Type responseType, Type errorType) { return JsonEndpoint.withTypeParameters(requestType, responseType, errorType); } - public static final Type JsonEndpoint = Type.builder().withPackage(PACKAGE).withName("JsonEndpoint").build(); - public static final Type OpenSearchTransport = Type.builder().withPackage(PACKAGE).withName("OpenSearchTransport").build(); - public static final Type TransportOptions = Type.builder().withPackage(PACKAGE).withName("TransportOptions").build(); + public static final Type JsonEndpoint = type(PACKAGE, "JsonEndpoint"); + public static final Type OpenSearchTransport = type(PACKAGE, "OpenSearchTransport"); + public static final Type TransportOptions = type(PACKAGE, "TransportOptions"); public static final class Endpoints { public static final String PACKAGE = Transport.PACKAGE + ".endpoints"; + public static final Type BooleanEndpoint = type(PACKAGE, "BooleanEndpoint"); + public static final Type BooleanResponse = type(PACKAGE, "BooleanResponse"); + public static Type DictionaryResponse(Type keyType, Type valueType) { return DictionaryResponse.withTypeParameters(keyType, valueType); } - public static final Type DictionaryResponse = Type.builder().withPackage(PACKAGE).withName("DictionaryResponse").build(); - public static final Type SimpleEndpoint = Type.builder().withPackage(PACKAGE).withName("SimpleEndpoint").build(); + public static final Type DictionaryResponse = type(PACKAGE, "DictionaryResponse"); + public static final Type SimpleEndpoint = type(PACKAGE, "SimpleEndpoint"); } } public static final class Util { public static final String PACKAGE = Client.PACKAGE + ".util"; - public static final Type ApiTypeHelper = Type.builder().withPackage(PACKAGE).withName("ApiTypeHelper").build(); + public static final Type ApiTypeHelper = type(PACKAGE, "ApiTypeHelper"); public static Type ObjectBuilder(Type type) { return ObjectBuilder.withTypeParameters(type); } - public static final Type ObjectBuilder = Type.builder().withPackage(PACKAGE).withName("ObjectBuilder").build(); - public static final Type ObjectBuilderBase = Type.builder().withPackage(PACKAGE).withName("ObjectBuilderBase").build(); + public static final Type ObjectBuilder = type(PACKAGE, "ObjectBuilder"); + public static final Type ObjectBuilderBase = type(PACKAGE, "ObjectBuilderBase"); public static Type TaggedUnion(Type tagType, Type baseType) { return TaggedUnion.withTypeParameters(tagType, baseType); } - public static final Type TaggedUnion = Type.builder().withPackage(PACKAGE).withName("TaggedUnion").build(); - public static final Type TaggedUnionUtils = Type.builder().withPackage(PACKAGE).withName("TaggedUnionUtils").build(); + public static final Type TaggedUnion = type(PACKAGE, "TaggedUnion"); + public static final Type TaggedUnionUtils = type(PACKAGE, "TaggedUnionUtils"); } } @@ -210,7 +225,7 @@ public static final class Json { public static final class Stream { public static final String PACKAGE = Json.PACKAGE + ".stream"; - public static final Type JsonGenerator = Type.builder().withPackage(PACKAGE).withName("JsonGenerator").build(); + public static final Type JsonGenerator = type(PACKAGE, "JsonGenerator"); } } } diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/Overrides.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/Overrides.java index 5df7938c9e..0e48cda5eb 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/Overrides.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/Overrides.java @@ -12,7 +12,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.function.Function; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -25,20 +24,16 @@ public class Overrides { private static final JsonPointer SCHEMAS = JsonPointer.of("components", "schemas"); public static final Overrides OVERRIDES = builder().withSchemas( - s -> s.with(SCHEMAS.append("_common.query_dsl:QueryContainer"), so -> so.withClassName("Query")) - .with(SCHEMAS.append("indices._common:IndexSettings"), so -> so.withAliasProvider((k) -> { - switch (k) { - case "index": - case "indexing": - case "mapping": - case "search": - case "settings": - case "top_metrics_max_size": - return null; - default: - return Set.of("index." + k); - } - })) + s -> s + // TODO: Remove this to generate property mapping types + .with(SCHEMAS.append("_common.mapping:Property"), so -> so.withShouldGenerate(ShouldGenerate.Never)) + // TODO: Remove this to generate query types + .with( + SCHEMAS.append("_common.query_dsl:QueryContainer"), + so -> so.withMappedType(t -> t.withPackage(Types.Client.OpenSearch._Types.PACKAGE + ".query_dsl").withName("Query")) + ) + // TODO: Remove this to generate index settings types + .with(SCHEMAS.append("indices._common:IndexSettings"), so -> so.withShouldGenerate(ShouldGenerate.Never)) .with( SCHEMAS.append("_common:ShardStatistics"), b -> b.withProperties( diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/SchemaOverride.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/SchemaOverride.java index a72db9173e..a1ee81b882 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/SchemaOverride.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/SchemaOverride.java @@ -24,19 +24,22 @@ import org.opensearch.client.codegen.utils.builder.ObjectMapBuilderBase; public final class SchemaOverride { - private final boolean skipGeneration; + private final ShouldGenerate shouldGenerate; @Nonnull private final Map properties; @Nullable private final Function> aliasProvider; @Nullable private final String className; + @Nullable + private final Type mappedType; private SchemaOverride(Builder builder) { - this.skipGeneration = builder.skipGeneration; + this.shouldGenerate = builder.shouldGenerate; this.properties = builder.properties != null ? Collections.unmodifiableMap(builder.properties) : Collections.emptyMap(); this.aliasProvider = builder.aliasProvider; this.className = builder.className; + this.mappedType = builder.mappedType; } @Nonnull @@ -63,8 +66,8 @@ public PropertyOverride getProperty(@Nonnull String key) { return PropertyOverride.builder().withMappedType(mappedType).withAliases(aliases).build(); } - public boolean shouldSkipGeneration() { - return skipGeneration; + public ShouldGenerate shouldGenerate() { + return shouldGenerate; } @Nonnull @@ -72,6 +75,11 @@ public Optional getClassName() { return Optional.ofNullable(className); } + @Nonnull + public Optional getMappedType() { + return Optional.ofNullable(mappedType); + } + @Nonnull public static Builder builder() { return new Builder(); @@ -83,13 +91,16 @@ public static MapBuilder mapBuilder() { } public static final class Builder extends ObjectBuilderBase { - private boolean skipGeneration; + @Nonnull + private ShouldGenerate shouldGenerate = ShouldGenerate.IfNeeded; @Nullable private Map properties; @Nullable private Function> aliasProvider; @Nullable private String className; + @Nullable + private Type mappedType; private Builder() {} @@ -100,8 +111,8 @@ protected SchemaOverride construct() { } @Nonnull - public Builder withSkipGeneration(boolean skipGeneration) { - this.skipGeneration = skipGeneration; + public Builder withShouldGenerate(ShouldGenerate shouldGenerate) { + this.shouldGenerate = Objects.requireNonNull(shouldGenerate, "shouldGenerate must not be null"); return this; } @@ -122,6 +133,18 @@ public Builder withClassName(@Nullable String className) { this.className = className; return this; } + + @Nonnull + public Builder withMappedType(@Nullable Type mappedType) { + this.mappedType = mappedType; + return this; + } + + @Nonnull + public Builder withMappedType(@Nonnull Function> fn) { + this.mappedType = Objects.requireNonNull(fn, "fn must not be null").apply(Type.builder()).build(); + return this; + } } public static final class MapBuilder extends ObjectMapBuilderBase { diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/ShouldGenerate.java b/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/ShouldGenerate.java new file mode 100644 index 0000000000..068511302c --- /dev/null +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/model/overrides/ShouldGenerate.java @@ -0,0 +1,15 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.client.codegen.model.overrides; + +public enum ShouldGenerate { + Always, + IfNeeded, + Never +} diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/openapi/OpenApiSchema.java b/java-codegen/src/main/java/org/opensearch/client/codegen/openapi/OpenApiSchema.java index 304b3e4055..79ca01555f 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/openapi/OpenApiSchema.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/openapi/OpenApiSchema.java @@ -68,6 +68,8 @@ public class OpenApiSchema extends OpenApiRefElement { @Nullable private final OpenApiDiscriminator discriminator; @Nullable + private final Object constValue; + @Nullable private final Semver versionRemoved; @Nullable private final Semver versionDeprecated; @@ -90,6 +92,7 @@ private OpenApiSchema(@Nonnull Builder builder) { title = builder.title; pattern = builder.pattern; discriminator = builder.discriminator; + constValue = builder.constValue; versionRemoved = builder.versionRemoved; versionDeprecated = builder.versionDeprecated; } @@ -144,6 +147,8 @@ protected OpenApiSchema(@Nullable OpenApiElement parent, @Nonnull JsonPointer discriminator = child("discriminator", schema.getDiscriminator(), OpenApiDiscriminator::new); + constValue = schema.getConst(); + var extensions = schema.getExtensions(); versionRemoved = Maps.tryGet(extensions, "x-version-removed").map(v -> Versions.coerce((String) v)).orElse(null); @@ -204,10 +209,6 @@ public boolean isString() { return is(OpenApiSchemaType.String); } - public boolean isStringEnum() { - return isString() && hasEnums(); - } - public boolean hasAllOf() { return allOf != null && !allOf.isEmpty(); } @@ -283,6 +284,15 @@ public Optional getDiscriminator() { return Optional.ofNullable(discriminator); } + public boolean hasConst() { + return constValue != null; + } + + @Nonnull + public Optional getConst() { + return Optional.ofNullable(constValue); + } + @Nonnull public Optional getVersionRemoved() { return Optional.ofNullable(versionRemoved); @@ -374,6 +384,8 @@ public static class Builder extends ObjectBuilderBase { @Nullable private OpenApiDiscriminator discriminator; @Nullable + private Object constValue; + @Nullable private Semver versionRemoved; @Nullable private Semver versionDeprecated; diff --git a/java-codegen/src/main/java/org/opensearch/client/codegen/utils/Markdown.java b/java-codegen/src/main/java/org/opensearch/client/codegen/utils/Markdown.java index 4f005f2a87..c8476f465b 100644 --- a/java-codegen/src/main/java/org/opensearch/client/codegen/utils/Markdown.java +++ b/java-codegen/src/main/java/org/opensearch/client/codegen/utils/Markdown.java @@ -8,6 +8,7 @@ package org.opensearch.client.codegen.utils; +import javax.annotation.Nonnull; import org.commonmark.parser.Parser; import org.commonmark.renderer.html.HtmlRenderer; @@ -17,7 +18,8 @@ private Markdown() {} private static final Parser PARSER = Parser.builder().build(); private static final HtmlRenderer RENDERER = HtmlRenderer.builder().omitSingleParagraphP(true).build(); - public static String toJavaDocHtml(String markdown) { + @Nonnull + public static String toJavaDocHtml(@Nonnull String markdown) { return RENDERER.render(PARSER.parse(markdown)).strip(); } } diff --git a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/EnumShape.mustache b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/EnumShape.mustache index 719c40ba20..543bfdb110 100644 --- a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/EnumShape.mustache +++ b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/EnumShape.mustache @@ -3,6 +3,11 @@ {{^-first}} {{/-first}} +{{#description}} + /** + * {{.}} + */ +{{/description}} {{#deprecated}} @Deprecated {{/deprecated}} diff --git a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Builder.mustache b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Builder.mustache index f9a8abeeaa..f715bd75d5 100644 --- a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Builder.mustache +++ b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Builder.mustache @@ -4,7 +4,7 @@ */ {{#extendsOtherShape}} public static class Builder extends {{extendsType}}.AbstractBuilder - implements {{TYPES.Client.Util.ObjectBuilder}}<{{className}}> { + implements {{TYPES.Client.Util.ObjectBuilder}}<{{className}}> {{#shouldImplementPlainDeserializable}}, {{TYPES.Client.Json.PlainDeserializable}}{{/shouldImplementPlainDeserializable}} { {{>ObjectShape/Builder/Fields}} {{>ObjectShape/Builder/SelfImpl}} @@ -15,7 +15,8 @@ {{^extendsOtherShape}} {{#extendedByOtherShape}} public static class Builder extends {{type}}.AbstractBuilder - implements {{TYPES.Client.Util.ObjectBuilder}}<{{className}}> { + implements {{TYPES.Client.Util.ObjectBuilder}}<{{className}}>{{#shouldImplementPlainDeserializable}}, {{TYPES.Client.Json.PlainDeserializable}}{{/shouldImplementPlainDeserializable}} + { {{>ObjectShape/Builder/SelfImpl}} {{>ObjectShape/Builder/BuildImpl}} @@ -23,7 +24,12 @@ {{/extendedByOtherShape}} {{^extendedByOtherShape}} public static class Builder extends {{TYPES.Client.Util.ObjectBuilderBase}} - implements {{TYPES.Client.Util.ObjectBuilder}}<{{className}}> { + implements {{TYPES.Client.Util.ObjectBuilder}}<{{className}}>{{#shouldImplementPlainDeserializable}}, {{TYPES.Client.Json.PlainDeserializable}}{{/shouldImplementPlainDeserializable}} + { + {{#shouldImplementPlainDeserializable}} + {{>ObjectShape/Builder/SelfImpl}} + + {{/shouldImplementPlainDeserializable}} {{>ObjectShape/Builder/Fields}} {{>ObjectShape/Builder/BuildImpl}} diff --git a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Builder/SelfImpl.mustache b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Builder/SelfImpl.mustache index 7d897fe252..ce3c4f49ed 100644 --- a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Builder/SelfImpl.mustache +++ b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Builder/SelfImpl.mustache @@ -1,4 +1,4 @@ @Override -protected Builder self() { +{{#shouldImplementPlainDeserializable}}public{{/shouldImplementPlainDeserializable}}{{^shouldImplementPlainDeserializable}}protected{{/shouldImplementPlainDeserializable}} Builder self() { return this; } \ No newline at end of file diff --git a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Deserialize.mustache b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Deserialize.mustache index ddb9adaddc..4d37bb6a2f 100644 --- a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Deserialize.mustache +++ b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/ObjectShape/Deserialize.mustache @@ -29,4 +29,8 @@ op.ignore({{#quoted}}{{key}}{{/quoted}}); {{/distinctDiscriminatorFieldValues}} + {{#shortcutProperty}} + + op.shortcutProperty({{#quoted}}{{.}}{{/quoted}}); + {{/shortcutProperty}} } \ No newline at end of file diff --git a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/RequestShape.mustache b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/RequestShape.mustache index f73f6dd4a2..f73e867c2f 100644 --- a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/RequestShape.mustache +++ b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/RequestShape.mustache @@ -35,7 +35,7 @@ /** * Endpoint "{@code {{operationGroup}}}". */ - public static final {{TYPES.Client.Transport.Endpoint}}<{{className}}, {{responseType}}, {{TYPES.Client.OpenSearch._Types.ErrorResponse}}> _ENDPOINT = new {{TYPES.Client.Transport.Endpoints.SimpleEndpoint}}<>( + public static final {{TYPES.Client.Transport.Endpoint}}<{{className}}, {{responseType}}, {{TYPES.Client.OpenSearch._Types.ErrorResponse}}> _ENDPOINT = new {{#isBooleanRequest}}{{TYPES.Client.Transport.Endpoints.BooleanEndpoint}}{{/isBooleanRequest}}{{^isBooleanRequest}}{{TYPES.Client.Transport.Endpoints.SimpleEndpoint}}{{/isBooleanRequest}}<>( // Request method request -> {{#quoted}}{{httpMethod}}{{/quoted}}, // Request path @@ -92,9 +92,12 @@ {{^hasQueryParams}} {{TYPES.Client.Transport.Endpoints.SimpleEndpoint}}.emptyMap(), {{/hasQueryParams}} - {{TYPES.Client.Transport.Endpoints.SimpleEndpoint}}.emptyMap(), + {{TYPES.Client.Transport.Endpoints.SimpleEndpoint}}.emptyMap() + {{^isBooleanRequest}} + , {{hasRequestBody}}, {{responseType}}._DESERIALIZER + {{/isBooleanRequest}} ); {{>ObjectShape/HashCode}} diff --git a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/TaggedUnionShape.mustache b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/TaggedUnionShape.mustache index fd51d4d80a..21c3a05a47 100644 --- a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/TaggedUnionShape.mustache +++ b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/TaggedUnionShape.mustache @@ -146,7 +146,7 @@ {{/discriminated}} {{^discriminated}} private static {{TYPES.Client.Json.JsonpDeserializer}}<{{className}}> build{{className}}Deserializer() { - return new {{TYPES.Client.Json.UnionDeserializer.builderType}}<{{className}}, Kind, Object>({{className}}::new, {{canStringify}}) + return new {{TYPES.Client.Json.UnionDeserializer.builderType}}<{{className}}, Kind, Object>({{className}}::new, {{hasAmbiguities}}) {{#variants}}.addMember(Kind.{{#pascalCase}}{{name}}{{/pascalCase}}, {{#type}}{{>Type/deserializer}}{{/type}}){{/variants}} .build(); } diff --git a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/Type/directSerializer.mustache b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/Type/directSerializer.mustache index f0768a1e03..1f4eec4047 100644 --- a/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/Type/directSerializer.mustache +++ b/java-codegen/src/main/resources/org/opensearch/client/codegen/templates/Type/directSerializer.mustache @@ -15,7 +15,16 @@ {{/type.isMap}} {{#type.isList}} for ({{type.listValueType}} item{{depth}} : {{value}}) { - {{#type.listValueType.serializer}}item{{depth}}{{/type.listValueType.serializer}} + {{#type.listValueType.isMap}} + generator.writeStartObject(); + if (item{{depth}} != null) { + {{#type.listValueType.directSerializer}}item{{depth}}{{/type.listValueType.directSerializer}} + } + generator.writeEnd(); + {{/type.listValueType.isMap}} + {{^type.listValueType.isMap}} + {{#type.listValueType.serializer}}item{{depth}}{{/type.listValueType.serializer}} + {{/type.listValueType.isMap}} } {{/type.isList}} {{^type.isListOrMap}}