Create a Custom Validator

Overview

This page describes how to implement a custom validator for use in document types within Bloomreach Content.

When to Use

Create a custom validator when the built-in validators do not meet your validation requirements for fields, compound fields, or entire document types.

Note: Validation is available only for document types with workflow enabled (hippostdpubwf:document).

Validator Scope

Validators can be applied at different levels. The following table summarizes each scope, what it validates, where violations are reported, and how to configure it:

Validator ScopeValidatesReportsConfigured
fieldValue of a single fieldBelow the fieldPer field
compoundValues of multiple fields in a compoundAbove the compoundPer field or compound type
documentValues of multiple fields in a documentAbove the document (field highlighting not supported)Per document type

Implementation Steps

1. Create the Validator Class

Implement a class that extends org.onehippo.cms.services.validation.api.Validator.

The following example shows a field-scoped RegExpValidator:

public class RegExpValidator implements Validator<String> { private static final String PATTERN_KEY = "regexp.pattern"; private final Pattern pattern; public RegExpValidator(final Node config) { try { pattern = Pattern.compile(config.getProperty(PATTERN_KEY).getString()); } catch (RepositoryException e) { throw new ValidationContextException("Cannot read required property '" + PATTERN_KEY + "'", e); } } public Optional<Violation> validate(final ValidationContext context, final String value) { if (pattern.matcher(value).find()) { return Optional.empty(); } return Optional.of(context.createViolation()); } }

Your validator class must implement:

  • A public constructor: The constructor must be public to allow instantiation via reflection. It can have no parameters or a single javax.jcr.Node parameter for validator-specific configuration.
  • The validate method: This method performs validation and returns a violation if the value is invalid. The value type should match the JCR property type (String, Date, Long, etc.). For compound fields and documents, the value is a javax.jcr.Node. The ValidationContext parameter provides access to:
    • JCR name (e.g., "myproject:title")
    • JCR type (e.g., "String" or "myproject:mycompound")
    • Field type (e.g., "Text")
    • User locale (e.g., "en")
    • User time zone (e.g., "Europe/Amsterdam")
    • Parent node
    • Document node

Note: The validate method must be thread-safe.

2. Register the Validator

Add a new hipposys:moduleconfig node to the validation service configuration at /hippo:configuration/hippo:modules/validation/hippo:moduleconfig.

Use your project namespace in the validator name to distinguish it from built-in validators.

Example configuration for an email validator:

/hippo:configuration/hippo:modules/validation/hippo:moduleconfig/myproject:email: jcr:primaryType: hipposys:moduleconfig hipposys:className: org.onehippo.cms.services.validation.validator.RegExpValidator regexp.pattern: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$

3. Assign the Validator to a Field or Document Type

To assign a validator at the field level, locate the field node in your document type definition at /hippo:namespaces/[namespace]/[documenttype]/hipposysedit:nodetype/hipposysedit:nodetype/[fieldname].

Add the validator node name (from your configuration) to the multi-valued hipposysedit:validators property.

Example for an 'Email' field in the 'author' document type:

/hippo:namespaces/myproject/author/hipposysedit:nodetype/hipposysedit:nodetype/email: jcr:primaryType: hipposysedit:field hipposysedit:mandatory: false hipposysedit:multiple: false hipposysedit:ordered: false hipposysedit:path: myproject:email hipposysedit:primary: false hipposysedit:type: String hipposysedit:validators: [myproject:email]

To assign a validator at the document type level, add the validator node name to the hipposysedit:validators property of the document type node at /hippo:namespaces/[namespace]/[documenttype]/hipposysedit:nodetype/hipposysedit:nodetype.

4. Configure Validation Messages

Validation messages are stored as repository resource bundles at /hippo:configuration/hippo:translations/hippo:cms/validators/.

For each supported language, add a translation property with the same name as your validator configuration. Use clear, imperative sentences for messages.

Example:

/en: jcr:primaryType: hipposys:resourcebundle myproject:email: Enter a valid email address escaped: 'Do not use these characters: < > & '' "' image-references: Select an image non-empty: Enter a value

To define multiple violation messages for a validator, use the format <validator-name>#<subKey>:

/en: jcr:primaryType: hipposys:resourcebundle myproject:customvalidator: Custom validation message myproject:customvalidator#alternate: Alternate validation message

Within your validator class, use context.createViolation() to access the default violation message, or context.createViolation(String subKey) for alternate messages.

Verification

After configuration, verify that your custom validator works as expected. When a validation error occurs, the document editor displays the corresponding message.

Document editor showing email validation error message

Troubleshooting

Symptom:
The document editor displays "This document has 1 error," but no validation error message appears below the affected field.

Document editor showing one error above Name and Email fields

Cause:
The frontend:references and frontend:services properties of the document type editor template's _default_ node are missing the "validator.id" value. This value is typically added by the document type editor, but it may be missing due to manual YAML editing, upgrades, or customizations.

Resolution:
Add "validator.id" to both the frontend:references and frontend:services properties of the _default_ node in the editor template.

Example for the "author" document type in the "myproject" project:

/hippo:namespaces/myproject/author/editor:templates/_default_: jcr:primaryType: frontend:plugincluster frontend:properties: [mode] frontend:references: [wicket.model, model.compareTo, engine, validator.id] frontend:services: [wicket.id, validator.id]
Share Feedback
Page: /build/plugins/core-plugins/create-a-custom-field-validator
Section: Build
Category *