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

Commit 72366d4

Browse files
authored
Java, adds Schema interface (#273)
* Improves SchemaValidatorTest * Adds beginning of Schema class * Removes unused exception * Updates SchemaValidator _validate method * Defines _validate only in SchemaValidator * Adds more schema code, adds anytypeschema and unsetanytypeschema * Fixes java warnings, fixes anytypeschema test * Adds test of map and list validation * Removes unneeded static keywords from UnsetAnyTypeSchema * Makes private methods private * Renames methods validate, romoves exception throwing
1 parent 2ae43a0 commit 72366d4

File tree

18 files changed

+1035
-67
lines changed

18 files changed

+1035
-67
lines changed

samples/client/petstore/java/.openapi-generator/FILES

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ README.md
22
pom.xml
33
src/main/java/org/openapijsonschematools/configurations/JsonSchemaKeywordFlags.java
44
src/main/java/org/openapijsonschematools/configurations/SchemaConfiguration.java
5+
src/main/java/org/openapijsonschematools/schemas/AnyTypeSchema.java
56
src/main/java/org/openapijsonschematools/schemas/CustomIsoparser.java
67
src/main/java/org/openapijsonschematools/schemas/PathToSchemasMap.java
8+
src/main/java/org/openapijsonschematools/schemas/PathToTypeMap.java
9+
src/main/java/org/openapijsonschematools/schemas/Schema.java
710
src/main/java/org/openapijsonschematools/schemas/SchemaValidator.java
11+
src/main/java/org/openapijsonschematools/schemas/UnsetAnyTypeSchema.java
812
src/main/java/org/openapijsonschematools/schemas/ValidationMetadata.java
913
src/main/java/org/openapijsonschematools/schemas/validators/KeywordValidator.java
1014
src/main/java/org/openapijsonschematools/schemas/validators/TypeValidator.java
1115
src/test/java/org/openapijsonschematools/configurations/JsonSchemaKeywordFlagsTest.java
16+
src/test/java/org/openapijsonschematools/schemas/AnyTypeSchemaTest.java
1217
src/test/java/org/openapijsonschematools/schemas/CustomIsoparserTest.java
1318
src/test/java/org/openapijsonschematools/schemas/SchemaValidatorTest.java
1419
src/test/java/org/openapijsonschematools/schemas/validators/TypeValidatorTest.java
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.openapijsonschematools.schemas;
2+
3+
import org.openapijsonschematools.configurations.SchemaConfiguration;
4+
5+
import java.time.LocalDate;
6+
import java.time.ZonedDateTime;
7+
import java.util.List;
8+
import java.util.Map;
9+
10+
record AnyTypeSchema() implements Schema {
11+
public static AnyTypeSchema withDefaults() {
12+
return new AnyTypeSchema();
13+
}
14+
15+
public static Void validate(Void arg, SchemaConfiguration configuration) {
16+
return Schema.validate(AnyTypeSchema.class, arg, configuration);
17+
}
18+
19+
public static Boolean validate(Boolean arg, SchemaConfiguration configuration) {
20+
return Schema.validate(AnyTypeSchema.class, arg, configuration);
21+
}
22+
23+
public static Integer validate(Integer arg, SchemaConfiguration configuration) {
24+
return Schema.validate(AnyTypeSchema.class, arg, configuration);
25+
}
26+
27+
public static Float validate(Float arg, SchemaConfiguration configuration) {
28+
return Schema.validate(AnyTypeSchema.class, arg, configuration);
29+
}
30+
31+
public static Double validate(Double arg, SchemaConfiguration configuration) {
32+
return Schema.validate(AnyTypeSchema.class, arg, configuration);
33+
}
34+
35+
public static String validate(String arg, SchemaConfiguration configuration) {
36+
return Schema.validate(AnyTypeSchema.class, arg, configuration);
37+
}
38+
39+
public static String validate(ZonedDateTime arg, SchemaConfiguration configuration) {
40+
return Schema.validate(AnyTypeSchema.class, arg, configuration);
41+
}
42+
43+
public static String validate(LocalDate arg, SchemaConfiguration configuration) {
44+
return Schema.validate(AnyTypeSchema.class, arg, configuration);
45+
}
46+
47+
public static <T extends Map> T validate(T arg, SchemaConfiguration configuration) {
48+
return Schema.validate(AnyTypeSchema.class, arg, configuration);
49+
}
50+
51+
public static <U extends List> U validate(U arg, SchemaConfiguration configuration) {
52+
return Schema.validate(AnyTypeSchema.class, arg, configuration);
53+
}
54+
}
Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
package org.openapijsonschematools.schemas;
22

3-
import java.util.HashMap;
3+
import java.util.LinkedHashMap;
44
import java.util.List;
55
import java.util.Map;
66

7-
public class PathToSchemasMap extends HashMap<List<Object>, Map<Class<?>, Void>> {
7+
public class PathToSchemasMap extends LinkedHashMap<List<Object>, LinkedHashMap<Class<?>, Void>> {
8+
9+
public void update(PathToSchemasMap other) {
10+
for (Map.Entry<List<Object>, LinkedHashMap<Class<?>, Void>> entry: other.entrySet()) {
11+
List<Object> pathToItem = entry.getKey();
12+
LinkedHashMap<Class<?>, Void> otherSchemas = entry.getValue();
13+
if (containsKey(pathToItem)) {
14+
get(pathToItem).putAll(otherSchemas);
15+
} else {
16+
put(pathToItem, otherSchemas);
17+
}
18+
}
19+
}
820
}
Lines changed: 8 additions & 0 deletions
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 PathToTypeMap extends HashMap<List<Object>, Class<?>> {
8+
}
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
package org.openapijsonschematools.schemas;
2+
3+
import org.openapijsonschematools.configurations.JsonSchemaKeywordFlags;
4+
import org.openapijsonschematools.configurations.SchemaConfiguration;
5+
6+
import java.lang.reflect.InvocationTargetException;
7+
import java.lang.reflect.Method;
8+
import java.math.BigDecimal;
9+
import java.time.LocalDate;
10+
import java.time.ZonedDateTime;
11+
import java.util.ArrayList;
12+
import java.util.HashSet;
13+
import java.util.LinkedHashMap;
14+
import java.util.LinkedHashSet;
15+
import java.util.List;
16+
import java.util.Map;
17+
import java.util.Objects;
18+
import java.util.Set;
19+
20+
public interface Schema<T extends Map, U extends List> extends SchemaValidator {
21+
private static Object castToAllowedTypes(Object arg, List<Object> pathToItem, PathToTypeMap pathToType) {
22+
if (arg == null) {
23+
pathToType.put(pathToItem, Void.class);
24+
return null;
25+
} else if (arg instanceof String) {
26+
pathToType.put(pathToItem, String.class);
27+
return arg;
28+
} else if (arg instanceof Map) {
29+
pathToType.put(pathToItem, Map.class);
30+
LinkedHashMap<String, Object> argFixed = new LinkedHashMap<>();
31+
for (Map.Entry<?, ?> entry: ((Map<?, ?>) arg).entrySet()) {
32+
String key = (String) entry.getKey();
33+
Object val = entry.getValue();
34+
List<Object> newPathToItem = new ArrayList<>(pathToItem);
35+
newPathToItem.add(key);
36+
Object fixedVal = castToAllowedTypes(val, newPathToItem, pathToType);
37+
argFixed.put(key, fixedVal);
38+
}
39+
return argFixed;
40+
} else if (arg instanceof Boolean) {
41+
pathToType.put(pathToItem, Boolean.class);
42+
return arg;
43+
} else if (arg instanceof Integer) {
44+
pathToType.put(pathToItem, Integer.class);
45+
return arg;
46+
} else if (arg instanceof Float) {
47+
pathToType.put(pathToItem, Float.class);
48+
return arg;
49+
} else if (arg instanceof Double) {
50+
pathToType.put(pathToItem, Double.class);
51+
return arg;
52+
} else if (arg instanceof BigDecimal) {
53+
pathToType.put(pathToItem, BigDecimal.class);
54+
return arg;
55+
} else if (arg instanceof List) {
56+
pathToType.put(pathToItem, List.class);
57+
List<Object> argFixed = new ArrayList<>();
58+
int i =0;
59+
for (Object item: ((List<?>) arg).toArray()) {
60+
List<Object> newPathToItem = new ArrayList<>(pathToItem);
61+
newPathToItem.add(i);
62+
Object fixedVal = castToAllowedTypes(item, newPathToItem, pathToType);
63+
argFixed.add(fixedVal);
64+
i += 1;
65+
}
66+
return argFixed;
67+
} else if (arg instanceof ZonedDateTime) {
68+
pathToType.put(pathToItem, String.class);
69+
return arg.toString();
70+
} else if (arg instanceof LocalDate) {
71+
pathToType.put(pathToItem, String.class);
72+
return arg.toString();
73+
} else {
74+
Class<?> argClass = arg.getClass();
75+
throw new RuntimeException("Invalid type passed in got input="+arg+" type="+argClass);
76+
}
77+
}
78+
79+
private static PathToSchemasMap getPathToSchemas(Class<Schema> cls, Object arg, ValidationMetadata validationMetadata, PathToTypeMap pathToType) {
80+
PathToSchemasMap pathToSchemasMap = new PathToSchemasMap();
81+
if (validationMetadata.validationRanEarlier(cls)) {
82+
// todo add deeper validated schemas
83+
} else {
84+
PathToSchemasMap otherPathToSchemas = SchemaValidator.validate(cls, arg, validationMetadata);
85+
pathToSchemasMap.update(otherPathToSchemas);
86+
for (LinkedHashMap<Class<?>, Void> schemas: pathToSchemasMap.values()) {
87+
Class<?> firstSchema = schemas.entrySet().iterator().next().getKey();
88+
schemas.clear();
89+
schemas.put(firstSchema, null);
90+
}
91+
Set<List<Object>> missingPaths = new HashSet<>(pathToType.keySet());
92+
missingPaths.removeAll(pathToSchemasMap.keySet());
93+
if (!missingPaths.isEmpty()) {
94+
LinkedHashMap<Class<?>, Void> unsetAnyTypeSchema = new LinkedHashMap<>();
95+
unsetAnyTypeSchema.put(UnsetAnyTypeSchema.class, null);
96+
for (List<Object> pathToItem: missingPaths) {
97+
pathToSchemasMap.put(pathToItem, unsetAnyTypeSchema);
98+
}
99+
}
100+
}
101+
return pathToSchemasMap;
102+
}
103+
104+
private static LinkedHashMap<String, Object> getProperties(Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
105+
LinkedHashMap<String, Object> properties = new LinkedHashMap<>();
106+
Map<String, Object> castArg = (Map<String, Object>) arg;
107+
for(Map.Entry<String, Object> entry: castArg.entrySet()) {
108+
String propertyName = entry.getKey();
109+
List<Object> propertyPathToItem = new ArrayList<>(pathToItem);
110+
propertyPathToItem.add(propertyName);
111+
Class<Schema> propertyClass = (Class<Schema>) pathToSchemas.get(propertyPathToItem).entrySet().iterator().next().getKey();
112+
Object value = entry.getValue();
113+
Object castValue = getNewInstance(propertyClass, value, propertyPathToItem, pathToSchemas);
114+
properties.put(propertyName, castValue);
115+
}
116+
return properties;
117+
}
118+
119+
private static List<Object> getItems(Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
120+
ArrayList<Object> items = new ArrayList<>();
121+
List<Object> castItems = (List<Object>) arg;
122+
int i = 0;
123+
for (Object item: castItems) {
124+
List<Object> itemPathToItem = new ArrayList<>(pathToItem);
125+
itemPathToItem.add(i);
126+
Class<Schema> itemClass = (Class<Schema>) pathToSchemas.get(itemPathToItem).entrySet().iterator().next().getKey();
127+
Object castItem = getNewInstance(itemClass, item, itemPathToItem, pathToSchemas);
128+
items.add(castItem);
129+
i += 1;
130+
}
131+
return items;
132+
}
133+
134+
private static Map<Class<?>, Class<?>> getTypeToOutputClass(Class<?> cls) {
135+
try {
136+
// This must be implemented in Schemas that are generics as a static method
137+
Method method = cls.getMethod("typeToOutputClass");
138+
Map<Class<?>, Class<?>> typeToOutputClass = (Map<Class<?>, Class<?>>) method.invoke(null);
139+
return typeToOutputClass;
140+
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
141+
return null;
142+
}
143+
}
144+
145+
private static Object getNewInstance(Class<Schema> cls, Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
146+
Object usedArg;
147+
if (arg instanceof Map) {
148+
usedArg = getProperties(arg, pathToItem, pathToSchemas);
149+
} else if (arg instanceof List) {
150+
usedArg = getItems(arg, pathToItem, pathToSchemas);
151+
} else {
152+
// str, int, float, boolean, null, FileIO, bytes
153+
return arg;
154+
}
155+
Class<?> argType = arg.getClass();
156+
Map<Class<?>, Class<?>> typeToOutputClass = getTypeToOutputClass(cls);
157+
if (typeToOutputClass == null) {
158+
return usedArg;
159+
}
160+
Class<?> outputClass = typeToOutputClass.get(argType);
161+
// TODO add class instantiation here
162+
return null;
163+
}
164+
165+
static Void validate(Class<?> cls, Void arg, SchemaConfiguration configuration) {
166+
return (Void) validateObject(cls, arg, configuration);
167+
}
168+
169+
static Boolean validate(Class<?> cls, Boolean arg, SchemaConfiguration configuration) {
170+
return (Boolean) validateObject(cls, arg, configuration);
171+
}
172+
173+
static Integer validate(Class<?> cls, Integer arg, SchemaConfiguration configuration) {
174+
return (Integer) validateObject(cls, arg, configuration);
175+
}
176+
177+
static Float validate(Class<?> cls, Float arg, SchemaConfiguration configuration) {
178+
return (Float) validateObject(cls, arg, configuration);
179+
}
180+
181+
static Double validate(Class<?> cls, Double arg, SchemaConfiguration configuration) {
182+
return (Double) validateObject(cls, arg, configuration);
183+
}
184+
185+
static String validate(Class<?> cls, String arg, SchemaConfiguration configuration) {
186+
return (String) validateObject(cls, arg, configuration);
187+
}
188+
189+
static String validate(Class<?> cls, ZonedDateTime arg, SchemaConfiguration configuration) {
190+
return (String) validateObject(cls, arg, configuration);
191+
}
192+
193+
static String validate(Class<?> cls, LocalDate arg, SchemaConfiguration configuration) {
194+
return (String) validateObject(cls, arg, configuration);
195+
}
196+
197+
static <T extends Map> T validate(Class<?> cls, T arg, SchemaConfiguration configuration) {
198+
return (T) validateObject(cls, arg, configuration);
199+
}
200+
201+
static <U extends List> U validate(Class<?> cls, U arg, SchemaConfiguration configuration) {
202+
return (U) validateObject(cls, arg, configuration);
203+
}
204+
205+
// todo add bytes and FileIO
206+
207+
private static Object validateObject(Class<?> cls, Object arg, SchemaConfiguration configuration) {
208+
Class<Schema> castCls = (Class<Schema>) cls;
209+
if (arg instanceof Map || arg instanceof List) {
210+
// todo don't run validation if the instance is one of the class generic types
211+
}
212+
PathToTypeMap pathToType = new PathToTypeMap();
213+
List<Object> pathToItem = new ArrayList<>();
214+
pathToItem.add("args[0]");
215+
Object castArg = castToAllowedTypes(arg, pathToItem, pathToType);
216+
SchemaConfiguration usedConfiguration = Objects.requireNonNullElseGet(configuration, () -> new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone()));
217+
PathToSchemasMap validatedPathToSchemas = new PathToSchemasMap();
218+
ValidationMetadata validationMetadata = new ValidationMetadata(
219+
pathToItem,
220+
usedConfiguration,
221+
validatedPathToSchemas,
222+
new LinkedHashSet<>()
223+
);
224+
PathToSchemasMap pathToSchemasMap = getPathToSchemas(castCls, castArg, validationMetadata, pathToType);
225+
return getNewInstance(castCls, castArg, validationMetadata.pathToItem(), pathToSchemasMap);
226+
}
227+
228+
}

0 commit comments

Comments
 (0)