Extensible type checking framework for arbitrary objects
To use prop-types, add the following dependency:
<dependency>
<groupId>com.factor18.oss</groupId>
<artifactId>prop-types</artifactId>
<version>VERSION</version>
</dependency>PropTypes is a powerful tool for validating arbitrary objects.
PropTypes exports a range of validators that can be used to make sure the data you receive is valid.
Here are some examples which showcase the possibilities using a simple integer validator
PropType schema = PInteger.builder().defaultValue(10).required(true).build();
// 123 will be assigned to 'a'
Integer a = (Integer) schema.parse(123);
// 10 will be assigned to 'b'
Integer b = (Integer) schema.parse(null);
// will throw InvalidPropTypeException
Integer c = (Integer) schema.parse("invalid");PropType schemaWithoutRequired = PInteger.builder().defaultValue(10).required(false).build();
// 123 will be assigned to 'd'
Integer d = (Integer) schemaWithoutRequired.parse(123);
// null will be assigned to 'e'
Integer e = (Integer) schemaWithoutRequired.parse(null);
// will throw InvalidPropTypeException
Integer f = (Integer) schemaWithoutRequired.parse("invalid");PropType schemaWithoutDefaultValue = PInteger.builder().required(true).build();
// 123 will be assigned to 'g'
Integer g = (Integer) schemaWithoutDefaultValue.parse(123);
// will throw InvalidPropTypeException
Integer h = (Integer) schemaWithoutDefaultValue.parse(null);
// will throw InvalidPropTypeException
Integer i = (Integer) schemaWithoutDefaultValue.parse("invalid");Default value is only used when required is true. So schemaWithoutRequired is the same as schemaWithoutDefaultValueAndRequired. This behaviour can be overriden by creating custom prop-types, which we will look at further in this document.
PropType schemaWithoutDefaultValueAndRequired = PInteger.builder().required(false).build();
// 123 will be assigned to 'j'
Integer j = (Integer) schemaWithoutDefaultValueAndRequired.parse(123);
// null will be assigned to 'k'
Integer k = (Integer) schemaWithoutDefaultValueAndRequired.parse(null);
// will throw InvalidPropTypeException
Integer l = (Integer) schemaWithoutDefaultValueAndRequired.parse("invalid");PInteger, PFloat, PBoolean, PString, PObject have the same properties.
required -> to validate if the given value is required or not
defaultValue -> if required and the value is null, it will be replaced with this value
PArray, PShape are special. They allow us to compose complex structures.
As the name suggests, it is used to define arrays.
PArray has two additional properties items, additionalItems
Lets say you want to validate a List which has this list [ 1, true, "sample", 2.0 ].
The items property comes in handy. It allows you to define the order of prop-types to be used to validate the List.
PropType schema = PArray.builder().items(Lists.newArrayList(
PInteger.builder().required(true).build(),
PBoolean.builder().required(true).build(),
PString.builder().required(true).build(),
PFloat.builder().required(true).build()
)).required(true).build();
List<Object> a = schema.parse(Lists.newArrayList(1, true, "as", 2.0));There might be a use case where you aren't aware the number items of the list. additionalItems will help you express such lists.
PropType schema = PArray.builder().additionalItems(
PInteger.builder().required(true).build()
).required(true).build();
List<Integer> a = (List<Integer>) schema.parse(Lists.newArrayList(1, 2, 3, 4));additionalItems can be clubbed with items to express lists like [1, true, "as", 2.0, 2, 3, 4, 5, 6, ... ]
PropType schema = PArray.builder().items(Lists.newArrayList(
PInteger.builder().required(true).build(),
PBoolean.builder().required(true).build(),
PString.builder().required(true).build(),
PFloat.builder().required(true).build()
)).additionalItems(
PInteger.builder().required(true).build()
).required(true).build();
List<Object> a = (List<Object>) schema.parse(Lists.newArrayList(1, true, "as", 2.0, 1, 2, 3, 4, 5, 6));It allows you to define the structure of a Map
PShape has a special property schema, which is a map of String:PropType. It is used to validate Maps like
{
"integer": 10,
"float": 2.0,
"boolean": true,
"string": "sample",
"object": "any random object",
"array": [ 1, 2, 3, 4, 5 ]
}The below mentioned schema validates the above mentioned data
Map<String, PropType> shape = Maps.newHashMap();
shape.put("integer",
PInteger.builder().required(true).build()
);
shape.put("float",
PFloat.builder().required(true).build()
);
shape.put("boolean",
PBoolean.builder().required(true).build()
);
shape.put("string",
PString.builder().required(true).build()
);
shape.put("object",
PObject.builder().required(true).build()
);
shape.put("array",
PArray.builder().additionalItems(
PInteger.builder().required(true).build()
).required(true).build()
);
PropType schema = PShape.builder().schema(shape).required(true).build();
Map<String, Object> data = Maps.newHashMap();
data.put("integer", 10);
data.put("float", 2.0);
data.put("boolean", true);
data.put("string", "sample");
data.put("object", "any random object");
data.put("array", Lists.newArrayList(1, 2, 3, 4, 5));
Map<String, Object> a = (Map<String, Object>) schema.parse(data);You can create your custom prop-types by implementing the PropType interface
public interface PropType {
String getType();
Object parse(Object value) throws InvalidPropTypeException;
Boolean isRequired();
Object getDefaultValue();
boolean isValid(Object value);
}prop-types is released under the Apache 2 License. Check LICENSE file for more information.