Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private static Object castToAllowedTypes(Object arg, List<Object> pathToItem, Pa
Object fixedVal = castToAllowedTypes(val, newPathToItem, pathToType);
argFixed.put(key, fixedVal);
}
return new FrozenMap(argFixed);
return new FrozenMap<>(argFixed);
} else if (arg instanceof Boolean) {
pathToType.put(pathToItem, Boolean.class);
return arg;
Expand All @@ -63,7 +63,7 @@ private static Object castToAllowedTypes(Object arg, List<Object> pathToItem, Pa
argFixed.add(fixedVal);
i += 1;
}
return new FrozenList(argFixed);
return new FrozenList<>(argFixed);
} else if (arg instanceof ZonedDateTime) {
pathToType.put(pathToItem, String.class);
return arg.toString();
Expand Down Expand Up @@ -104,7 +104,7 @@ private static PathToSchemasMap getPathToSchemas(Class<Schema> cls, Object arg,
return pathToSchemasMap;
}

private static LinkedHashMap<String, Object> getProperties(Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
private static FrozenMap<String, Object> getProperties(Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
LinkedHashMap<String, Object> properties = new LinkedHashMap<>();
Map<String, Object> castArg = (Map<String, Object>) arg;
for(Map.Entry<String, Object> entry: castArg.entrySet()) {
Expand All @@ -116,7 +116,7 @@ private static LinkedHashMap<String, Object> getProperties(Object arg, List<Obje
Object castValue = getNewInstance(propertyClass, value, propertyPathToItem, pathToSchemas);
properties.put(propertyName, castValue);
}
return new FrozenMap(properties);
return new FrozenMap<>(properties);
}

private static FrozenList<Object> getItems(Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
Expand All @@ -131,37 +131,35 @@ private static FrozenList<Object> getItems(Object arg, List<Object> pathToItem,
items.add(castItem);
i += 1;
}
return new FrozenList(items);
}

private static Map<Class<?>, Class<?>> getTypeToOutputClass(Class<?> cls) {
try {
// This must be implemented in Schemas that are generics as a static method
Method method = cls.getMethod("typeToOutputClass");
Map<Class<?>, Class<?>> typeToOutputClass = (Map<Class<?>, Class<?>>) method.invoke(null);
return typeToOutputClass;
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
return null;
}
return new FrozenList<>(items);
}

private static Object getNewInstance(Class<Schema> cls, Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
Object usedArg;
if (!(arg instanceof Map || arg instanceof List)) {
// str, int, float, boolean, null, FileIO, bytes
return arg;
}
if (arg instanceof Map) {
usedArg = getProperties(arg, pathToItem, pathToSchemas);
FrozenMap<String, Object> usedArg = getProperties(arg, pathToItem, pathToSchemas);
try {
Method method = cls.getMethod("getMapOutputInstance", FrozenMap.class);
return method.invoke(null, usedArg);
} catch (NoSuchMethodException e) {
return usedArg;
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
} else if (arg instanceof List) {
usedArg = getItems(arg, pathToItem, pathToSchemas);
} else {
// str, int, float, boolean, null, FileIO, bytes
return arg;
}
Class<?> argType = arg.getClass();
Map<Class<?>, Class<?>> typeToOutputClass = getTypeToOutputClass(cls);
if (typeToOutputClass == null) {
return usedArg;
FrozenList<Object> usedArg = getItems(arg, pathToItem, pathToSchemas);
try {
Method method = cls.getMethod("getListOutputInstance", FrozenList.class);
return method.invoke(null, usedArg);
} catch (NoSuchMethodException e) {
return usedArg;
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
Class<?> outputClass = typeToOutputClass.get(argType);
// TODO add class instantiation here
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ private Void validateNumericFormat(Number arg, String format, ValidationMetadata
// there is a json schema test where 1.0 validates as an integer
BigInteger intArg;
if (arg instanceof Float || arg instanceof Double) {
Double doubleArg = (Double) arg;
if (Math.floor((Double) arg) != doubleArg) {
Double doubleArg;
if (arg instanceof Float) {
doubleArg = arg.doubleValue();
} else {
doubleArg = (Double) arg;
}
if (Math.floor(doubleArg) != doubleArg) {
throw new RuntimeException(
"Invalid non-integer value " + arg + " for format " + format + " at " + validationMetadata.pathToItem()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,35 @@ public static FrozenList<Object> validate(List<Object> arg, SchemaConfiguration
}
}

class ArrayWithOutputClsSchemaList extends FrozenList<String> {
ArrayWithOutputClsSchemaList(FrozenList<? extends String> m) {
super(m);
}

public static ArrayWithOutputClsSchemaList of(List<Object> arg, SchemaConfiguration configuration) {
return ArrayWithOutputClsSchema.validate(arg, configuration);
}
}

record ArrayWithOutputClsSchema(LinkedHashSet<Class<?>> type, Class<?> items) implements Schema {
public static ArrayWithOutputClsSchema withDefaults() {
LinkedHashSet<Class<?>> type = new LinkedHashSet<>();
// can't use ImmutableList because it does not allow null values in entries
// can't use Collections.unmodifiableList because Collections.UnmodifiableList is not public + extensible
type.add(FrozenList.class);
Class<?> items = StringSchema.class;
return new ArrayWithOutputClsSchema(type, items);
}

public static ArrayWithOutputClsSchemaList getListOutputInstance(FrozenList<? extends String> arg) {
return new ArrayWithOutputClsSchemaList(arg);
}

public static ArrayWithOutputClsSchemaList validate(List<Object> arg, SchemaConfiguration configuration) {
return Schema.validate(ArrayWithOutputClsSchema.class, arg, configuration);
}
}

public class ArrayTypeSchemaTest {
static final SchemaConfiguration configuration = new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone());

Expand Down Expand Up @@ -58,4 +87,29 @@ public void testValidateArrayWithItemsSchema() {
finalInList, configuration
));
}

@Test
public void testValidateArrayWithOutputClsSchema() {
// map with only item works
List<Object> inList = new ArrayList<>();
inList.add("abc");
ArrayWithOutputClsSchemaList validatedValue = ArrayWithOutputClsSchema.validate(inList, configuration);
List<Object> outList = new ArrayList<>();
outList.add("abc");
Assert.assertEquals(validatedValue, outList);

// map with no items works
inList = new ArrayList<>();
validatedValue = ArrayWithOutputClsSchema.validate(inList, configuration);
outList = new ArrayList<>();
Assert.assertEquals(validatedValue, outList);

// invalid prop type fails
inList = new ArrayList<>();
inList.add(1);
List<Object> finalInList = inList;
Assert.assertThrows(RuntimeException.class, () -> ArrayWithOutputClsSchema.validate(
finalInList, configuration
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,35 @@ public static FrozenMap<String, Object> validate(Map<String, Object> arg, Schema
}
}

class ObjectWithOutputTypeSchemaMap extends FrozenMap<String, Object> {
ObjectWithOutputTypeSchemaMap(FrozenMap<? extends String, ?> m) {
super(m);
}

public static ObjectWithOutputTypeSchemaMap of(Map<String, Object> arg, SchemaConfiguration configuration) {
return ObjectWithOutputTypeSchema.validate(arg, configuration);
}
}


record ObjectWithOutputTypeSchema(LinkedHashSet<Class<?>> type, LinkedHashMap<String, Class<?>> properties) implements Schema {
public static ObjectWithOutputTypeSchema withDefaults() {
LinkedHashSet<Class<?>> type = new LinkedHashSet<>();
type.add(FrozenMap.class);
LinkedHashMap<String, Class<?>> properties = new LinkedHashMap<>();
properties.put("someString", StringSchema.class);
return new ObjectWithOutputTypeSchema(type, properties);
}

public static ObjectWithOutputTypeSchemaMap getMapOutputInstance(FrozenMap<? extends String, ?> arg) {
return new ObjectWithOutputTypeSchemaMap(arg);
}

public static ObjectWithOutputTypeSchemaMap validate(Map<String, Object> arg, SchemaConfiguration configuration) {
return Schema.validate(ObjectWithOutputTypeSchema.class, arg, configuration);
}
}

public class ObjectTypeSchemaTest {
static final SchemaConfiguration configuration = new SchemaConfiguration(JsonSchemaKeywordFlags.ofNone());

Expand Down Expand Up @@ -161,4 +190,33 @@ public void testValidateObjectWithPropsAndAddpropsSchema() {
invalidAddpropMap, configuration
));
}

@Test
public void testValidateObjectWithOutputTypeSchema() {
// map with only property works
Map<String, Object> inMap = new LinkedHashMap<>();
inMap.put("someString", "abc");
ObjectWithOutputTypeSchemaMap validatedValue = ObjectWithOutputTypeSchema.validate(inMap, configuration);
LinkedHashMap<String, String> outMap = new LinkedHashMap<>();
outMap.put("someString", "abc");
Assert.assertEquals(validatedValue, outMap);

// map with additional unvalidated property works
inMap = new LinkedHashMap<>();
inMap.put("someString", "abc");
inMap.put("someOtherString", "def");
validatedValue = ObjectWithOutputTypeSchema.validate(inMap, configuration);
outMap = new LinkedHashMap<>();
outMap.put("someString", "abc");
outMap.put("someOtherString", "def");
Assert.assertEquals(validatedValue, outMap);

// invalid prop type fails
inMap = new LinkedHashMap<>();
inMap.put("someString", 1);
Map<String, Object> finalInMap = inMap;
Assert.assertThrows(RuntimeException.class, () -> ObjectWithOutputTypeSchema.validate(
finalInMap, configuration
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public interface Schema extends SchemaValidator {
Object fixedVal = castToAllowedTypes(val, newPathToItem, pathToType);
argFixed.put(key, fixedVal);
}
return new FrozenMap(argFixed);
return new FrozenMap<>(argFixed);
} else if (arg instanceof Boolean) {
pathToType.put(pathToItem, Boolean.class);
return arg;
Expand All @@ -63,7 +63,7 @@ public interface Schema extends SchemaValidator {
argFixed.add(fixedVal);
i += 1;
}
return new FrozenList(argFixed);
return new FrozenList<>(argFixed);
} else if (arg instanceof ZonedDateTime) {
pathToType.put(pathToItem, String.class);
return arg.toString();
Expand Down Expand Up @@ -104,7 +104,7 @@ public interface Schema extends SchemaValidator {
return pathToSchemasMap;
}

private static LinkedHashMap<String, Object> getProperties(Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
private static FrozenMap<String, Object> getProperties(Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
LinkedHashMap<String, Object> properties = new LinkedHashMap<>();
Map<String, Object> castArg = (Map<String, Object>) arg;
for(Map.Entry<String, Object> entry: castArg.entrySet()) {
Expand All @@ -116,7 +116,7 @@ public interface Schema extends SchemaValidator {
Object castValue = getNewInstance(propertyClass, value, propertyPathToItem, pathToSchemas);
properties.put(propertyName, castValue);
}
return new FrozenMap(properties);
return new FrozenMap<>(properties);
}

private static FrozenList<Object> getItems(Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
Expand All @@ -131,37 +131,35 @@ public interface Schema extends SchemaValidator {
items.add(castItem);
i += 1;
}
return new FrozenList(items);
}

private static Map<Class<?>, Class<?>> getTypeToOutputClass(Class<?> cls) {
try {
// This must be implemented in Schemas that are generics as a static method
Method method = cls.getMethod("typeToOutputClass");
Map<Class<?>, Class<?>> typeToOutputClass = (Map<Class<?>, Class<?>>) method.invoke(null);
return typeToOutputClass;
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
return null;
}
return new FrozenList<>(items);
}

private static Object getNewInstance(Class<Schema> cls, Object arg, List<Object> pathToItem, PathToSchemasMap pathToSchemas) {
Object usedArg;
if (!(arg instanceof Map || arg instanceof List)) {
// str, int, float, boolean, null, FileIO, bytes
return arg;
}
if (arg instanceof Map) {
usedArg = getProperties(arg, pathToItem, pathToSchemas);
FrozenMap<String, Object> usedArg = getProperties(arg, pathToItem, pathToSchemas);
try {
Method method = cls.getMethod("getMapOutputInstance", FrozenMap.class);
return method.invoke(null, usedArg);
} catch (NoSuchMethodException e) {
return usedArg;
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
} else if (arg instanceof List) {
usedArg = getItems(arg, pathToItem, pathToSchemas);
} else {
// str, int, float, boolean, null, FileIO, bytes
return arg;
}
Class<?> argType = arg.getClass();
Map<Class<?>, Class<?>> typeToOutputClass = getTypeToOutputClass(cls);
if (typeToOutputClass == null) {
return usedArg;
FrozenList<Object> usedArg = getItems(arg, pathToItem, pathToSchemas);
try {
Method method = cls.getMethod("getListOutputInstance", FrozenList.class);
return method.invoke(null, usedArg);
} catch (NoSuchMethodException e) {
return usedArg;
} catch (InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
Class<?> outputClass = typeToOutputClass.get(argType);
// TODO add class instantiation here
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ public class FormatValidator implements KeywordValidator {
// there is a json schema test where 1.0 validates as an integer
BigInteger intArg;
if (arg instanceof Float || arg instanceof Double) {
Double doubleArg = (Double) arg;
if (Math.floor((Double) arg) != doubleArg) {
Double doubleArg;
if (arg instanceof Float) {
doubleArg = arg.doubleValue();
} else {
doubleArg = (Double) arg;
}
if (Math.floor(doubleArg) != doubleArg) {
throw new RuntimeException(
"Invalid non-integer value " + arg + " for format " + format + " at " + validationMetadata.pathToItem()
);
Expand Down
Loading