diff --git a/docs/generators/java.md b/docs/generators/java.md index 51e712d8556..2129e21cbaa 100644 --- a/docs/generators/java.md +++ b/docs/generators/java.md @@ -279,7 +279,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |Const|✓|OAS3 |Contains|✓|OAS3 |Default|✓|OAS2,OAS3 -|DependentRequired|✗|OAS3 +|DependentRequired|✓|OAS3 |DependentSchemas|✗|OAS3 |Discriminator|✗|OAS2,OAS3 |Else|✗|OAS3 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 c73985cb6bc..a555be6c888 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 @@ -213,6 +213,7 @@ src/main/java/org/openapijsonschematools/client/schemas/validation/ConstValidato src/main/java/org/openapijsonschematools/client/schemas/validation/ContainsValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/CustomIsoparser.java src/main/java/org/openapijsonschematools/client/schemas/validation/DefaultValueMethod.java +src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/DoubleEnumValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/DoubleValueMethod.java src/main/java/org/openapijsonschematools/client/schemas/validation/EnumValidator.java diff --git a/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java b/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java new file mode 100644 index 00000000000..8c91c9316fc --- /dev/null +++ b/samples/client/3_0_3_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java @@ -0,0 +1,48 @@ +package org.openapijsonschematools.client.schemas.validation; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.openapijsonschematools.client.exceptions.ValidationException; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class DependentRequiredValidator implements KeywordValidator { + public final Map> dependentRequired; + + public DependentRequiredValidator(Map> dependentRequired) { + this.dependentRequired = dependentRequired; + } + + @Override + public @Nullable PathToSchemasMap validate( + JsonSchema schema, + @Nullable Object arg, + ValidationMetadata validationMetadata, + @Nullable List containsPathToSchemas + ) { + if (!(arg instanceof Map)) { + return null; + } + for (Map.Entry> entry: dependentRequired.entrySet()) { + if (!((Map) arg).containsKey(entry.getKey())) { + continue; + } + Set missingKeys = new HashSet<>(entry.getValue()); + for (Object objKey: ((Map) arg).keySet()) { + if (objKey instanceof String key) { + missingKeys.remove(key); + } + } + if (missingKeys.isEmpty()) { + continue; + } + throw new ValidationException( + "Validation failed for dependentRequired because these_keys="+missingKeys+" are "+ + "missing at pathToItem="+validationMetadata.pathToItem()+" in class "+schema.getClass() + ); + } + return null; + } +} 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 7385eb03930..9d7831b6225 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 @@ -50,6 +50,7 @@ public abstract class JsonSchema { public final @Nullable Integer maxContains; public final @Nullable Integer minContains; public final @Nullable Class propertyNames; + public @Nullable Map> dependentRequired; private final LinkedHashMap keywordToValidator; protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { @@ -260,6 +261,13 @@ protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { new PropertyNamesValidator(this.propertyNames) ); } + this.dependentRequired = jsonSchemaInfo.dependentRequired; + if (this.dependentRequired != null) { + keywordToValidator.put( + "dependentRequired", + new DependentRequiredValidator(this.dependentRequired) + ); + } 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 0f34ad5c61b..59f51a6be72 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 @@ -162,4 +162,9 @@ public JsonSchemaInfo propertyNames(Class propertyNames) { this.propertyNames = propertyNames; return this; } + public @Nullable Map> dependentRequired = null; + public JsonSchemaInfo dependentRequired(Map> dependentRequired) { + this.dependentRequired = dependentRequired; + return this; + } } \ No newline at end of file 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 dfafcef9ea0..610c2c86171 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 @@ -265,6 +265,7 @@ src/main/java/org/openapijsonschematools/client/schemas/validation/ConstValidato src/main/java/org/openapijsonschematools/client/schemas/validation/ContainsValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/CustomIsoparser.java src/main/java/org/openapijsonschematools/client/schemas/validation/DefaultValueMethod.java +src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/DoubleEnumValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/DoubleValueMethod.java src/main/java/org/openapijsonschematools/client/schemas/validation/EnumValidator.java diff --git a/samples/client/3_1_0_unit_test/java/docs/components/schemas/EmptyDependents.md b/samples/client/3_1_0_unit_test/java/docs/components/schemas/EmptyDependents.md index 9c1b7c6da46..d85711c57b0 100644 --- a/samples/client/3_1_0_unit_test/java/docs/components/schemas/EmptyDependents.md +++ b/samples/client/3_1_0_unit_test/java/docs/components/schemas/EmptyDependents.md @@ -19,6 +19,14 @@ A schema class that validates payloads ### Field Summary | Modifier and Type | Field and Description | | ----------------- | ---------------------- | +| Map> | dependentRequired = MapUtils.makeMap(
+    new AbstractMap.SimpleEntry<>(
+        "bar",
+        SetMaker.makeSet( +        ) +    )
+) + | ### 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/EmptyDependents.java b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/EmptyDependents.java index 6ab68453d03..ed5d703fb93 100644 --- a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/EmptyDependents.java +++ b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/components/schemas/EmptyDependents.java @@ -1,6 +1,7 @@ package org.openapijsonschematools.client.components.schemas; import java.time.LocalDate; import java.time.ZonedDateTime; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; @@ -17,6 +18,7 @@ import org.openapijsonschematools.client.exceptions.InvalidTypeException; import org.openapijsonschematools.client.exceptions.UnsetPropertyException; import org.openapijsonschematools.client.exceptions.ValidationException; +import org.openapijsonschematools.client.schemas.SetMaker; import org.openapijsonschematools.client.schemas.UnsetAddPropsSetter; import org.openapijsonschematools.client.schemas.validation.BooleanSchemaValidator; import org.openapijsonschematools.client.schemas.validation.FrozenList; @@ -25,6 +27,7 @@ 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.MapUtils; import org.openapijsonschematools.client.schemas.validation.NullSchemaValidator; import org.openapijsonschematools.client.schemas.validation.NumberSchemaValidator; import org.openapijsonschematools.client.schemas.validation.PathToSchemasMap; @@ -46,6 +49,13 @@ public static class EmptyDependents1 extends JsonSchema implements NullSchemaVal protected EmptyDependents1() { super(new JsonSchemaInfo() + .dependentRequired(MapUtils.makeMap( + new AbstractMap.SimpleEntry<>( + "bar", + SetMaker.makeSet( + ) + ) + )) ); } diff --git a/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java new file mode 100644 index 00000000000..8c91c9316fc --- /dev/null +++ b/samples/client/3_1_0_unit_test/java/src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java @@ -0,0 +1,48 @@ +package org.openapijsonschematools.client.schemas.validation; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.openapijsonschematools.client.exceptions.ValidationException; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class DependentRequiredValidator implements KeywordValidator { + public final Map> dependentRequired; + + public DependentRequiredValidator(Map> dependentRequired) { + this.dependentRequired = dependentRequired; + } + + @Override + public @Nullable PathToSchemasMap validate( + JsonSchema schema, + @Nullable Object arg, + ValidationMetadata validationMetadata, + @Nullable List containsPathToSchemas + ) { + if (!(arg instanceof Map)) { + return null; + } + for (Map.Entry> entry: dependentRequired.entrySet()) { + if (!((Map) arg).containsKey(entry.getKey())) { + continue; + } + Set missingKeys = new HashSet<>(entry.getValue()); + for (Object objKey: ((Map) arg).keySet()) { + if (objKey instanceof String key) { + missingKeys.remove(key); + } + } + if (missingKeys.isEmpty()) { + continue; + } + throw new ValidationException( + "Validation failed for dependentRequired because these_keys="+missingKeys+" are "+ + "missing at pathToItem="+validationMetadata.pathToItem()+" in class "+schema.getClass() + ); + } + return null; + } +} 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 7385eb03930..9d7831b6225 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 @@ -50,6 +50,7 @@ public abstract class JsonSchema { public final @Nullable Integer maxContains; public final @Nullable Integer minContains; public final @Nullable Class propertyNames; + public @Nullable Map> dependentRequired; private final LinkedHashMap keywordToValidator; protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { @@ -260,6 +261,13 @@ protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { new PropertyNamesValidator(this.propertyNames) ); } + this.dependentRequired = jsonSchemaInfo.dependentRequired; + if (this.dependentRequired != null) { + keywordToValidator.put( + "dependentRequired", + new DependentRequiredValidator(this.dependentRequired) + ); + } 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 0f34ad5c61b..59f51a6be72 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 @@ -162,4 +162,9 @@ public JsonSchemaInfo propertyNames(Class propertyNames) { this.propertyNames = propertyNames; return this; } + public @Nullable Map> dependentRequired = null; + public JsonSchemaInfo dependentRequired(Map> dependentRequired) { + this.dependentRequired = dependentRequired; + return this; + } } \ No newline at end of file diff --git a/samples/client/petstore/java/.openapi-generator/FILES b/samples/client/petstore/java/.openapi-generator/FILES index be646b3ea7d..3df4cfd1c39 100644 --- a/samples/client/petstore/java/.openapi-generator/FILES +++ b/samples/client/petstore/java/.openapi-generator/FILES @@ -691,6 +691,7 @@ src/main/java/org/openapijsonschematools/client/schemas/validation/ConstValidato src/main/java/org/openapijsonschematools/client/schemas/validation/ContainsValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/CustomIsoparser.java src/main/java/org/openapijsonschematools/client/schemas/validation/DefaultValueMethod.java +src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/DoubleEnumValidator.java src/main/java/org/openapijsonschematools/client/schemas/validation/DoubleValueMethod.java src/main/java/org/openapijsonschematools/client/schemas/validation/EnumValidator.java diff --git a/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java b/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java new file mode 100644 index 00000000000..8c91c9316fc --- /dev/null +++ b/samples/client/petstore/java/src/main/java/org/openapijsonschematools/client/schemas/validation/DependentRequiredValidator.java @@ -0,0 +1,48 @@ +package org.openapijsonschematools.client.schemas.validation; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.openapijsonschematools.client.exceptions.ValidationException; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class DependentRequiredValidator implements KeywordValidator { + public final Map> dependentRequired; + + public DependentRequiredValidator(Map> dependentRequired) { + this.dependentRequired = dependentRequired; + } + + @Override + public @Nullable PathToSchemasMap validate( + JsonSchema schema, + @Nullable Object arg, + ValidationMetadata validationMetadata, + @Nullable List containsPathToSchemas + ) { + if (!(arg instanceof Map)) { + return null; + } + for (Map.Entry> entry: dependentRequired.entrySet()) { + if (!((Map) arg).containsKey(entry.getKey())) { + continue; + } + Set missingKeys = new HashSet<>(entry.getValue()); + for (Object objKey: ((Map) arg).keySet()) { + if (objKey instanceof String key) { + missingKeys.remove(key); + } + } + if (missingKeys.isEmpty()) { + continue; + } + throw new ValidationException( + "Validation failed for dependentRequired because these_keys="+missingKeys+" are "+ + "missing at pathToItem="+validationMetadata.pathToItem()+" in class "+schema.getClass() + ); + } + return null; + } +} 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 7385eb03930..9d7831b6225 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 @@ -50,6 +50,7 @@ public abstract class JsonSchema { public final @Nullable Integer maxContains; public final @Nullable Integer minContains; public final @Nullable Class propertyNames; + public @Nullable Map> dependentRequired; private final LinkedHashMap keywordToValidator; protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { @@ -260,6 +261,13 @@ protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { new PropertyNamesValidator(this.propertyNames) ); } + this.dependentRequired = jsonSchemaInfo.dependentRequired; + if (this.dependentRequired != null) { + keywordToValidator.put( + "dependentRequired", + new DependentRequiredValidator(this.dependentRequired) + ); + } 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 0f34ad5c61b..59f51a6be72 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 @@ -162,4 +162,9 @@ public JsonSchemaInfo propertyNames(Class propertyNames) { this.propertyNames = propertyNames; return this; } + public @Nullable Map> dependentRequired = null; + public JsonSchemaInfo dependentRequired(Map> dependentRequired) { + this.dependentRequired = dependentRequired; + return this; + } } \ No newline at end of file diff --git a/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java b/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java index b49a6a67369..e4ce58e2b93 100644 --- a/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java +++ b/src/main/java/org/openapijsonschematools/codegen/generators/JavaClientGenerator.java @@ -258,7 +258,7 @@ public JavaClientGenerator() { SchemaFeature.Const, SchemaFeature.Contains, SchemaFeature.Default, - // SchemaFeature.DependentRequired, + SchemaFeature.DependentRequired, // SchemaFeature.DependentSchemas, // SchemaFeature.Discriminator, // SchemaFeature.Else, @@ -567,6 +567,7 @@ public void processOpts() { keywordValidatorFiles.add("BigDecimalValidator"); keywordValidatorFiles.add("CustomIsoparser"); keywordValidatorFiles.add("DefaultValueMethod"); + keywordValidatorFiles.add("DependentRequiredValidator"); keywordValidatorFiles.add("DoubleEnumValidator"); keywordValidatorFiles.add("DoubleValueMethod"); keywordValidatorFiles.add("EnumValidator"); @@ -1347,6 +1348,7 @@ public Set getImports(String sourceJsonPath, CodegenSchema schema, Featu addMultipleOfValidator(schema, imports); addAdditionalPropertiesImports(schema, imports); addDefaultValueImport(schema, imports); + addDependentRequiredImports(schema, imports); if (schema.mapValueSchema != null) { imports.addAll(getDeeperImports(sourceJsonPath, schema.mapValueSchema)); } @@ -1460,6 +1462,14 @@ private void addPropertiesValidator(CodegenSchema schema, Set imports) { } } + private void addDependentRequiredImports(CodegenSchema schema, Set imports) { + if (schema.dependentRequired != null) { + imports.add("import "+packageName + ".schemas.validation.MapUtils;"); + imports.add("import java.util.AbstractMap;"); + imports.add("import "+packageName + ".schemas.SetMaker;"); + } + } + private void addAllOfValidator(CodegenSchema schema, Set imports) { if (schema.allOf != null) { imports.add("import java.util.List;"); @@ -1554,6 +1564,7 @@ private void addMapSchemaImports(Set imports, CodegenSchema schema) { addAnyOfValidator(schema, imports); addOneOfValidator(schema, imports); addAdditionalPropertiesImports(schema, imports); + addDependentRequiredImports(schema, imports); } private void addListSchemaImports(Set imports, CodegenSchema schema) { 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 2064fa6b1c1..eb60ec24f8c 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 @@ -111,6 +111,9 @@ public static class {{jsonPathPiece.pascalCase}} extends JsonSchema implements { {{#if propertyNames}} {{> src/main/java/packagename/components/schemas/SchemaClass/_propertyNames }} {{/if}} + {{#if dependentRequired}} + {{> src/main/java/packagename/components/schemas/SchemaClass/_dependentRequired }} + {{/if}} ); } @@ -135,9 +138,6 @@ public static class {{jsonPathPiece.pascalCase}} extends JsonSchema implements { {{#if else_}} {{!> components/schemas/schema_cls/_else }} {{/if}} -{{#if dependentRequired}} - {{!> components/schemas/schema_cls/_dependent_required }} -{{/if}} {{#if dependentSchemas}} {{!> components/schemas/schema_cls/_dependent_schemas }} {{/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 da3cab20572..6371ba4c53b 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 @@ -50,6 +50,9 @@ public static class {{jsonPathPiece.pascalCase}} extends JsonSchema implements M {{#if propertyNames}} {{> src/main/java/packagename/components/schemas/SchemaClass/_propertyNames }} {{/if}} + {{#if dependentRequired}} + {{> src/main/java/packagename/components/schemas/SchemaClass/_dependentRequired }} + {{/if}} ); } @@ -71,9 +74,6 @@ public static class {{jsonPathPiece.pascalCase}} extends JsonSchema implements M {{#if else_}} {{!> components/schemas/schema_cls/_else }} {{/if}} - {{#if dependentRequired}} - {{!> components/schemas/schema_cls/_dependent_required }} - {{/if}} {{#if dependentSchemas}} {{!> components/schemas/schema_cls/_dependent_schemas }} {{/if}} diff --git a/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_dependentRequired.hbs b/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_dependentRequired.hbs new file mode 100644 index 00000000000..b134b9fb065 --- /dev/null +++ b/src/main/resources/java/src/main/java/packagename/components/schemas/SchemaClass/_dependentRequired.hbs @@ -0,0 +1,27 @@ +{{#if forDocs}} +dependentRequired = MapUtils.makeMap(
+ {{#each dependentRequired}} +    new AbstractMap.SimpleEntry<>(
+        "{{{@key}}}",
+        SetMaker.makeSet( + {{#each this}} +            "{{{this}}}"{{#unless @last}},{{/unless}}
+ {{/each}} +        ) +    ){{#unless @last}},{{/unless}}
+ {{/each}} +) +{{else}} +.dependentRequired(MapUtils.makeMap( + {{#each dependentRequired}} + new AbstractMap.SimpleEntry<>( + "{{{@key}}}", + SetMaker.makeSet( + {{#each this}} + "{{{this}}}"{{#unless @last}},{{/unless}} + {{/each}} + ) + ){{#unless @last}},{{/unless}} + {{/each}} +)) +{{/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 6b267efc37e..d7aaacda855 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 @@ -85,3 +85,6 @@ {{#if propertyNames}} | Class | {{> src/main/java/packagename/components/schemas/SchemaClass/_propertyNames }} | {{/if}} +{{#if dependentRequired}} +| Map> | {{> src/main/java/packagename/components/schemas/SchemaClass/_dependentRequired }} | +{{/if}} diff --git a/src/main/resources/java/src/main/java/packagename/schemas/validation/DependentRequiredValidator.hbs b/src/main/resources/java/src/main/java/packagename/schemas/validation/DependentRequiredValidator.hbs new file mode 100644 index 00000000000..13a9f9ed85b --- /dev/null +++ b/src/main/resources/java/src/main/java/packagename/schemas/validation/DependentRequiredValidator.hbs @@ -0,0 +1,48 @@ +package {{{packageName}}}.schemas.validation; + +import org.checkerframework.checker.nullness.qual.Nullable; +import {{{packageName}}}.exceptions.ValidationException; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class DependentRequiredValidator implements KeywordValidator { + public final Map> dependentRequired; + + public DependentRequiredValidator(Map> dependentRequired) { + this.dependentRequired = dependentRequired; + } + + @Override + public @Nullable PathToSchemasMap validate( + JsonSchema schema, + @Nullable Object arg, + ValidationMetadata validationMetadata, + @Nullable List containsPathToSchemas + ) { + if (!(arg instanceof Map)) { + return null; + } + for (Map.Entry> entry: dependentRequired.entrySet()) { + if (!((Map) arg).containsKey(entry.getKey())) { + continue; + } + Set missingKeys = new HashSet<>(entry.getValue()); + for (Object objKey: ((Map) arg).keySet()) { + if (objKey instanceof String key) { + missingKeys.remove(key); + } + } + if (missingKeys.isEmpty()) { + continue; + } + throw new ValidationException( + "Validation failed for dependentRequired because these_keys="+missingKeys+" are "+ + "missing at pathToItem="+validationMetadata.pathToItem()+" in class "+schema.getClass() + ); + } + return null; + } +} 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 0bc00463d8d..a18be460d45 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 @@ -50,6 +50,7 @@ public abstract class JsonSchema { public final @Nullable Integer maxContains; public final @Nullable Integer minContains; public final @Nullable Class propertyNames; + public @Nullable Map> dependentRequired; private final LinkedHashMap keywordToValidator; protected JsonSchema(JsonSchemaInfo jsonSchemaInfo) { @@ -260,6 +261,13 @@ public abstract class JsonSchema { new PropertyNamesValidator(this.propertyNames) ); } + this.dependentRequired = jsonSchemaInfo.dependentRequired; + if (this.dependentRequired != null) { + keywordToValidator.put( + "dependentRequired", + new DependentRequiredValidator(this.dependentRequired) + ); + } 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 906a0cf0f0d..0f17554d0f2 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 @@ -162,4 +162,9 @@ public class JsonSchemaInfo { this.propertyNames = propertyNames; return this; } + public @Nullable Map> dependentRequired = null; + public JsonSchemaInfo dependentRequired(Map> dependentRequired) { + this.dependentRequired = dependentRequired; + return this; + } } \ No newline at end of file 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 26f73b27486..bc2019c813f 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 @@ -719,13 +719,11 @@ def write_openapi_spec(): 'IfAppearsAtTheEndWhenSerializedKeywordProcessingSequence', 'IgnoreThenWithoutIf', 'IgnoreElseWithoutIf', - 'MultipleDependentsRequired', 'MultipleSimultaneousPatternpropertiesAreValidated', 'NonAsciiPatternWithAdditionalproperties', 'PatternpropertiesValidatesPropertiesMatchingARegex', 'PropertiesPatternpropertiesAdditionalpropertiesInteraction', 'RegexesAreNotAnchoredByDefaultAndAreCaseSensitive', - 'SingleDependency', 'UnevaluateditemsAsSchema', 'UnevaluateditemsWithNullInstanceElements', 'UnevaluatedpropertiesNotAffectedByPropertynames',