Customize attribute validation


In this topic


About customizing attribute validation

Attributes in a table or feature class are validated based on the attribute's domains and subtypes. A class extension is developed, deployed, and applied to the table or feature class to implement complex or specialized attribute validation with other validations specified by domains and subtypes on its attributes. 
For more information about class extensions, see Getting started with class extensions.
The following are some validations implemented by the class extension:
  • Validation of text attributes using string functions (such as, string comparisons) or regular expressions 
  • Validation of attributes constrained by a combination of multiple fields
  • Validation of attributes using external sources, such as a data dictionary table or the local file system

Implementation

The following scenario discusses a complex attribute validation that can be achieved by implementing a class extension. For more information about the basics of implementing class extensions, see How to implement class extensions.
Scenario—Validate the e-mail text attribute field name exists and ensure its value is a valid e-mail address that matches the [\w-]+@([\w-]+\.)+[\w-]+ regular expression. For example, mlucic@bostonbruins.com is valid, but mlucic@boston bruins.com is not, because a space is not allowed in the e-mail address.

Develop the class extension

To implement the scenario, develop a class extension that implements the IObjectClassValidation interface and customize the attribute validation. The validateRow() and validateField() methods are defined by IObjectClassValidation.
  • The validateRow() method is called after the geodatabase native validation has been completed. Typically, validateRow() will be implemented to call validateField() on the attribute requiring custom validation. If the class extension customizes validation of more than one attribute (field) in a table or feature class, invoke the validateField() method for every attribute. 
  • The validateField() method implementation is customized to validate the attribute (field) value as specified in the scenario.
The validateRow() and validateField() methods have string return types. If the validation is successful, an empty string is returned; otherwise, a description of the error is returned.
See the following items and code example (also available as a sample):
  • The @ArcGISExtension annotation of the Java class and the category attribute value ArcGISCategories.GeoObjectClassExtensions
  • The Java class implements the IObjectValidation interface
  • The init() method implementation receives the object reference from its class helper parameter and finds the field index of the applicable e-mail attribute
  • The validateRow() method implementation invokes the validateField() method for the applicable e-mail Attribute(Field)
  • The validateField() method implementation validates the e-mail field value with the regular expression
[Java]
package classextension;

import java.io.IOException;
import java.util.regex.*;
import com.esri.arcgis.geodatabase.*;
import com.esri.arcgis.interop.AutomationException;
import com.esri.arcgis.interop.extn.*;
import com.esri.arcgis.system.IPropertySet;
@ArcGISExtension(categories = {
    ArcGISCategories.GeoObjectClassExtensions
}

)public class EmailValidationExtension implements IClassExtension,
    IObjectClassExtension, IFeatureClassExtension, IObjectClassValidation{
    /**
     * The name of the e-mail address field to be validated.
     */
    private static final String EMAIL_FIELD_NAME = "email";
    /**
     * A regular expression pattern representing an e-mail address.
     */
    private static final String EMAIL_REGEX = "[\\w-]+@([\\w-]+\\.)+[\\w-]+";
    /**
     * The index of the e-mail address field in the extension's class. A value of –1
     * indicates that it could not be found during initialization.
     */
    int emailFieldIndex =  - 1;
    /**
     * The regex pattern used to evaluate e-mail field values.
     */
    private Pattern regexPattern = null;
    /************************************************************************************************
     * IClassExtension members
     ************************************************************************************************/
    /**
     * Initializes the extension, passing in a reference to its class helper and its extension properties.
     */
    public void init(IClassHelper classHelper, IPropertySet extensionProperties)
        throws IOException, AutomationException{
        // Get the index of the e-mail field.
        IClass baseClass = classHelper.esri_getClass();
        emailFieldIndex = baseClass.findField(EMAIL_FIELD_NAME);
        // Compile a regex pattern for e-mail validation.
        regexPattern = Pattern.compile(EMAIL_REGEX);
    }
    /**
     * Called when the extension's class is being disposed of from memory.
     */
    public void shutdown()throws IOException, AutomationException{
        // Do nothing.
    }
    /************************************************************************************************
     * IObjectClassValidation members
     ************************************************************************************************/
    /**
     * Validates the row.
     */
    public String validateRow(IRow row)throws IOException, AutomationException{
        return validateField(row, EMAIL_FIELD_NAME);
    }
    /**
     * Validates the row's specified attribute. 
     */
    public String validateField(IRow row, String fieldName)throws IOException,
        AutomationException{
        // Make sure the e-mail field is the field being validated and that its index was
        // successfully determined during validation.
        if (fieldName.equalsIgnoreCase(EMAIL_FIELD_NAME) && emailFieldIndex !=  - 1){
            try{
                // Check that the field value is not null before matching. 
                Object emailObj = row.getValue(emailFieldIndex);
                if (emailObj != null){
                    // Try to match the value with the regular expression matcher.
                    String emailAddress = (String)emailObj;
                    Matcher matcher = regexPattern.matcher(emailAddress);
                    if (matcher.matches()){
                        // The value is a match, return null to indicate it is valid.
                        return null;
                    }
                    else{
                        // The value is not a match.
                        return emailAddress.concat(" is not a valid email address.");
                    }
                }
            }
            catch (Exception exc){
                return "An error occurred during validation: " + exc.getMessage();
            }
        }
        return null;
    }
}
After developing the Java class to deploy the class extension, compile the .java file and bundle the .class file as a Java Archive (JAR) file.

Deploy the class extension

To deploy the class extension, the created JAR file is placed in <ArcGIS Install Dir>/java/lib/ext of the ArcGIS application accessing the object class. The ArcGIS application (ArcGIS Engine, ArcMap, ArcCatalog, and ArcGIS Server) recognizes the class extension by its annotation when started. If the ArcGIS application is running, restart it after the class extension is deployed.

Apply the class extension

The created class extension can be applied to any object class. For more information about how a class extension can be applied, see Apply class extensions.
The following code example shows how to apply the extension programmatically to an existing class:
[Java]
//Import the created class extension class files.
//Do not forget to add the class extension JAR file to the class path.
import classextensions.*;

//Declare the class variable.
private static final String EMAIL_FIELD_NAME = "email";

public void applyClassExtension(FeatureClass fc){
    try{
        //Verify the FieldName attribute is available in the feature class.
        //Verify that no other class extension is applied to the feature class.
        if ((fc.findField(EMAIL_FIELD_NAME) >  - 1) && (fc.getEXTCLSID() == null)){
            fc.changeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);
            // Create a unique identifier object (UID) and assign the extension.
            UID extUID = new UID();
            //Notice, the fully qualified class name of the created class extension Java class  
            //is passed as a parameter.
            extUID.setValue(classextension.EmailValidationExtension.class.getName());

            //Apply the class extension to the feature class.
            fc.alterClassExtensionCLSID(extUID, null);
            fc.changeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
        }
    }
    catch (IOException e){

        e.printStackTrace();
    }

Validate attributes

A geodatabase has an "optimistic" view of the data; therefore, data validation is not performed when the data is created, stored, or edited (data is later evaluated by the user). The custom attribute validation of an object or feature class is validated at a user specified time with other out-of-the-box validation.
The following shows the order in which data is validated:
  1. Subtype validation
  2. Out-of-the-box attribute rules (domains) validation
  3. Network connectivity rules (if network features) validation 
  4. Relationship rules validation
  5. Custom validation defined in the class extension
Validation is interrupted when any of the preceding validation items return false. The data behavior of object and feature classes, including its custom behavior implemented by class extensions, can be validated programmatically using the IValidate.validate() or IValidation.validate() methods.
While the IValidation interface validates a complete set of rows at once, IValidate operates on one row. This can be useful if you want to validate the row immediately.
The following code example shows how you can validate the e-mail attribute implemented by the class extension with other validations. If the e-mail attribute is not valid, the console output of the code example will be "Not Valid :mlucic@boston bruins is not a valid e-mail."
[Java]
//Validates the input feature.
private void validateFeature(IFeature inFeature){
    IValidate validate = (IValidate)inFeature;
    String[] errorMessage = new String[1];
    boolean valid = false;
    try{
        valid = validate.validate(errorMessage);
    }
    catch (IOException e){
        e.printStackTrace();
    }
    if (!valid){
        System.out.println("Not Valid :" + errorMessage[0]);
    }
}

Attributes of the feature class validation

Feature class attributes of the feature class can also be validated in ArcMap through its editing interface by doing the following steps:
  1. Open the feature class in ArcMap.
  2. Click the Edit () tool on the Editing toolbar.
  3. Select the features you want to validate. You can only validate features from a geodatabase.
  4. Click Editor, then click Validate Features. See the following screen shot:

  5. If your selection contains invalid features, a message appears with the number of invalid features. Only those features that are invalid will remain selected. Click OK on the message dialog box.
  6. Click one of the invalid features.
  7. Repeat Step 3. A message appears indicating why the feature is invalid.
  8. Click OK.
  9. Click the Attributes () button to view the attributes of the invalid features.
  10. Click the values that are invalid and change them.
  11. Close the Attributes dialog box.
  12. Repeat Steps 6 through 11 for all invalid features.
  13. Repeat Steps 2 through 3. If all features are valid, a message appears indicating that all features are valid.
  14. Click OK on the message dialog box.


See Also:

How to implement class extensions
Scenario: Customize object event behavior
Scenario: Customize relationship behavior
Apply class extensions