From 0815fc28f6ca3f9bac6a85047f64573bd9a7febc Mon Sep 17 00:00:00 2001 From: Justin Black Date: Tue, 16 Jan 2024 11:00:29 -0800 Subject: [PATCH 1/6] ENables propertynames test in java 310 client --- .../generators/JavaClientGenerator.java | 3 ++ .../3_1_0_unit_test_spec_nopaths.yaml | 43 +++++++++++++++++++ .../3_1/unit_test_spec/spec_writer.py | 1 - 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java b/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java index 91983f9a0a3..f64a52163e9 100644 --- a/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java +++ b/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java @@ -1145,6 +1145,9 @@ public Set getImports(String sourceJsonPath, CodegenSchema schema, Featu if (schema.unevaluatedProperties != null) { imports.addAll(getImports(sourceJsonPath, schema.unevaluatedProperties, featureSet)); } + if (schema.propertyNames != null) { + imports.addAll(getImports(sourceJsonPath, schema.propertyNames, featureSet)); + } if (schema.prefixItems != null && !schema.prefixItems.isEmpty()) { for (CodegenSchema cs: schema.prefixItems) { imports.addAll(getImports(sourceJsonPath, cs, featureSet)); diff --git a/src/test/resources/3_1/unit_test_spec/3_1_0_unit_test_spec_nopaths.yaml b/src/test/resources/3_1/unit_test_spec/3_1_0_unit_test_spec_nopaths.yaml index 1d846eb8a33..6b0eb400862 100644 --- a/src/test/resources/3_1/unit_test_spec/3_1_0_unit_test_spec_nopaths.yaml +++ b/src/test/resources/3_1/unit_test_spec/3_1_0_unit_test_spec_nopaths.yaml @@ -456,6 +456,10 @@ components: type: string constructor: type: number + PropertynamesValidation: + $schema: https://json-schema.org/draft/2020-12/schema + propertyNames: + maxLength: 3 PropertyNamedRefThatIsNotAReference: $schema: https://json-schema.org/draft/2020-12/schema properties: @@ -2605,6 +2609,45 @@ components: constructor: 37 valid: true comment: null + PropertynamesValidation: + AllPropertyNamesValid: + description: all property names valid + data: + f: {} + foo: {} + valid: true + comment: null + SomePropertyNamesInvalid: + description: some property names invalid + data: + foo: {} + foobar: {} + valid: false + comment: null + ObjectWithoutPropertiesIsValid: + description: object without properties is valid + data: {} + valid: true + comment: null + IgnoresArrays: + description: ignores arrays + data: + - 1 + - 2 + - 3 + - 4 + valid: true + comment: null + IgnoresStrings: + description: ignores strings + data: foobar + valid: true + comment: null + IgnoresOtherNonObjects: + description: ignores other non-objects + data: 12 + valid: true + comment: null PropertyNamedRefThatIsNotAReference: PropertyNamedRefValid: description: property named $ref valid diff --git a/src/test/resources/3_1/unit_test_spec/spec_writer.py b/src/test/resources/3_1/unit_test_spec/spec_writer.py index 8c97b6357f1..26f73b27486 100644 --- a/src/test/resources/3_1/unit_test_spec/spec_writer.py +++ b/src/test/resources/3_1/unit_test_spec/spec_writer.py @@ -724,7 +724,6 @@ def write_openapi_spec(): 'NonAsciiPatternWithAdditionalproperties', 'PatternpropertiesValidatesPropertiesMatchingARegex', 'PropertiesPatternpropertiesAdditionalpropertiesInteraction', - 'PropertynamesValidation', 'RegexesAreNotAnchoredByDefaultAndAreCaseSensitive', 'SingleDependency', 'UnevaluateditemsAsSchema', From 3fea548b70393c4e019445fbcc7bbf6f16d9fac3 Mon Sep 17 00:00:00 2001 From: Justin Black Date: Tue, 16 Jan 2024 11:05:03 -0800 Subject: [PATCH 2/6] 310 java regen --- .../java/.openapi-generator/FILES | 3 + samples/client/3_1_0_unit_test/java/README.md | 1 + .../schemas/PropertynamesValidation.md | 76 +++++ .../schemas/PropertynamesValidation.java | 283 ++++++++++++++++++ .../schemas/PropertynamesValidationTest.java | 112 +++++++ 5 files changed, 475 insertions(+) create mode 100644 samples/client/3_1_0_unit_test/java/docs/components/schemas/PropertynamesValidation.md create mode 100644 samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidation.java create mode 100644 samples/client/3_1_0_unit_test/java/src/test/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidationTest.java diff --git a/samples/client/3_1_0_unit_test/java/.openapi-generator/FILES b/samples/client/3_1_0_unit_test/java/.openapi-generator/FILES index 12d9180bf19..bb7aa2c4237 100644 --- a/samples/client/3_1_0_unit_test/java/.openapi-generator/FILES +++ b/samples/client/3_1_0_unit_test/java/.openapi-generator/FILES @@ -88,6 +88,7 @@ docs/components/schemas/PropertiesWhoseNamesAreJavascriptObjectPropertyNames.md docs/components/schemas/PropertiesWithEscapedCharacters.md docs/components/schemas/PropertiesWithNullValuedInstanceProperties.md docs/components/schemas/PropertyNamedRefThatIsNotAReference.md +docs/components/schemas/PropertynamesValidation.md docs/components/schemas/RegexFormat.md docs/components/schemas/RelativeJsonPointerFormat.md docs/components/schemas/RequiredDefaultValidation.md @@ -202,6 +203,7 @@ src/main/java/org/openapijsonschematools/client/components/schemas/PropertiesWho src/main/java/org/openapijsonschematools/client/components/schemas/PropertiesWithEscapedCharacters.java src/main/java/org/openapijsonschematools/client/components/schemas/PropertiesWithNullValuedInstanceProperties.java src/main/java/org/openapijsonschematools/client/components/schemas/PropertyNamedRefThatIsNotAReference.java +src/main/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidation.java src/main/java/org/openapijsonschematools/client/components/schemas/RegexFormat.java src/main/java/org/openapijsonschematools/client/components/schemas/RelativeJsonPointerFormat.java src/main/java/org/openapijsonschematools/client/components/schemas/RequiredDefaultValidation.java @@ -319,6 +321,7 @@ src/main/java/org/openapijsonschematools/client/schemas/validation/ValidationMet src/main/java/org/openapijsonschematools/client/servers/Server0.java src/main/java/org/openapijsonschematools/client/servers/ServerWithVariables.java src/main/java/org/openapijsonschematools/client/servers/ServerWithoutVariables.java +src/test/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidationTest.java src/test/java/org/openapijsonschematools/client/configurations/JsonSchemaKeywordFlagsTest.java src/test/java/org/openapijsonschematools/client/schemas/AnyTypeSchemaTest.java src/test/java/org/openapijsonschematools/client/schemas/ArrayTypeSchemaTest.java diff --git a/samples/client/3_1_0_unit_test/java/README.md b/samples/client/3_1_0_unit_test/java/README.md index 3c7156969eb..6bcb419a53a 100644 --- a/samples/client/3_1_0_unit_test/java/README.md +++ b/samples/client/3_1_0_unit_test/java/README.md @@ -246,6 +246,7 @@ allowed input and output types. | [PropertiesWithEscapedCharacters.PropertiesWithEscapedCharacters1](docs/components/schemas/PropertiesWithEscapedCharacters.md#propertieswithescapedcharacters1) | | | [PropertiesWithNullValuedInstanceProperties.PropertiesWithNullValuedInstanceProperties1](docs/components/schemas/PropertiesWithNullValuedInstanceProperties.md#propertieswithnullvaluedinstanceproperties1) | | | [PropertyNamedRefThatIsNotAReference.PropertyNamedRefThatIsNotAReference1](docs/components/schemas/PropertyNamedRefThatIsNotAReference.md#propertynamedrefthatisnotareference1) | | +| [PropertynamesValidation.PropertynamesValidation1](docs/components/schemas/PropertynamesValidation.md#propertynamesvalidation1) | | | [RegexFormat.RegexFormat1](docs/components/schemas/RegexFormat.md#regexformat1) | | | [RelativeJsonPointerFormat.RelativeJsonPointerFormat1](docs/components/schemas/RelativeJsonPointerFormat.md#relativejsonpointerformat1) | | | [RequiredDefaultValidation.RequiredDefaultValidation1](docs/components/schemas/RequiredDefaultValidation.md#requireddefaultvalidation1) | | diff --git a/samples/client/3_1_0_unit_test/java/docs/components/schemas/PropertynamesValidation.md b/samples/client/3_1_0_unit_test/java/docs/components/schemas/PropertynamesValidation.md new file mode 100644 index 00000000000..80ef569b2e5 --- /dev/null +++ b/samples/client/3_1_0_unit_test/java/docs/components/schemas/PropertynamesValidation.md @@ -0,0 +1,76 @@ +# PropertynamesValidation +org.openapijsonschematools.client.components.schemas.PropertynamesValidation.java +public class PropertynamesValidation + +A class that contains necessary nested +- schema classes (which validate payloads), extends JsonSchema + +## Nested Class Summary +| Modifier and Type | Class and Description | +| ----------------- | ---------------------- | +| static class | [PropertynamesValidation.PropertynamesValidation1](#propertynamesvalidation1)
schema class | +| static class | [PropertynamesValidation.PropertyNames](#propertynames)
schema class | + +## PropertynamesValidation1 +public static class PropertynamesValidation1
+extends JsonSchema + +A schema class that validates payloads + +### Field Summary +| Modifier and Type | Field and Description | +| ----------------- | ---------------------- | + +### Method Summary +| Modifier and Type | Method and Description | +| ----------------- | ---------------------- | +| String | validate(String arg, SchemaConfiguration configuration) | +| Void | validate(Void arg, SchemaConfiguration configuration) | +| int | validate(int arg, SchemaConfiguration configuration) | +| long | validate(long arg, SchemaConfiguration configuration) | +| float | validate(float arg, SchemaConfiguration configuration) | +| double | validate(double arg, SchemaConfiguration configuration) | +| boolean | validate(boolean arg, SchemaConfiguration configuration) | +| FrozenMap | validate(Map<?, ?> arg, SchemaConfiguration configuration) | +| FrozenList<@Nullable Object> | validate(List arg, SchemaConfiguration configuration) | +| @Nullable Object | validate(@Nullable Object arg, SchemaConfiguration configuration) | +## PropertyNames +public static class PropertyNames
+extends JsonSchema + +A schema class that validates payloads + +### Code Sample +``` +import org.openapijsonschematools.client.configurations.JsonSchemaKeywordFlags; +import org.openapijsonschematools.client.configurations.SchemaConfiguration; +import org.openapijsonschematools.client.exceptions.ValidationException; +import org.openapijsonschematools.client.schemas.validation.MapUtils; +import org.openapijsonschematools.client.schemas.validation.FrozenList; +import org.openapijsonschematools.client.schemas.validation.FrozenMap; + +import java.util.Arrays; +import java.util.List; +import java.util.AbstractMap; + +static final SchemaConfiguration configuration = new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone()); + +// String validation +String validatedPayload = PropertynamesValidation.PropertyNames.validate( + "a", + configuration +); +``` + +### Field Summary +| Modifier and Type | Field and Description | +| ----------------- | ---------------------- | +| Set> | type = Set.of(
    String.class
)
| +| Integer | maxLength = 3 | + +### Method Summary +| Modifier and Type | Method and Description | +| ----------------- | ---------------------- | +| String | validate(String arg, SchemaConfiguration configuration) | +| @Nullable Object | validate(@Nullable Object arg, SchemaConfiguration configuration) | +[[Back to top]](#top) [[Back to Component Schemas]](../../../README.md#Component-Schemas) [[Back to README]](../../../README.md) diff --git a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidation.java b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidation.java new file mode 100644 index 00000000000..b64a82533dd --- /dev/null +++ b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidation.java @@ -0,0 +1,283 @@ +package org.openapijsonschematools.client.components.schemas; +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.openapijsonschematools.client.configurations.JsonSchemaKeywordFlags; +import org.openapijsonschematools.client.configurations.SchemaConfiguration; +import org.openapijsonschematools.client.exceptions.InvalidAdditionalPropertyException; +import org.openapijsonschematools.client.exceptions.InvalidTypeException; +import org.openapijsonschematools.client.exceptions.UnsetPropertyException; +import org.openapijsonschematools.client.exceptions.ValidationException; +import org.openapijsonschematools.client.schemas.UnsetAddPropsSetter; +import org.openapijsonschematools.client.schemas.validation.BooleanSchemaValidator; +import org.openapijsonschematools.client.schemas.validation.FrozenList; +import org.openapijsonschematools.client.schemas.validation.FrozenMap; +import org.openapijsonschematools.client.schemas.validation.JsonSchema; +import org.openapijsonschematools.client.schemas.validation.JsonSchemaInfo; +import org.openapijsonschematools.client.schemas.validation.ListSchemaValidator; +import org.openapijsonschematools.client.schemas.validation.MapSchemaValidator; +import org.openapijsonschematools.client.schemas.validation.NullSchemaValidator; +import org.openapijsonschematools.client.schemas.validation.NumberSchemaValidator; +import org.openapijsonschematools.client.schemas.validation.PathToSchemasMap; +import org.openapijsonschematools.client.schemas.validation.StringSchemaValidator; +import org.openapijsonschematools.client.schemas.validation.ValidationMetadata; + +public class PropertynamesValidation { + // nest classes so all schemas and input/output classes can be public + + + public static class PropertyNames extends JsonSchema implements StringSchemaValidator { + private static @Nullable PropertyNames instance = null; + + protected PropertyNames() { + super(new JsonSchemaInfo() + .type(Set.of( + String.class + )) + .maxLength(3) + ); + } + + public static PropertyNames getInstance() { + if (instance == null) { + instance = new PropertyNames(); + } + return instance; + } + + @Override + public String validate(String arg, SchemaConfiguration configuration) throws ValidationException { + Set> pathSet = new HashSet<>(); + List pathToItem = List.of("args[0"); + String castArg = castToAllowedTypes(arg, pathToItem, pathSet); + SchemaConfiguration usedConfiguration = Objects.requireNonNullElseGet(configuration, () -> new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone())); + ValidationMetadata validationMetadata = new ValidationMetadata(pathToItem, usedConfiguration, new PathToSchemasMap(), new LinkedHashSet<>()); + getPathToSchemas(this, castArg, validationMetadata, pathSet); + return castArg; + } + + @Override + public @Nullable Object validate(@Nullable Object arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException { + if (arg instanceof String) { + return validate((String) arg, configuration); + } + throw new InvalidTypeException("Invalid input type="+getClass(arg)+". It can't be validated by this schema"); + } + @Override + public @Nullable Object getNewInstance(@Nullable Object arg, List pathToItem, PathToSchemasMap pathToSchemas) throws InvalidTypeException { + if (arg instanceof String) { + return getNewInstance((String) arg, pathToItem, pathToSchemas); + } + throw new InvalidTypeException("Invalid input type="+getClass(arg)+". It can't be instantiated by this schema"); + } + } + + public static class PropertynamesValidation1 extends JsonSchema implements NullSchemaValidator, BooleanSchemaValidator, NumberSchemaValidator, StringSchemaValidator, ListSchemaValidator>, MapSchemaValidator> { + /* + NOTE: This class is auto generated by OpenAPI JSON Schema Generator. + Ref: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator + + Do not edit the class manually. + */ + private static @Nullable PropertynamesValidation1 instance = null; + + protected PropertynamesValidation1() { + super(new JsonSchemaInfo() + ); + } + + public static PropertynamesValidation1 getInstance() { + if (instance == null) { + instance = new PropertynamesValidation1(); + } + return instance; + } + + @Override + public Void validate(Void arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException { + Set> pathSet = new HashSet<>(); + List pathToItem = List.of("args[0]"); + Void castArg = castToAllowedTypes(arg, pathToItem, pathSet); + SchemaConfiguration usedConfiguration = Objects.requireNonNullElseGet(configuration, () -> new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone())); + PathToSchemasMap validatedPathToSchemas = new PathToSchemasMap(); + ValidationMetadata validationMetadata = new ValidationMetadata(pathToItem, usedConfiguration, validatedPathToSchemas, new LinkedHashSet<>()); + getPathToSchemas(this, castArg, validationMetadata, pathSet); + return castArg; + } + + @Override + public boolean validate(boolean arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException { + Set> pathSet = new HashSet<>(); + List pathToItem = List.of("args[0]"); + boolean castArg = castToAllowedTypes(arg, pathToItem, pathSet); + SchemaConfiguration usedConfiguration = Objects.requireNonNullElseGet(configuration, () -> new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone())); + PathToSchemasMap validatedPathToSchemas = new PathToSchemasMap(); + ValidationMetadata validationMetadata = new ValidationMetadata(pathToItem, usedConfiguration, validatedPathToSchemas, new LinkedHashSet<>()); + getPathToSchemas(this, castArg, validationMetadata, pathSet); + return castArg; + } + + @Override + public Number validate(Number arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException { + Set> pathSet = new HashSet<>(); + List pathToItem = List.of("args[0]"); + Number castArg = castToAllowedTypes(arg, pathToItem, pathSet); + SchemaConfiguration usedConfiguration = Objects.requireNonNullElseGet(configuration, () -> new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone())); + PathToSchemasMap validatedPathToSchemas = new PathToSchemasMap(); + ValidationMetadata validationMetadata = new ValidationMetadata(pathToItem, usedConfiguration, validatedPathToSchemas, new LinkedHashSet<>()); + getPathToSchemas(this, castArg, validationMetadata, pathSet); + return castArg; + } + + public int validate(int arg, SchemaConfiguration configuration) { + return (int) validate((Number) arg, configuration); + } + + public long validate(long arg, SchemaConfiguration configuration) { + return (long) validate((Number) arg, configuration); + } + + public float validate(float arg, SchemaConfiguration configuration) { + return (float) validate((Number) arg, configuration); + } + + public double validate(double arg, SchemaConfiguration configuration) { + return (double) validate((Number) arg, configuration); + } + + @Override + public String validate(String arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException { + Set> pathSet = new HashSet<>(); + List pathToItem = List.of("args[0]"); + String castArg = castToAllowedTypes(arg, pathToItem, pathSet); + SchemaConfiguration usedConfiguration = Objects.requireNonNullElseGet(configuration, () -> new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone())); + PathToSchemasMap validatedPathToSchemas = new PathToSchemasMap(); + ValidationMetadata validationMetadata = new ValidationMetadata(pathToItem, usedConfiguration, validatedPathToSchemas, new LinkedHashSet<>()); + getPathToSchemas(this, castArg, validationMetadata, pathSet); + return castArg; + } + + public String validate(LocalDate arg, SchemaConfiguration configuration) throws ValidationException { + return validate(arg.toString(), configuration); + } + + public String validate(ZonedDateTime arg, SchemaConfiguration configuration) throws ValidationException { + return validate(arg.toString(), configuration); + } + + public String validate(UUID arg, SchemaConfiguration configuration) throws ValidationException { + return validate(arg.toString(), configuration); + } + + @Override + public FrozenList<@Nullable Object> getNewInstance(List arg, List pathToItem, PathToSchemasMap pathToSchemas) { + List<@Nullable Object> items = new ArrayList<>(); + int i = 0; + for (Object item: arg) { + List itemPathToItem = new ArrayList<>(pathToItem); + itemPathToItem.add(i); + LinkedHashMap schemas = pathToSchemas.get(itemPathToItem); + if (schemas == null) { + throw new InvalidTypeException("Validation result is invalid, schemas must exist for a pathToItem"); + } + JsonSchema itemSchema = schemas.entrySet().iterator().next().getKey(); + @Nullable Object itemInstance = itemSchema.getNewInstance(item, itemPathToItem, pathToSchemas); + items.add(itemInstance); + i += 1; + } + FrozenList<@Nullable Object> newInstanceItems = new FrozenList<>(items); + return newInstanceItems; + } + + public FrozenList<@Nullable Object> validate(List arg, SchemaConfiguration configuration) throws ValidationException { + Set> pathSet = new HashSet<>(); + List pathToItem = List.of("args[0"); + List castArg = castToAllowedTypes(arg, pathToItem, pathSet); + SchemaConfiguration usedConfiguration = Objects.requireNonNullElseGet(configuration, () -> new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone())); + ValidationMetadata validationMetadata = new ValidationMetadata(pathToItem, usedConfiguration, new PathToSchemasMap(), new LinkedHashSet<>()); + PathToSchemasMap pathToSchemasMap = getPathToSchemas(this, castArg, validationMetadata, pathSet); + return getNewInstance(castArg, validationMetadata.pathToItem(), pathToSchemasMap); + } + + @Override + public FrozenMap<@Nullable Object> getNewInstance(Map arg, List pathToItem, PathToSchemasMap pathToSchemas) { + LinkedHashMap properties = new LinkedHashMap<>(); + for(Map.Entry entry: arg.entrySet()) { + @Nullable Object entryKey = entry.getKey(); + if (!(entryKey instanceof String)) { + throw new InvalidTypeException("Invalid non-string key value"); + } + String propertyName = (String) entryKey; + List propertyPathToItem = new ArrayList<>(pathToItem); + propertyPathToItem.add(propertyName); + Object value = entry.getValue(); + LinkedHashMap schemas = pathToSchemas.get(propertyPathToItem); + if (schemas == null) { + throw new InvalidTypeException("Validation result is invalid, schemas must exist for a pathToItem"); + } + JsonSchema propertySchema = schemas.entrySet().iterator().next().getKey(); + @Nullable Object propertyInstance = propertySchema.getNewInstance(value, propertyPathToItem, pathToSchemas); + properties.put(propertyName, propertyInstance); + } + FrozenMap<@Nullable Object> castProperties = new FrozenMap<>(properties); + return castProperties; + } + + public FrozenMap<@Nullable Object> validate(Map arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException { + Set> pathSet = new HashSet<>(); + List pathToItem = List.of("args[0]"); + Map castArg = castToAllowedTypes(arg, pathToItem, pathSet); + SchemaConfiguration usedConfiguration = Objects.requireNonNullElseGet(configuration, () -> new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone())); + PathToSchemasMap validatedPathToSchemas = new PathToSchemasMap(); + ValidationMetadata validationMetadata = new ValidationMetadata(pathToItem, usedConfiguration, validatedPathToSchemas, new LinkedHashSet<>()); + PathToSchemasMap pathToSchemasMap = getPathToSchemas(this, castArg, validationMetadata, pathSet); + return getNewInstance(castArg, validationMetadata.pathToItem(), pathToSchemasMap); + } + + @Override + public @Nullable Object validate(@Nullable Object arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException { + if (arg == null) { + return validate((Void) null, configuration); + } else if (arg instanceof Boolean) { + boolean boolArg = (Boolean) arg; + return validate(boolArg, configuration); + } else if (arg instanceof Number) { + return validate((Number) arg, configuration); + } else if (arg instanceof String) { + return validate((String) arg, configuration); + } else if (arg instanceof List) { + return validate((List) arg, configuration); + } else if (arg instanceof Map) { + return validate((Map) arg, configuration); + } + throw new InvalidTypeException("Invalid input type="+getClass(arg)+". It can't be validated by this schema"); + } + @Override + public @Nullable Object getNewInstance(@Nullable Object arg, List pathToItem, PathToSchemasMap pathToSchemas) throws InvalidTypeException { + if (arg == null) { + return getNewInstance((Void) null, pathToItem, pathToSchemas); + } else if (arg instanceof Boolean) { + boolean boolArg = (Boolean) arg; + return getNewInstance(boolArg, pathToItem, pathToSchemas); + } else if (arg instanceof Number) { + return getNewInstance((Number) arg, pathToItem, pathToSchemas); + } else if (arg instanceof String) { + return getNewInstance((String) arg, pathToItem, pathToSchemas); + } else if (arg instanceof List) { + return getNewInstance((List) arg, pathToItem, pathToSchemas); + } else if (arg instanceof Map) { + return getNewInstance((Map) arg, pathToItem, pathToSchemas); + } + throw new InvalidTypeException("Invalid input type="+getClass(arg)+". It can't be instantiated by this schema"); + } + } +} diff --git a/samples/client/3_1_0_unit_test/java/src/test/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidationTest.java b/samples/client/3_1_0_unit_test/java/src/test/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidationTest.java new file mode 100644 index 00000000000..bad349bb35b --- /dev/null +++ b/samples/client/3_1_0_unit_test/java/src/test/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidationTest.java @@ -0,0 +1,112 @@ +package org.openapijsonschematools.client.components.schemas; + +import org.junit.Assert; +import org.junit.Test; +import org.openapijsonschematools.client.configurations.JsonSchemaKeywordFlags; +import org.openapijsonschematools.client.configurations.SchemaConfiguration; +import org.openapijsonschematools.client.exceptions.ValidationException; +import org.openapijsonschematools.client.exceptions.InvalidTypeException; +import org.openapijsonschematools.client.schemas.validation.MapUtils; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.AbstractMap; + +public class PropertynamesValidationTest { + static final SchemaConfiguration configuration = new SchemaConfiguration(JsonSchemaKeywordFlags.onlyFormat()); + + @Test + public void testSomePropertyNamesInvalidFails() { + // some property names invalid + final var schema = PropertynamesValidation.PropertynamesValidation1.getInstance(); + try { + schema.validate( + MapUtils.makeMap( + new AbstractMap.SimpleEntry>( + "foo", + MapUtils.makeMap( + ) + ), + new AbstractMap.SimpleEntry>( + "foobar", + MapUtils.makeMap( + ) + ) + ), + configuration + ); + throw new RuntimeException("A different exception must be thrown"); + } catch (ValidationException | InvalidTypeException ignored) { + ; + } + } + + @Test + public void testIgnoresOtherNonObjectsPasses() { + // ignores other non-objects + final var schema = PropertynamesValidation.PropertynamesValidation1.getInstance(); + schema.validate( + 12, + configuration + ); + } + + @Test + public void testAllPropertyNamesValidPasses() { + // all property names valid + final var schema = PropertynamesValidation.PropertynamesValidation1.getInstance(); + schema.validate( + MapUtils.makeMap( + new AbstractMap.SimpleEntry>( + "f", + MapUtils.makeMap( + ) + ), + new AbstractMap.SimpleEntry>( + "foo", + MapUtils.makeMap( + ) + ) + ), + configuration + ); + } + + @Test + public void testObjectWithoutPropertiesIsValidPasses() { + // object without properties is valid + final var schema = PropertynamesValidation.PropertynamesValidation1.getInstance(); + schema.validate( + MapUtils.makeMap( + ), + configuration + ); + } + + @Test + public void testIgnoresArraysPasses() { + // ignores arrays + final var schema = PropertynamesValidation.PropertynamesValidation1.getInstance(); + schema.validate( + Arrays.asList( + 1, + 2, + 3, + 4 + ), + configuration + ); + } + + @Test + public void testIgnoresStringsPasses() { + // ignores strings + final var schema = PropertynamesValidation.PropertynamesValidation1.getInstance(); + schema.validate( + "foobar", + configuration + ); + } +} From bb8484da4cc003a607943556af074f6b793d7422 Mon Sep 17 00:00:00 2001 From: Justin Black Date: Tue, 16 Jan 2024 11:26:28 -0800 Subject: [PATCH 3/6] Generates schema and test in java client --- .../java/.openapi-generator/FILES | 2 +- .../schemas/PropertynamesValidation.md | 1 + .../schemas/PropertynamesValidation.java | 1 + .../client/schemas/validation/JsonSchema.java | 8 ++++++ .../schemas/validation/JsonSchemaInfo.java | 5 ++++ .../validation/PropertyNamesValidator.java | 28 +++++++++++++++++++ .../generators/JavaClientGenerator.java | 1 + .../_Schema_anytypeOrMultitype.hbs | 6 ++-- .../schemas/SchemaClass/_Schema_map.hbs | 6 ++-- .../schemas/SchemaClass/_propertyNames.hbs | 17 +++++++++++ .../schemas/docschema_fields_field.hbs | 3 ++ .../schemas/validation/JsonSchema.hbs | 8 ++++++ .../schemas/validation/JsonSchemaInfo.hbs | 5 ++++ .../validation/PropertyNamesValidator.hbs | 28 +++++++++++++++++++ 14 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java create mode 100644 src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_propertyNames.hbs create mode 100644 src/main/resources/java/src/main/java/packagename/schemas/validation/PropertyNamesValidator.hbs diff --git a/samples/client/3_1_0_unit_test/java/.openapi-generator/FILES b/samples/client/3_1_0_unit_test/java/.openapi-generator/FILES index bb7aa2c4237..dfafcef9ea0 100644 --- a/samples/client/3_1_0_unit_test/java/.openapi-generator/FILES +++ b/samples/client/3_1_0_unit_test/java/.openapi-generator/FILES @@ -310,6 +310,7 @@ src/main/java/org/openapijsonschematools/client/schemas/validation/PathToSchemas src/main/java/org/openapijsonschematools/client/schemas/validation/PatternValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/PropertiesValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyEntry.java +src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/RequiredValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/StringEnumValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/StringSchemaValidator.java @@ -321,7 +322,6 @@ src/main/java/org/openapijsonschematools/client/schemas/validation/ValidationMet src/main/java/org/openapijsonschematools/client/servers/Server0.java src/main/java/org/openapijsonschematools/client/servers/ServerWithVariables.java src/main/java/org/openapijsonschematools/client/servers/ServerWithoutVariables.java -src/test/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidationTest.java src/test/java/org/openapijsonschematools/client/configurations/JsonSchemaKeywordFlagsTest.java src/test/java/org/openapijsonschematools/client/schemas/AnyTypeSchemaTest.java src/test/java/org/openapijsonschematools/client/schemas/ArrayTypeSchemaTest.java diff --git a/samples/client/3_1_0_unit_test/java/docs/components/schemas/PropertynamesValidation.md b/samples/client/3_1_0_unit_test/java/docs/components/schemas/PropertynamesValidation.md index 80ef569b2e5..ffd1f8f51e1 100644 --- a/samples/client/3_1_0_unit_test/java/docs/components/schemas/PropertynamesValidation.md +++ b/samples/client/3_1_0_unit_test/java/docs/components/schemas/PropertynamesValidation.md @@ -20,6 +20,7 @@ A schema class that validates payloads ### Field Summary | Modifier and Type | Field and Description | | ----------------- | ---------------------- | +| Class | propertyNames = [PropertyNames.class](#propertynames) | ### Method Summary | Modifier and Type | Method and Description | diff --git a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidation.java b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidation.java index b64a82533dd..ef561372fe2 100644 --- a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidation.java +++ b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/PropertynamesValidation.java @@ -92,6 +92,7 @@ public static class PropertynamesValidation1 extends JsonSchema implements NullS protected PropertynamesValidation1() { super(new JsonSchemaInfo() + .propertyNames(PropertyNames.class) ); } diff --git a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java index 44c83b6d379..7385eb03930 100644 --- a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java +++ b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java @@ -49,6 +49,7 @@ public abstract class JsonSchema { public final @Nullable Class contains; public final @Nullable Integer maxContains; public final @Nullable Integer minContains; + public final @Nullable Class propertyNames; private final LinkedHashMap keywordToValidator; protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { @@ -252,6 +253,13 @@ protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { new MinContainsValidator(this.minContains) ); } + this.propertyNames = jsonSchemaInfo.propertyNames; + if (this.propertyNames != null) { + keywordToValidator.put( + "propertyNames", + new PropertyNamesValidator(this.propertyNames) + ); + } this.keywordToValidator = keywordToValidator; } diff --git a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java index 191148fe7bf..0f34ad5c61b 100644 --- a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java +++ b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java @@ -157,4 +157,9 @@ public JsonSchemaInfo minContains(Integer minContains) { this.minContains = minContains; return this; } + public @Nullable Class propertyNames = null; + public JsonSchemaInfo propertyNames(Class propertyNames) { + this.propertyNames = propertyNames; + return this; + } } \ No newline at end of file diff --git a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java new file mode 100644 index 00000000000..003ce66d2ea --- /dev/null +++ b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java @@ -0,0 +1,28 @@ +package org.openapijsonschematools.client.schemas.validation; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Map; + +public class PropertyNamesValidator implements KeywordValidator { + public final Class propertyNames; + + public PropertyNamesValidator(Class propertyNames) { + this.propertyNames = propertyNames; + } + + @Override + public @Nullable PathToSchemasMap validate( + JsonSchema schema, + @Nullable Object arg, + ValidationMetadata validationMetadata, + @Nullable List containsPathToSchemas + ) { + if (!(arg instanceof Map)) { + return null; + } + PathToSchemasMap pathToSchemas = new PathToSchemasMap(); + // todo add implementation + return pathToSchemas; + } +} diff --git a/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java b/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java index f64a52163e9..2bfa6d3aae4 100644 --- a/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java +++ b/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java @@ -612,6 +612,7 @@ public void processOpts() { keywordValidatorFiles.add("PatternValidator"); keywordValidatorFiles.add("PropertiesValidator"); keywordValidatorFiles.add("PropertyEntry"); + keywordValidatorFiles.add("PropertyNamesValidator"); keywordValidatorFiles.add("RequiredValidator"); keywordValidatorFiles.add("StringEnumValidator"); keywordValidatorFiles.add("StringSchemaValidator"); diff --git a/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_Schema_anytypeOrMultitype.hbs b/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_Schema_anytypeOrMultitype.hbs index 9ab119aaee9..2064fa6b1c1 100644 --- a/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_Schema_anytypeOrMultitype.hbs +++ b/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_Schema_anytypeOrMultitype.hbs @@ -108,6 +108,9 @@ public static class {{jsonPathPiece.pascalCase}} extends JsonSchema implements { {{#neq minContains null}} {{> src/main/java/packagename/components/schemas/SchemaClass/_minContains }} {{/neq}} + {{#if propertyNames}} + {{> src/main/java/packagename/components/schemas/SchemaClass/_propertyNames }} + {{/if}} ); } @@ -138,9 +141,6 @@ public static class {{jsonPathPiece.pascalCase}} extends JsonSchema implements { {{#if dependentSchemas}} {{!> components/schemas/schema_cls/_dependent_schemas }} {{/if}} -{{#if propertyNames}} - {{!> components/schemas/schema_cls/_property_names }} -{{/if}} {{#if patternProperties}} {{!> components/schemas/schema_cls/_pattern_properties }} {{/if}} diff --git a/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_Schema_map.hbs b/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_Schema_map.hbs index 7001b32ff08..da3cab20572 100644 --- a/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_Schema_map.hbs +++ b/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_Schema_map.hbs @@ -47,6 +47,9 @@ public static class {{jsonPathPiece.pascalCase}} extends JsonSchema implements M {{#if not}} {{> src/main/java/packagename/components/schemas/SchemaClass/_not }} {{/if}} + {{#if propertyNames}} + {{> src/main/java/packagename/components/schemas/SchemaClass/_propertyNames }} + {{/if}} ); } @@ -74,9 +77,6 @@ public static class {{jsonPathPiece.pascalCase}} extends JsonSchema implements M {{#if dependentSchemas}} {{!> components/schemas/schema_cls/_dependent_schemas }} {{/if}} - {{#if propertyNames}} - {{!> components/schemas/schema_cls/_property_names }} - {{/if}} {{#if patternProperties}} {{!> components/schemas/schema_cls/_pattern_properties }} {{/if}} diff --git a/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_propertyNames.hbs b/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_propertyNames.hbs new file mode 100644 index 00000000000..a403510199b --- /dev/null +++ b/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_propertyNames.hbs @@ -0,0 +1,17 @@ +{{#if forDocs}} + {{#with propertyNames}} + {{#if refInfo.refClass}} + {{#if refInfo.refModule}} +propertyNames = [{{refInfo.refModule}}.{{refInfo.refClass}}.class]({{docRoot}}{{refInfo.ref.pathFromDocRoot}}.md#{{refInfo.ref.jsonPathPiece.kebabCase}}) + {{~else}} +propertyNames = [{{refInfo.refClass}}.class](#{{refInfo.ref.jsonPathPiece.kebabCase}}) + {{~/if}} + {{else}} +propertyNames = [{{jsonPathPiece.pascalCase}}.class](#{{jsonPathPiece.kebabCase}}) + {{~/if}} + {{/with}} +{{else}} + {{#with propertyNames}} +.propertyNames({{#if refInfo.refClass}}{{#if refInfo.refModule}}{{refInfo.refModule}}.{{/if}}{{refInfo.refClass}}{{else}}{{jsonPathPiece.pascalCase}}{{/if}}.class) + {{/with}} +{{/if}} \ No newline at end of file diff --git a/src/main/resources/java/src/main/java/packagename/components/schemas/docschema_fields_field.hbs b/src/main/resources/java/src/main/java/packagename/components/schemas/docschema_fields_field.hbs index f37276d3e64..6b267efc37e 100644 --- a/src/main/resources/java/src/main/java/packagename/components/schemas/docschema_fields_field.hbs +++ b/src/main/resources/java/src/main/java/packagename/components/schemas/docschema_fields_field.hbs @@ -82,3 +82,6 @@ {{#neq minContains null}} | Integer | {{> src/main/java/packagename/components/schemas/SchemaClass/_minContains }} | {{/neq}} +{{#if propertyNames}} +| Class | {{> src/main/java/packagename/components/schemas/SchemaClass/_propertyNames }} | +{{/if}} diff --git a/src/main/resources/java/src/main/java/packagename/schemas/validation/JsonSchema.hbs b/src/main/resources/java/src/main/java/packagename/schemas/validation/JsonSchema.hbs index a2f163bf0d9..0bc00463d8d 100644 --- a/src/main/resources/java/src/main/java/packagename/schemas/validation/JsonSchema.hbs +++ b/src/main/resources/java/src/main/java/packagename/schemas/validation/JsonSchema.hbs @@ -49,6 +49,7 @@ public abstract class JsonSchema { public final @Nullable Class contains; public final @Nullable Integer maxContains; public final @Nullable Integer minContains; + public final @Nullable Class propertyNames; private final LinkedHashMap keywordToValidator; protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { @@ -252,6 +253,13 @@ public abstract class JsonSchema { new MinContainsValidator(this.minContains) ); } + this.propertyNames = jsonSchemaInfo.propertyNames; + if (this.propertyNames != null) { + keywordToValidator.put( + "propertyNames", + new PropertyNamesValidator(this.propertyNames) + ); + } this.keywordToValidator = keywordToValidator; } diff --git a/src/main/resources/java/src/main/java/packagename/schemas/validation/JsonSchemaInfo.hbs b/src/main/resources/java/src/main/java/packagename/schemas/validation/JsonSchemaInfo.hbs index 9f436b810cc..906a0cf0f0d 100644 --- a/src/main/resources/java/src/main/java/packagename/schemas/validation/JsonSchemaInfo.hbs +++ b/src/main/resources/java/src/main/java/packagename/schemas/validation/JsonSchemaInfo.hbs @@ -157,4 +157,9 @@ public class JsonSchemaInfo { this.minContains = minContains; return this; } + public @Nullable Class propertyNames = null; + public JsonSchemaInfo propertyNames(Class propertyNames) { + this.propertyNames = propertyNames; + return this; + } } \ No newline at end of file diff --git a/src/main/resources/java/src/main/java/packagename/schemas/validation/PropertyNamesValidator.hbs b/src/main/resources/java/src/main/java/packagename/schemas/validation/PropertyNamesValidator.hbs new file mode 100644 index 00000000000..4eb9bffd0ad --- /dev/null +++ b/src/main/resources/java/src/main/java/packagename/schemas/validation/PropertyNamesValidator.hbs @@ -0,0 +1,28 @@ +package {{{packageName}}}.schemas.validation; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Map; + +public class PropertyNamesValidator implements KeywordValidator { + public final Class propertyNames; + + public PropertyNamesValidator(Class propertyNames) { + this.propertyNames = propertyNames; + } + + @Override + public @Nullable PathToSchemasMap validate( + JsonSchema schema, + @Nullable Object arg, + ValidationMetadata validationMetadata, + @Nullable List containsPathToSchemas + ) { + if (!(arg instanceof Map)) { + return null; + } + PathToSchemasMap pathToSchemas = new PathToSchemasMap(); + // todo add implementation + return pathToSchemas; + } +} From ea08bdc7a91dc0cf88a746e76678f038587857ce Mon Sep 17 00:00:00 2001 From: Justin Black Date: Tue, 16 Jan 2024 11:45:23 -0800 Subject: [PATCH 4/6] Turns on PropertyNames feature for java generator --- docs/generators/java.md | 2 +- .../validation/PropertyNamesValidator.java | 20 ++++++++++++++++--- .../generators/JavaClientGenerator.java | 2 +- .../validation/PropertyNamesValidator.hbs | 20 ++++++++++++++++--- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/docs/generators/java.md b/docs/generators/java.md index fbc033160f5..8f79dbb09a1 100644 --- a/docs/generators/java.md +++ b/docs/generators/java.md @@ -307,7 +307,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |PatternProperties|✗|OAS3 |PrefixItems|✗|OAS3 |Properties|✓|OAS2,OAS3 -|PropertyNames|✗|OAS3 +|PropertyNames|✓|OAS3 |Ref|✓|OAS2,OAS3 |Required|✓|OAS2,OAS3 |Then|✗|OAS3 diff --git a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java index 003ce66d2ea..b0c50ba11e3 100644 --- a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java +++ b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java @@ -2,6 +2,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.ArrayList; +import java.util.List; import java.util.Map; public class PropertyNamesValidator implements KeywordValidator { @@ -21,8 +23,20 @@ public PropertyNamesValidator(Class propertyNames) { if (!(arg instanceof Map)) { return null; } - PathToSchemasMap pathToSchemas = new PathToSchemasMap(); - // todo add implementation - return pathToSchemas; + JsonSchema propertyNamesSchema = JsonSchemaFactory.getInstance(propertyNames); + for (Object objKey: ((Map) arg).keySet()) { + if (objKey instanceof String key) { + List propPathToItem = new ArrayList<>(validationMetadata.pathToItem()); + propPathToItem.add(key); + ValidationMetadata keyValidationMetadata = new ValidationMetadata( + propPathToItem, + validationMetadata.configuration(), + validationMetadata.validatedPathToSchemas(), + validationMetadata.seenClasses() + ); + JsonSchema.validate(propertyNamesSchema, key, keyValidationMetadata); + } + } + return null; } } diff --git a/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java b/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java index 2bfa6d3aae4..b49a6a67369 100644 --- a/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java +++ b/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java @@ -286,7 +286,7 @@ public JavaClientGenerator() { // SchemaFeature.PatternProperties, // SchemaFeature.PrefixItems, SchemaFeature.Properties, - // SchemaFeature.PropertyNames, + SchemaFeature.PropertyNames, SchemaFeature.Ref, SchemaFeature.Required, // SchemaFeature.Then, diff --git a/src/main/resources/java/src/main/java/packagename/schemas/validation/PropertyNamesValidator.hbs b/src/main/resources/java/src/main/java/packagename/schemas/validation/PropertyNamesValidator.hbs index 4eb9bffd0ad..1c0160c9805 100644 --- a/src/main/resources/java/src/main/java/packagename/schemas/validation/PropertyNamesValidator.hbs +++ b/src/main/resources/java/src/main/java/packagename/schemas/validation/PropertyNamesValidator.hbs @@ -2,6 +2,8 @@ package {{{packageName}}}.schemas.validation; import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.ArrayList; +import java.util.List; import java.util.Map; public class PropertyNamesValidator implements KeywordValidator { @@ -21,8 +23,20 @@ public class PropertyNamesValidator implements KeywordValidator { if (!(arg instanceof Map)) { return null; } - PathToSchemasMap pathToSchemas = new PathToSchemasMap(); - // todo add implementation - return pathToSchemas; + JsonSchema propertyNamesSchema = JsonSchemaFactory.getInstance(propertyNames); + for (Object objKey: ((Map) arg).keySet()) { + if (objKey instanceof String key) { + List propPathToItem = new ArrayList<>(validationMetadata.pathToItem()); + propPathToItem.add(key); + ValidationMetadata keyValidationMetadata = new ValidationMetadata( + propPathToItem, + validationMetadata.configuration(), + validationMetadata.validatedPathToSchemas(), + validationMetadata.seenClasses() + ); + JsonSchema.validate(propertyNamesSchema, key, keyValidationMetadata); + } + } + return null; } } From 10ab9569f6d3c69cc86eac4ebe6b5a03838bde96 Mon Sep 17 00:00:00 2001 From: Justin Black Date: Tue, 16 Jan 2024 11:53:40 -0800 Subject: [PATCH 5/6] Samples regen --- .../java/.openapi-generator/FILES | 1 + .../client/schemas/validation/JsonSchema.java | 8 ++++ .../schemas/validation/JsonSchemaInfo.java | 5 +++ .../validation/PropertyNamesValidator.java | 42 +++++++++++++++++++ .../petstore/java/.openapi-generator/FILES | 1 + .../client/schemas/validation/JsonSchema.java | 8 ++++ .../schemas/validation/JsonSchemaInfo.java | 5 +++ .../validation/PropertyNamesValidator.java | 42 +++++++++++++++++++ 8 files changed, 112 insertions(+) create mode 100644 samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java create mode 100644 samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java diff --git a/samples/client/3_0_3_unit_test/java/.openapi-generator/FILES b/samples/client/3_0_3_unit_test/java/.openapi-generator/FILES index f22ef910054..c73985cb6bc 100644 --- a/samples/client/3_0_3_unit_test/java/.openapi-generator/FILES +++ b/samples/client/3_0_3_unit_test/java/.openapi-generator/FILES @@ -258,6 +258,7 @@ src/main/java/org/openapijsonschematools/client/schemas/validation/PathToSchemas src/main/java/org/openapijsonschematools/client/schemas/validation/PatternValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/PropertiesValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyEntry.java +src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/RequiredValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/StringEnumValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/StringSchemaValidator.java diff --git a/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java b/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java index 44c83b6d379..7385eb03930 100644 --- a/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java +++ b/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java @@ -49,6 +49,7 @@ public abstract class JsonSchema { public final @Nullable Class contains; public final @Nullable Integer maxContains; public final @Nullable Integer minContains; + public final @Nullable Class propertyNames; private final LinkedHashMap keywordToValidator; protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { @@ -252,6 +253,13 @@ protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { new MinContainsValidator(this.minContains) ); } + this.propertyNames = jsonSchemaInfo.propertyNames; + if (this.propertyNames != null) { + keywordToValidator.put( + "propertyNames", + new PropertyNamesValidator(this.propertyNames) + ); + } this.keywordToValidator = keywordToValidator; } diff --git a/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java b/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java index 191148fe7bf..0f34ad5c61b 100644 --- a/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java +++ b/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java @@ -157,4 +157,9 @@ public JsonSchemaInfo minContains(Integer minContains) { this.minContains = minContains; return this; } + public @Nullable Class propertyNames = null; + public JsonSchemaInfo propertyNames(Class propertyNames) { + this.propertyNames = propertyNames; + return this; + } } \ No newline at end of file diff --git a/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java b/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java new file mode 100644 index 00000000000..b0c50ba11e3 --- /dev/null +++ b/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java @@ -0,0 +1,42 @@ +package org.openapijsonschematools.client.schemas.validation; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class PropertyNamesValidator implements KeywordValidator { + public final Class propertyNames; + + public PropertyNamesValidator(Class propertyNames) { + this.propertyNames = propertyNames; + } + + @Override + public @Nullable PathToSchemasMap validate( + JsonSchema schema, + @Nullable Object arg, + ValidationMetadata validationMetadata, + @Nullable List containsPathToSchemas + ) { + if (!(arg instanceof Map)) { + return null; + } + JsonSchema propertyNamesSchema = JsonSchemaFactory.getInstance(propertyNames); + for (Object objKey: ((Map) arg).keySet()) { + if (objKey instanceof String key) { + List propPathToItem = new ArrayList<>(validationMetadata.pathToItem()); + propPathToItem.add(key); + ValidationMetadata keyValidationMetadata = new ValidationMetadata( + propPathToItem, + validationMetadata.configuration(), + validationMetadata.validatedPathToSchemas(), + validationMetadata.seenClasses() + ); + JsonSchema.validate(propertyNamesSchema, key, keyValidationMetadata); + } + } + return null; + } +} diff --git a/samples/client/petstore/java/.openapi-generator/FILES b/samples/client/petstore/java/.openapi-generator/FILES index 65fbd2c52fb..be646b3ea7d 100644 --- a/samples/client/petstore/java/.openapi-generator/FILES +++ b/samples/client/petstore/java/.openapi-generator/FILES @@ -736,6 +736,7 @@ src/main/java/org/openapijsonschematools/client/schemas/validation/PathToSchemas src/main/java/org/openapijsonschematools/client/schemas/validation/PatternValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/PropertiesValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyEntry.java +src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/RequiredValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/StringEnumValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/StringSchemaValidator.java diff --git a/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java b/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java index 44c83b6d379..7385eb03930 100644 --- a/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java +++ b/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchema.java @@ -49,6 +49,7 @@ public abstract class JsonSchema { public final @Nullable Class contains; public final @Nullable Integer maxContains; public final @Nullable Integer minContains; + public final @Nullable Class propertyNames; private final LinkedHashMap keywordToValidator; protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { @@ -252,6 +253,13 @@ protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { new MinContainsValidator(this.minContains) ); } + this.propertyNames = jsonSchemaInfo.propertyNames; + if (this.propertyNames != null) { + keywordToValidator.put( + "propertyNames", + new PropertyNamesValidator(this.propertyNames) + ); + } this.keywordToValidator = keywordToValidator; } diff --git a/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java b/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java index 191148fe7bf..0f34ad5c61b 100644 --- a/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java +++ b/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/JsonSchemaInfo.java @@ -157,4 +157,9 @@ public JsonSchemaInfo minContains(Integer minContains) { this.minContains = minContains; return this; } + public @Nullable Class propertyNames = null; + public JsonSchemaInfo propertyNames(Class propertyNames) { + this.propertyNames = propertyNames; + return this; + } } \ No newline at end of file diff --git a/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java b/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java new file mode 100644 index 00000000000..b0c50ba11e3 --- /dev/null +++ b/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/PropertyNamesValidator.java @@ -0,0 +1,42 @@ +package org.openapijsonschematools.client.schemas.validation; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class PropertyNamesValidator implements KeywordValidator { + public final Class propertyNames; + + public PropertyNamesValidator(Class propertyNames) { + this.propertyNames = propertyNames; + } + + @Override + public @Nullable PathToSchemasMap validate( + JsonSchema schema, + @Nullable Object arg, + ValidationMetadata validationMetadata, + @Nullable List containsPathToSchemas + ) { + if (!(arg instanceof Map)) { + return null; + } + JsonSchema propertyNamesSchema = JsonSchemaFactory.getInstance(propertyNames); + for (Object objKey: ((Map) arg).keySet()) { + if (objKey instanceof String key) { + List propPathToItem = new ArrayList<>(validationMetadata.pathToItem()); + propPathToItem.add(key); + ValidationMetadata keyValidationMetadata = new ValidationMetadata( + propPathToItem, + validationMetadata.configuration(), + validationMetadata.validatedPathToSchemas(), + validationMetadata.seenClasses() + ); + JsonSchema.validate(propertyNamesSchema, key, keyValidationMetadata); + } + } + return null; + } +} From 081333a6d7fc3da2a856e35cd6ac63fc453f2fae Mon Sep 17 00:00:00 2001 From: Justin Black Date: Tue, 16 Jan 2024 12:01:53 -0800 Subject: [PATCH 6/6] Updates java data type features to include number --- docs/generators/java.md | 2 +- .../codegen/generators/DefaultGenerator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/generators/java.md b/docs/generators/java.md index 8f79dbb09a1..51e712d8556 100644 --- a/docs/generators/java.md +++ b/docs/generators/java.md @@ -197,7 +197,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |Integer|✓|OAS2,OAS3 |Float|✓|OAS2,OAS3 |Double|✓|OAS2,OAS3 -|Number|✗|OAS2,OAS3 +|Number|✓|OAS2,OAS3 |String|✓|OAS2,OAS3 |Byte|✗|OAS2,OAS3 |Binary|✗|OAS2,OAS3 diff --git a/src/main/java/org/openapijsonschematools/codegen/generators/DefaultGenerator.java b/src/main/java/org/openapijsonschematools/codegen/generators/DefaultGenerator.java index bcfe709d5ac..b3cdb2baf3b 100644 --- a/src/main/java/org/openapijsonschematools/codegen/generators/DefaultGenerator.java +++ b/src/main/java/org/openapijsonschematools/codegen/generators/DefaultGenerator.java @@ -159,7 +159,7 @@ public class DefaultGenerator implements Generator { static { DefaultFeatureSet = FeatureSet.newBuilder() .includeDataTypeFeatures( - DataTypeFeature.Int32, DataTypeFeature.Int64, DataTypeFeature.Integer, DataTypeFeature.Float, DataTypeFeature.Double, + DataTypeFeature.Int32, DataTypeFeature.Int64, DataTypeFeature.Integer, DataTypeFeature.Float, DataTypeFeature.Double, DataTypeFeature.Number, DataTypeFeature.String, DataTypeFeature.Boolean, DataTypeFeature.Date, DataTypeFeature.DateTime, DataTypeFeature.Array, DataTypeFeature.Object, DataTypeFeature.Enum, DataTypeFeature.Uuid,