2

I am trying to understand when Salesforce validation is being performed on custom field types like Email. It appears that it does not occur in the controller like it does for standard fields like Strings.

For example, I've created a custom object called Superhero__c with the following two fields:

Favorite_Color__c (String)
Email_Address__c (Email)

I have also created the following custom controller:

public class SuperheroController {
  public Superhero__c mySuperhero {get;set;}
  public PageReference returnPage {get;set;}

  public SuperheroController() {
    System.debug('starting SuperheroController()');
    String id = ApexPages.currentPage().getParameters().get('id');
    Superhero__c[] superheros = [select id, email_address__c, favorite_color__c from superhero__c where id=:id];
    if (superheros.size() ==1) {
      mySuperhero = superheros[0];
    }
  }

  public PageReference doSaveSuperhero() {
    System.debug('starting doSaveSuperhero()');
    returnPage = NULL;
    boolean errorsExist = false;
    if (mySuperhero.favorite_color__c == 'yellow') 
    {
      mySuperhero.addError('Real superheros do not wear yellow - pick another color');
      errorsExist = true;
    }
    if (!errorsExist) {
      try {
        update mySuperhero;
        returnPage = Page.ShowAllSuperheros;
      } catch (Exception e) {
        ApexPages.addMessages(e);
      }
    }
    return returnPage;
  }
}

and VisualForce page:

<apex:page controller="SuperheroController" docType="html-5.0" showHeader="false">
    <apex:pageMessages />   
    <apex:form >
        Favorite color : <apex:inputField value="{!mySuperhero.Favorite_Color__c}"/><br/>
        Email address : <apex:inputField value="{!mySuperhero.Email_Address__c}"/><br/>
        <apex:commandButton action="{!doSaveSuperhero}" value="Save" Styleclass="btn btn-success"/>
    </apex:form>
</apex:page>

If I create a superhero with id=123 and access the VF page via /apex/superhero?id=123, I see the page with the favorite color and email address. If I enter yellow for the favorite color and click the Save button, I see the error message displayed on the page and I see "starting doSaveSuperhero()" in the debug log. If I enter a non-yellow color and a valid email address, I also see "starting doSaveSuperhero()" in the debug log, the object gets saved successfully and I'm redirected to the ShowAllSuperheros page. So far, so good.

But if I enter "abc" for the email address and click the Save button, I see the error message "Email Address: Invalid Email Address." and I do not see "starting doSaveSuperhero()" in the debug log. This leads me to believe that validation is occurring elsewhere - but where?

I'd like to capture the error and display a different error message but I don't know where to put this code if it doesn't get run in the doSaveSuperhero() method.

3

The validation occurs during the Visualforce bootstrap code during the validation phase. This phase occurs before your action method executes, around the same time that the initial deserialization occurs. Basically, Visualforce execution looks like this for a postback (which is what we're talking about here):

  1. Verify the session ID is valid.
  2. Load the page's metadata.
  3. Load the page's classes (like Java's classloader).
  4. Validate, decrypt, and deserialize the view state.
  5. Validate all form elements, including picklist values, numeric values, email values, etc.
  6. Call all setters in arbitrary order.
  7. Call the action method specified, if any.
  8. Call all getters in optimized load order (per page metadata).
  9. Render page's response.
  10. Serialize Viewstate.
  11. Send response to browser.

Now, I'm over-simplifying here, and I may not have the order 100% correct in terms of the bootstrap/shutdown order of operations or steps involved (1-6 and 9-11, respectively), but the point is that as a developer, we have no control over Visualforce until our first setter is called, and we lose control after our last getter is called.

This is why we can't catch errors when we exceed view state, or the 10,000 items per collection limit, or other Visualforce errors, and also why we can't detect metadata-defined errors, including using the required attribute in the page code, detecting invalid numbers in numeric fields, and so on. System validation occurs before anything that we do, and we cannot intercept this.

However, there is a potential workaround: you can intercept a form submit or AJAX request, perform your own validation in JavaScript, then allow or deny the flow to continue based on this validation. However, this leaves you to render the UI in JavaScript instead of pure Visualforce or Apex Code, which some consider a drawback.

| improve this answer | |
  • Thanks for the detailed explanation - exactly what I was looking for! – Bart Aug 28 '13 at 20:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.