Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit e7cfbe0

Browse files
authored
Feat adds java schema configuration (#271)
* Requires java 17 to use records * Adds tests of JsonSchemaKewordFlags * Adds SchemaConfiguration class * Adds ValidationMetadata * Adds validationRanEarlier method * Adds PathToSchemasMap class * Sample updated * Docs updated
1 parent b1d827a commit e7cfbe0

File tree

25 files changed

+1128
-10
lines changed

25 files changed

+1128
-10
lines changed

docs/generators/java.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ title: Documentation for the java generator
1010
| generator stability | EXPERIMENTAL | |
1111
| generator type | CLIENT | |
1212
| generator language | Java | |
13+
| generator language version | 17 | |
1314
| generator default templating engine | handlebars | |
1415
| helpTxt | Generates a Java client library (HTTP lib: Jersey (1.x, 2.x), Retrofit (2.x), OpenFeign (10.x) and more. | |
1516

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
README.md
22
pom.xml
3+
src/main/java/org/openapijsonschematools/configurations/JsonSchemaKeywordFlags.java
4+
src/main/java/org/openapijsonschematools/configurations/SchemaConfiguration.java
35
src/main/java/org/openapijsonschematools/schemas/CustomIsoparser.java
6+
src/main/java/org/openapijsonschematools/schemas/PathToSchemasMap.java
7+
src/main/java/org/openapijsonschematools/schemas/SchemaValidator.java
8+
src/main/java/org/openapijsonschematools/schemas/ValidationMetadata.java
9+
src/main/java/org/openapijsonschematools/schemas/validators/KeywordValidator.java
10+
src/main/java/org/openapijsonschematools/schemas/validators/TypeValidator.java
11+
src/test/java/org/openapijsonschematools/configurations/JsonSchemaKeywordFlagsTest.java
412
src/test/java/org/openapijsonschematools/schemas/CustomIsoparserTest.java
13+
src/test/java/org/openapijsonschematools/schemas/validators/TypeValidatorTest.java

samples/client/petstore/java/README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@ This Java package is automatically generated by the [OpenAPI JSON Schema Generat
77

88
- API version: 1.0.0
99
- Package version:
10-
1110
- Build package: JavaClientGenerator
1211

1312

1413
## Requirements
1514

16-
Python
15+
Java 17
1716

1817
## Migration Guides
1918
- [3.0.0 Migration Guide](migration_3_0_0.md)

samples/client/petstore/java/pom.xml

+1-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@
4141
<artifactId>maven-compiler-plugin</artifactId>
4242
<version>3.8.1</version>
4343
<configuration>
44-
<source>1.8</source>
45-
<target>1.8</target>
4644
<fork>true</fork>
4745
<meminitial>128m</meminitial>
4846
<maxmem>512m</maxmem>
@@ -281,6 +279,7 @@
281279
</dependency>
282280
</dependencies>
283281
<properties>
282+
<maven.compiler.release>17</maven.compiler.release>
284283
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
285284
<swagger-annotations-version>1.6.3</swagger-annotations-version>
286285
<jersey-version>1.19.4</jersey-version>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package org.openapijsonschematools.configurations;
2+
3+
import java.util.LinkedHashSet;
4+
5+
public record JsonSchemaKeywordFlags(
6+
boolean additionalProperties,
7+
boolean allOf,
8+
boolean anyOf,
9+
boolean const_,
10+
boolean contains,
11+
boolean dependentRequired,
12+
boolean dependentSchemas,
13+
boolean discriminator,
14+
boolean else_,
15+
boolean enum_,
16+
boolean exclusiveMaximum,
17+
boolean exclusiveMinimum,
18+
boolean format,
19+
boolean if_,
20+
boolean maximum,
21+
boolean minimum,
22+
boolean items,
23+
boolean maxContains,
24+
boolean maxItems,
25+
boolean maxLength,
26+
boolean maxProperties,
27+
boolean minContains,
28+
boolean minItems,
29+
boolean minLength,
30+
boolean minProperties,
31+
boolean multipleOf,
32+
boolean not,
33+
boolean oneOf,
34+
boolean pattern,
35+
boolean patternProperties,
36+
boolean prefixItems,
37+
boolean properties,
38+
boolean propertyNames,
39+
boolean required,
40+
boolean then,
41+
boolean type,
42+
boolean uniqueItems,
43+
boolean unevaluatedItems,
44+
boolean unevaluatedProperties
45+
) {
46+
47+
public static JsonSchemaKeywordFlags ofNone() {
48+
return new JsonSchemaKeywordFlags(
49+
false,
50+
false,
51+
false,
52+
false,
53+
false,
54+
false,
55+
false,
56+
false,
57+
false,
58+
false,
59+
false,
60+
false,
61+
false,
62+
false,
63+
false,
64+
false,
65+
false,
66+
false,
67+
false,
68+
false,
69+
false,
70+
false,
71+
false,
72+
false,
73+
false,
74+
false,
75+
false,
76+
false,
77+
false,
78+
false,
79+
false,
80+
false,
81+
false,
82+
false,
83+
false,
84+
false,
85+
false,
86+
false,
87+
false
88+
);
89+
}
90+
91+
public LinkedHashSet<String> getKeywords() {
92+
LinkedHashSet<String> enabledKeywords = new LinkedHashSet<>();
93+
if (additionalProperties) { enabledKeywords.add("additionalProperties"); }
94+
if (allOf) { enabledKeywords.add("allOf"); }
95+
if (anyOf) { enabledKeywords.add("anyOf"); }
96+
if (const_) { enabledKeywords.add("const_"); }
97+
if (contains) { enabledKeywords.add("contains"); }
98+
if (dependentRequired) { enabledKeywords.add("dependentRequired"); }
99+
if (dependentSchemas) { enabledKeywords.add("dependentSchemas"); }
100+
if (discriminator) { enabledKeywords.add("discriminator"); }
101+
if (else_) { enabledKeywords.add("else_"); }
102+
if (enum_) { enabledKeywords.add("enum_"); }
103+
if (exclusiveMaximum) { enabledKeywords.add("exclusiveMaximum"); }
104+
if (exclusiveMinimum) { enabledKeywords.add("exclusiveMinimum"); }
105+
if (format) { enabledKeywords.add("format"); }
106+
if (if_) { enabledKeywords.add("if_"); }
107+
if (maximum) { enabledKeywords.add("maximum"); }
108+
if (minimum) { enabledKeywords.add("minimum"); }
109+
if (items) { enabledKeywords.add("items"); }
110+
if (maxContains) { enabledKeywords.add("maxContains"); }
111+
if (maxItems) { enabledKeywords.add("maxItems"); }
112+
if (maxLength) { enabledKeywords.add("maxLength"); }
113+
if (maxProperties) { enabledKeywords.add("maxProperties"); }
114+
if (minContains) { enabledKeywords.add("minContains"); }
115+
if (minItems) { enabledKeywords.add("minItems"); }
116+
if (minLength) { enabledKeywords.add("minLength"); }
117+
if (minProperties) { enabledKeywords.add("minProperties"); }
118+
if (multipleOf) { enabledKeywords.add("multipleOf"); }
119+
if (not) { enabledKeywords.add("not"); }
120+
if (oneOf) { enabledKeywords.add("oneOf"); }
121+
if (pattern) { enabledKeywords.add("pattern"); }
122+
if (patternProperties) { enabledKeywords.add("patternProperties"); }
123+
if (prefixItems) { enabledKeywords.add("prefixItems"); }
124+
if (properties) { enabledKeywords.add("properties"); }
125+
if (propertyNames) { enabledKeywords.add("propertyNames"); }
126+
if (required) { enabledKeywords.add("required"); }
127+
if (then) { enabledKeywords.add("then"); }
128+
if (type) { enabledKeywords.add("type"); }
129+
if (uniqueItems) { enabledKeywords.add("uniqueItems"); }
130+
if (unevaluatedItems) { enabledKeywords.add("unevaluatedItems"); }
131+
if (unevaluatedProperties) { enabledKeywords.add("unevaluatedProperties"); }
132+
return enabledKeywords;
133+
}
134+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.openapijsonschematools.configurations;
2+
3+
public record SchemaConfiguration(JsonSchemaKeywordFlags disabledKeywordFlags) {
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.openapijsonschematools.schemas;
2+
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
public class PathToSchemasMap extends HashMap<List<Object>, Map<Class<?>, Void>> {
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package org.openapijsonschematools.schemas;
2+
3+
import org.openapijsonschematools.schemas.validators.KeywordValidator;
4+
import org.openapijsonschematools.schemas.validators.TypeValidator;
5+
6+
import java.lang.reflect.Field;
7+
import java.util.HashMap;
8+
import java.util.LinkedHashSet;
9+
import java.util.Map;
10+
11+
public class SchemaValidator {
12+
static final HashMap<String, KeywordValidator> keywordToValidator = new HashMap(){{
13+
put("type", new TypeValidator());
14+
}};
15+
static PathToSchemasMap _validate(
16+
Class<SchemaValidator> cls,
17+
Object arg,
18+
ValidationMetadata validationMetadata
19+
) throws InstantiationException, IllegalAccessException {
20+
SchemaValidator clsSchema = cls.newInstance();
21+
Field[] fields = cls.getDeclaredFields();
22+
HashMap<String, Object> fieldsToValues = new HashMap<>();
23+
LinkedHashSet<String> disabledKeywords = validationMetadata.configuration().disabledKeywordFlags().getKeywords();
24+
for (Field field : fields) {
25+
String fieldName = field.getName();
26+
if (disabledKeywords.contains(fieldName)) {
27+
continue;
28+
}
29+
Object value = field.get(clsSchema);
30+
fieldsToValues.put(fieldName, value);
31+
}
32+
PathToSchemasMap pathToSchemas = new PathToSchemasMap();
33+
for (Map.Entry<String, Object> entry: fieldsToValues.entrySet()) {
34+
String jsonKeyword = entry.getKey();
35+
Object value = entry.getValue();
36+
KeywordValidator validatorClass = keywordToValidator.get(jsonKeyword);
37+
PathToSchemasMap otherPathToSchemas = validatorClass.validate(
38+
arg,
39+
value,
40+
null,
41+
cls,
42+
validationMetadata
43+
);
44+
}
45+
return pathToSchemas;
46+
}
47+
}
48+
/**
49+
* @classmethod
50+
* def _validate(
51+
* cls,
52+
* arg,
53+
* validation_metadata: ValidationMetadata,
54+
* ) -> PathToSchemasType:
55+
* """
56+
* SchemaValidator validate
57+
* All keyword validation except for type checking was done in calling stack frames
58+
* If those validations passed, the validated classes are collected in path_to_schemas
59+
* """
60+
* cls_schema = cls()
61+
* json_schema_data = {
62+
* k: v
63+
* for k, v in vars(cls_schema).items()
64+
* if k not in cls.__excluded_cls_properties
65+
* and k
66+
* not in validation_metadata.configuration.disabled_json_schema_python_keywords
67+
* }
68+
* contains_path_to_schemas = []
69+
* path_to_schemas: PathToSchemasType = {}
70+
* if 'contains' in vars(cls_schema):
71+
* contains_path_to_schemas = _get_contains_path_to_schemas(
72+
* arg,
73+
* vars(cls_schema)['contains'],
74+
* validation_metadata,
75+
* path_to_schemas
76+
* )
77+
* if_path_to_schemas = None
78+
* if 'if_' in vars(cls_schema):
79+
* if_path_to_schemas = _get_if_path_to_schemas(
80+
* arg,
81+
* vars(cls_schema)['if_'],
82+
* validation_metadata,
83+
* )
84+
* validated_pattern_properties: typing.Optional[PathToSchemasType] = None
85+
* if 'pattern_properties' in vars(cls_schema):
86+
* validated_pattern_properties = _get_validated_pattern_properties(
87+
* arg,
88+
* vars(cls_schema)['pattern_properties'],
89+
* cls,
90+
* validation_metadata
91+
* )
92+
* prefix_items_length = 0
93+
* if 'prefix_items' in vars(cls_schema):
94+
* prefix_items_length = len(vars(cls_schema)['prefix_items'])
95+
* for keyword, val in json_schema_data.items():
96+
* used_val: typing.Any
97+
* if keyword in {'contains', 'min_contains', 'max_contains'}:
98+
* used_val = (val, contains_path_to_schemas)
99+
* elif keyword == 'items':
100+
* used_val = (val, prefix_items_length)
101+
* elif keyword in {'unevaluated_items', 'unevaluated_properties'}:
102+
* used_val = (val, path_to_schemas)
103+
* elif keyword in {'types'}:
104+
* format: typing.Optional[str] = vars(cls_schema).get('format', None)
105+
* used_val = (val, format)
106+
* elif keyword in {'pattern_properties', 'additional_properties'}:
107+
* used_val = (val, validated_pattern_properties)
108+
* elif keyword in {'if_', 'then', 'else_'}:
109+
* used_val = (val, if_path_to_schemas)
110+
* else:
111+
* used_val = val
112+
* validator = json_schema_keyword_to_validator[keyword]
113+
*
114+
* other_path_to_schemas = validator(
115+
* arg,
116+
* used_val,
117+
* cls,
118+
* validation_metadata,
119+
*
120+
* )
121+
* if other_path_to_schemas:
122+
* update(path_to_schemas, other_path_to_schemas)
123+
*
124+
* base_class = type(arg)
125+
* if validation_metadata.path_to_item not in path_to_schemas:
126+
* path_to_schemas[validation_metadata.path_to_item] = dict()
127+
* path_to_schemas[validation_metadata.path_to_item][base_class] = None
128+
* path_to_schemas[validation_metadata.path_to_item][cls] = None
129+
* return path_to_schemas
130+
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.openapijsonschematools.schemas;
2+
3+
import org.openapijsonschematools.configurations.SchemaConfiguration;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.Set;
7+
8+
public record ValidationMetadata(
9+
List<Object> pathToItem,
10+
SchemaConfiguration configuration,
11+
PathToSchemasMap validatedPathToSchemas,
12+
Set<Class<?>> seenClasses
13+
) {
14+
15+
protected boolean validationRanEarlier(Class<?> cls) {
16+
Map<Class<?>, Void> validatedSchemas = validatedPathToSchemas.getOrDefault(pathToItem, null);
17+
if (validatedSchemas != null && validatedSchemas.containsKey(cls)) {
18+
return true;
19+
}
20+
if (seenClasses.contains(cls)) {
21+
return true;
22+
}
23+
return false;
24+
}
25+
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.openapijsonschematools.schemas.validators;
2+
3+
import org.openapijsonschematools.schemas.PathToSchemasMap;
4+
import org.openapijsonschematools.schemas.SchemaValidator;
5+
import org.openapijsonschematools.schemas.ValidationMetadata;
6+
7+
public interface KeywordValidator {
8+
PathToSchemasMap validate(
9+
Object arg,
10+
Object value,
11+
Object extra,
12+
Class<SchemaValidator> cls,
13+
ValidationMetadata validationMetadata);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.openapijsonschematools.schemas.validators;
2+
3+
import org.openapijsonschematools.schemas.PathToSchemasMap;
4+
import org.openapijsonschematools.schemas.SchemaValidator;
5+
import org.openapijsonschematools.schemas.ValidationMetadata;
6+
7+
import java.util.HashSet;
8+
9+
public class TypeValidator implements KeywordValidator {
10+
@Override
11+
public PathToSchemasMap validate(Object arg, Object value, Object extra, Class<SchemaValidator> cls, ValidationMetadata validationMetadata) {
12+
HashSet<Class<?>> types = (HashSet<Class<?>>) value;
13+
if (!types.contains(arg.getClass())) {
14+
throw new RuntimeException("invalid type");
15+
}
16+
return null;
17+
}
18+
}

0 commit comments

Comments
 (0)