The ValidatorService
provides the link between the REST framework and the validator framework. You can invoke the ValidatorService
directly by using the invokeValidator
method or by using the methods available in the RestUtils
class.
If the endpoint has been annotated with isValidatedByFramework=true
, then the REST framework invokes the ValidationService
using the invokeValidator
method. For example:
/** * Main entry point for validating an input object when * wanting to allow the framework to control selection of * validator, target bean, type of update etc. * @param pInputObject object to validate */ public void invokeValidator(Object pInputObject)
The service tries to obtain the validator to use for a particular object by obtaining the validatorId
endpoint setting from the RestContext
.
The ValidationService
provides access to the validator framework for the validation of incoming JSON JAX-RS messages and, optionally, the updating of target beans or repository items.
Whenever a PUT, POST or Patch operation occurs, its input is run through a validator service. The rules for this validation are configured using the payload schema XML file. Validation can be performed automatically by the framework or can be done manually using the endpoint. Validators are associated with an endpoint by using the validatorId
endpoint annotation, which references the unique ID associated with a schema in the validation XML file. If validation fails, a 400 BAD_REQUEST response is returned to the client along with details of the property or properties whose values are invalid.
For additional information on the payload schema, refer to the Working with the Payload Schema section.
Configuring Automatic Validation
The ValidatorManager
manages the validation of property values and maintains a Hashtable for the creating and updating of mapping from a property name to a validator. It also provides code to update one dynamic bean from another, enabling a way of going from input endpoint JSON to updating objects.
Validation is automatically performed for any update request by the ValidatorManager
component using the defined schema for the endpoint. In addition to rejecting invalid input, the validation process also determines any sets of changes that the endpoint may need to apply, and can pre-populate target beans directly with the input values. The validation process first tries to GET the latest version of the resource. While validating against the schema, the validation process can also update the resource with the values taken from the input. For collection resources, elements are matched against the input by comparing ID fields.
If you want validation to occur automatically, your endpoints must specify a validatorId
endpoint annotation. If you do not want the framework to validate an endpoint, change the isValidatedByFramework
endpoint annotation from its default to false
. The automatic update of the target beans by the validation process can be disabled using the @Endpoint
annotation updateTarget
attribute. RestUtils
also has a method that you can use to manually invoke the validation process if automatic validation has been disabled for an endpoint. For additional information on validation, refer to the Working with the Payload Schema section.
Configuring Manual Validation
You can manually handle input validation by using the validateInputObject
utility method that is available in RestUtils
.
The payload schema framework can also provide additional support for an endpoint, depending on the endpoint type. For example, an endpoint can create a new resource or update an existing resource. If the message validates successfully, then a requestUpdateInfo
property is populated on the current RestContext
.
Use the endpoint annotation to assign a validator to a specific endpoint.
public @interface Endpoint { ... String validatorId() default NULL_STRING; ... }
This allows a validator to be associated to an endpoint:
@Endpoint(id="test.addorders.orderId", validatorId="type.id.addItem") public RepresentationModel defaultGet(@PathParam("orderId") String pOrderId){
Working with Endpoints that Create Resources
For endpoints that create resources, the ResourceUpdateInfo
, which is available using the RestUtils.getRestUtils().getResourceUpdateInfo()
method, can provide validated input in the form of a map or an actual instance of the bean. Additionally, you can use the getUpdates()
method to get the actual single item to be created.
If getUpdates
is set to true
, the framework tries to create an instance of the bean or repository item defined by the validator. The factory
attribute can identify a Nucleus component or Java class that can create an instance of the target class. This may be required where the target instance requires initialization before it can be used. The Java class referenced by the factory
attribute must implement the atg.service.validator.BeanInstanceFactory
interface. For example:
<validator id="type.id-addItem"> <bean class="atg.commerce.order.SomeItemType" factory="nucleus:/atg/commerce/order/restresources/SomeItemTypeCreator"/> ... </validator>
If getUpdates
is set to false
, the ResourceUpdateInfo
contains the validated input in the form of a java.utl.Map
, which may be more convenient for the endpoint than working with the raw org.json.JSONObject
. However the raw org.json.JSONObject
is still available from the RestContext.inputJson
property.
Working with Endpoints that Update Resources
For endpoints that update existing resources, the framework can validate and then apply incoming changes to the target bean.
Use the getMembersUpdateInfos()
method of the ResourceUpdateInfo
object to get information on the updated for a collection. Use the getTarget
method of the ResourceUpdateInfo
object to get information on the update of a single resource.
For detailed information on validation, refer to the Working with the Payload Schema section.
Reusing Validators
Both schema
and bean-property
properties allow the validators to be reused with the use-validator-id
attribute. When this attribute is specified, the validator code retrieves the properties and bean-properties of the referred validator. The filtering code must inspect the schema
and bean-property
for the use-validator-id
and, if populated, retrieve the properties and bean properties from that validator.
For example:
<validator id="orders.id-Other" use-validator-id="/orders/{id}-Summary"> <bean class="atg.TestOrder"/> </validator> <validator id="orders.id-AndAnother" include-all-simple="true"> <bean class="atg.TestOrder"/> <bean-property name="commerceItems" use-validator-id="orders. commerceitems.id-Summary"/> </validator>
Validating Collections
Validators can be configured for beans and bean properties. To do this, set the treat-container-as-bean
attribute of the schema
and bean-property
properties. The key/value pairs of the map are written to the output according to the schema
and bean-property
configuration, which will refer to the map keys.
Note: There may be errors upon startup of the ValidatorRegstry
component since Map has neither description nor quantity properties.
The following is an example of using the treat-container-as-bean
attribute:
<validator id="orders.id-Other" treat-container-as-bean="true"> <bean class="java.util.Map"/> <property name="description" hidden="false"/> <property name="quantity" hidden="true"/> </validator>
For additional information on the treat-container-as-bean
attribute, refer to the Working with the Payload Schema section.
Use the pseudo-property value
when you do not want a map to be treated as a dynamic bean. This configuration is applied to all values of the map when producing output:
<validator id="orders.commerceItems.id-Test" treat-container-as-bean="false"> <bean class="java.util.Map"/> <bean-property name="value"> <bean class="atg.TestCommerceItem"/> <property name="id" hidden="false"/> <property name="quantity" hidden="true"/> </bean-property> </validator>
When working with collections, use the element
pseudo-property. The configuration is applied to all elements of the collection when producing output:
<validator id="orders.commerceItems.id-Test"> <bean class="java.util.Collection"/> <bean-property name="element"> <bean class="atg.TestCommerceItem"/> <property name="id" hidden="false"/> <property name="quantity" hidden="true"/> </bean-property> </validator>
If the value
or element
pseudo-property is not specific but the output code detects a map or collection, the framework attempts to apply the schema
or bean-property
configuration to all of the values or elements of the collection.
Configuring Timestamps
By default, timestamp
properties returned in output are configured as Long. You can create a custom instance of a PropertyCustomizer
that converts the Long format to a formatted date using the request locale. For example:
<property name="lastModifiedTime" writable="false" property- customizer="/atg/dynamo/service/filter/bean/CustomDatePropertyCustomizer"/>