JSON Bean Definitions
When developing your application, you might want to describe the structure of the data model you are using. This can be very important for two reasons:
- data validation: in some cases it is useful to perform a client side validation of data coming from the user or from the server.
- Data normalization: adding default values automatically can spare you a lot of effort for checking whether some data portions have been defined or not.
- Documentation: your code could be more readable if you were able to define properly the type of data that you expect in the signature of a method.
Aria Templates allows you to define your own JSON Schemas by means of Bean definitions. The framework uses these schemas extensively: just to mention a couple of examples, widget configurations and AJAX request parameters are normalized against bean definitions.
Remark: In this article the words bean definition, schema and data type are used as sinonyms.
A bean definition is a Json object that contains all the information on the data type that you want to define.
Bean definitions are grouped into packages. In order to define a package you have to use the Aria.beanDefinitions method of the Aria singleton object. Let us introduce an example of usage that will allow to explain in more detail how to specify bean definitions.
This method allows to define the package
ariadoc.snippets.core.beans.SimpleBean which contains the two bean definitions
Each bean definition contains the mandatory
$type property. It represents the parent type of the data type that you want to define. The parent type is described by means of a string like 'namespace:value', where the namespace refers to the package in which the corresponding parent bean definition is set, and the value refers to the bean definition itself. It is advisable to define the namespaces corresponding to the packages that you will be using in the
$namespaces property of the bean definition.
In the above example, the parent type of the schema
Name is the type
String whose schema is defined in the package
aria.core.JsonTypes. On top of that, the bean definition
Name has its own properties
$mandatory. This means that
Name inherits all the properties of its parent bean
aria.core.JsonTypes.String and adds or overrides the parent
This bean inheritance mechanism is the very core of beans definitions in Aria Templates. Every data type that you define (through a bean definition) will have to inherit from another data type (specified in another bean definition).
Aria Templates provides a set of built-in data types whose bean definitions are available in the package aria.core.JsonTypes. Every other schema is a descendant of one of these schemas. Technically, these types are characterized by the fact that they inherit from themselves.
There are two categories of built-in types (click on the links to learn more about them):
- simple types: String, Boolean, Integer, Float, Date, RegExp, ObjectRef, FunctionRef, JsonProperty, Enum
- complex types: Object, Array, Map, MultiTypes
When creating your bean definition, you can always include the following properties (an explanation is also available here):
$type: the mandatory parent type
$description: a short literal description of your data type. It is mandatory when inheriting directly from a built-in data type. When inheriting from a user-defined schema, it is not necessarily required.
$sample: an example
$mandatory: a boolean telling whether the element has to be provided for the Json object containing it to be valid. More detail on validation will be provided later.
$default: the default value. If the data is mandatory, it obviously does not make sense to provide a default value.
Furthermore, depending on the built-in type that you want your schema to inherit from, some additional properties can be specified (and others are automatically added by the framework). Most of them are useful for validation purposes. For example, when using the Integer type, you might want to specify the allowed range (minimum and maximum value), or when using a String type as parent you might want to specify a regular expression that it has to match in order to be valid. The basic example introduced earlier can be enhanced a little by adding extra properties to the bean definitions:
The list of extra properties that can be added to the schema according to the ancestor built-in type can be found here
In this section we will introduce more complex examples involving complex built-in data types like Arrays, Objects and MultiTypes, as well as the inheritance from a user-defined schema. Consider the following example:
The following explanatory remarks might be useful:
- when using type
$propertiesproperty is a Json object whose values are themselves bean definitions to describe the type of expected data. Thus, another bean definition is automatically available at, for example,
- When using type
$contentTypecan be specified as a schema (available at
BaseContact.$properties.address.$contentTypeis a bean definition that inherits from the user-defined bean definition
Address. In particular, it overrides only its
Consider the following example:
- the package
ariadoc.snippets.core.beans.BaseContactBeansis included in the
$namespacesproperty of the bean definition. This allows to use schemas defined in that package.
Animalschemas inherit from the type
BaseContactdefined in the
ariadoc.snippets.core.beans.BaseContactBeanspackage. They add a property to the
$propertiesof their parent type.
Groupinherits from the built-in complex type
"json:Map". The difference between a Map and an Object is that in a Map there is no constraint to the keys that can be used. The
Group.$contentTypeschema describes the type of the valid values.
Group.$contentTypeinherits from the built-in complex type
"json:MultiTypes". This special type allows to specify alternative types for a data. In this case the allowed types inherit from
This special type allows you to specify the different alternative types that are allowed.
The main purpose of defining schemas is to check the validity of data. Aria Templates allows you to perform data model validation by means of the class aria.core.JsonValidator. There are two methods of this class that you can use for this purpose:
- check: checks that the provided json object complies with a certain bean definition.
- normalize: checks that the provided json object complies with a certain bean definition and adds default values. If you look at the method signature, you will notice that it accepts a second parameter which tells whether to throw errors or not.
For performance reasons, in both cases the check is performed only when you are working in debug mode. Otherwise, the
check method always returns
true and the
normalize method only applies default values when specified in the bean definition.
Warning: At the moment Aria Templates does not support validation for schemas that inherit from
aria.core.JsonTypes.MultiTypes because normalization can be ambiguous in some cases. Hence normalization for those types of data will be automatically skipped. This feature might be added in the future.
In order to provide an example that interacts with the previously defined schemas, a class that performs some data normalization is reported here.
You can see that:
- the package
ariadoc.snippets.core.beans.ContactBeanscontaining useful bean definitions is included in the dependencies of the class. This allows to load and preprocess the bean definitions, so that they are available to the
normalizemethod is surrounded by a try...catch statement. It is a good practice to do so when the second parameter passed to the method is true.
As you can see in the previous code snippet, bean definitions allow you to associate a more adequate type to methods parameters or class properties.
It is also possible to specify class-specific bean definitions inside the
$beans key of the classDefintion configuration Json object. However, the schemas thus defined cannot be used in any way at the moment.