Skip to content
CMO & CTO
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

  • Digital Experience
    • Experience Strategy
    • Experience-Driven Commerce
    • Multi-Channel Experience
    • Personalization & Targeting
    • SEO & Performance
    • User Journey & Behavior
  • Marketing Technologies
    • Analytics & Measurement
    • Content Management Systems
    • Customer Data Platforms
    • Digital Asset Management
    • Marketing Automation
    • MarTech Stack & Strategy
    • Technology Buying & ROI
  • Software Engineering
    • Software Engineering
    • Software Architecture
    • General Software
    • Development Practices
    • Productivity & Workflow
    • Code
    • Engineering Management
    • Business of Software
    • Code
    • Digital Transformation
    • Systems Thinking
    • Technical Implementation
  • About
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

JSF Validation in Practice: Friendly Errors

Posted on August 1, 2010 By Luis Fernandez

Why do our forms still feel like they are scolding us, and what would it take for JSF validation to sound like a friendly teammate instead of a compiler error?

Most of us ship forms that catch mistakes, yet too many apps answer with vague red text and a full page refresh that makes people sigh. With JavaServer Faces 2 and Facelets we already have the pieces to do better. The trick is not a secret library or a design trend. The trick is to keep the user in the flow, write messages a person can understand, and wire the JSF validation features so the interface reacts quickly. Today I will show what I use on real projects to turn angry errors into friendly errors without heavy ceremony.

Think less about rules and more about guidance.

Start with labels and single field messages

JSF gives you h:message for a field and h:messages for the page. Use both. Field messages sit next to inputs and prevent eye ping pong. Page messages handle cross field checks or surprises. Give every input a label so default texts can include it. In practice I set the component label attribute or add an f:attribute name=”label” so standard validators read a human name instead of the component id. Then I keep the message short and specific. No capitals, no tech jargon, just what went wrong and what to do next.

Your users should not need to hunt for the error.

<h:form id="signupForm">
  <h:panelGrid columns="2">
    <h:outputLabel for="email" value="Email"/>
    <h:inputText id="email" value="#{userBean.email}" 
                 label="Email" required="true"
                 requiredMessage="Email is required" 
                 validatorMessage="Please enter a valid email">
      <f:validateRegex pattern="^[^@]+@[^@]+\\.[^@]+$"/>
    </h:inputText>
    <h:message for="email" styleClass="msg msg_error"/>

    <h:outputLabel for="age" value="Age"/>
    <h:inputText id="age" value="#{userBean.age}" label="Age"
                 converterMessage="Age must be a number">
      <f:validateLongRange minimum="13" maximum="120"/>
    </h:inputText>
    <h:message for="age" styleClass="msg msg_error"/>
  </h:panelGrid>

  <h:messages globalOnly="true" styleClass="msg msg_warn"/>
  <h:commandButton value="Create account" action="#{userBean.create}"/>
</h:form>

requiredMessage, converterMessage, and validatorMessage let you speak like a person and not a stack trace.

Centralize words with a message bundle

Hard coded messages are easy to start and hard to keep consistent. Put your words in a bundle so the tone stays the same and translation is not a scramble later. JSF already knows how to load a message bundle. You can also override default validator texts by adding the keys that JSF looks for. That means you can keep labels short in your pages and keep the full friendly sentence in a properties file. It also means the same field reads the same across forms, which is one of those small touches that make the app feel steady.

<faces-config version="2.0">
  <application>
    <message-bundle>com.example.i18n.Messages</message-bundle>
  </application>
</faces-config>
# com/example/i18n/Messages.properties
Email_required=Email is required
Email_invalid=That does not look like a valid email
Age_converter=Age must be a number
javax.faces.component.UIInput.REQUIRED={0} is required
javax.faces.validator.LengthValidator.MINIMUM={1} must be at least {0} characters
javax.faces.validator.LengthValidator.MAXIMUM={1} must be at most {0} characters

Now your pages can stay clean while the copy lives in one place.

Give feedback early with f:ajax

Full submits for every typo are a drag. With JSF 2 we can attach f:ajax to an input and update only its message and maybe the submit button state. That keeps the user on the same page while still running server side validators and converters. The key is to keep the Ajax target small. Update the message span near the field and possibly a help block, not the whole form. This pattern delivers the feeling of a smart client without custom JavaScript and without inventing your own validation rules twice.

Fast feedback beats a long lecture.

<h:inputText id="email" value="#{userBean.email}" label="Email" required="true">
  <f:ajax event="blur" render="emailMsg submitBtn"/>
  <f:validateRegex pattern="^[^@]+@[^@]+\\.[^@]+$"/>
</h:inputText>
<h:message id="emailMsg" for="email" styleClass="msg msg_error"/>

<h:commandButton id="submitBtn" value="Create account" 
                 disabled="#{not facesContext.maximumSeverity.ordinal le 1}"/>

Write custom validators with a human voice

Stock validators are great but you will meet rules that are all yours. When you write a validator, craft the FacesMessage with a short summary and a helpful detail. The summary should be a quick hint that works next to the field. The detail can expand when rendered in the global list. This dual tone lets you stay brief near the input while still giving clear steps at the top of the form. Keep the severity levels consistent so the user can tell info from error at a glance.

@FacesValidator("usernameAvailable")
public class UsernameAvailableValidator implements Validator {

  @Inject
  private UserService userService;

  @Override
  public void validate(FacesContext ctx, UIComponent comp, Object value)
      throws ValidatorException {
    String username = value != null ? value.toString() : "";
    if (userService.exists(username)) {
      FacesMessage msg = new FacesMessage(
          FacesMessage.SEVERITY_ERROR,
          "That username is taken",
          "Try a different username. Tips: add a number or use your nickname");
      throw new ValidatorException(msg);
    }
  }
}

You can also back this with Bean Validation on your model and let JSF pick up the constraints, which keeps rules in one place.

Arrange and style messages so they help

Content is half the story. The other half is where the message shows and how it looks. Put the field message right next to the input and give it a small color cue. Put the global messages in a box at the top so people do not miss cross field problems. Use icons if you can, but do not rely on color alone. Keep the tone calm. No red walls. No caps. Just a gentle nudge that says what and how to fix it. Here is a tiny style I often paste into the page template while keeping the classes reusable across forms.

.msg { font-size: 0.95em; margin-left: 6px; }
.msg_error { color: #b94a48; }
.msg_warn { color: #c09853; }
.msg_info { color: #3a87ad; }
input.invalid { border-color: #b94a48; }

If you want to go further, PrimeFaces and RichFaces add nice growl style globals that pair well with field messages.

Avoid these common traps

Do not hide messages on partial render, or the user will think the form is frozen. Do not write a regex that accepts nothing and then fix it in production. Do not throw a generic error from a validator when a converter would be clearer. Do not forget the label attribute and then wonder why messages show the component id. Do not flood the page with both field and global duplicates. Choose one spot for each problem and stick to it. Finally, do not blame the user for our rules. Own the wording.

We are the guides, not the gatekeepers.

A compact checklist for friendly JSF validation

Add a message bundle and set it in faces config. Set a label on every input. Prefer h:message next to fields, keep h:messages for page wide issues. Use requiredMessage, converterMessage, and validatorMessage for human copy. Fire f:ajax on blur to render the nearby message and the submit state. Keep summaries short and details helpful. Style messages so they are visible but not loud. Use Bean Validation on the model when rules are shared. Test with a keyboard only pass to feel the flow. Read the form out loud and see if it sounds polite.

Small changes here add up to a smoother day for everyone.

Friendly errors turn validation from a wall into a guide.

Software Architecture Software Engineering

Post navigation

Previous post
Next post
  • Digital Experience (94)
    • Experience Strategy (19)
    • Experience-Driven Commerce (5)
    • Multi-Channel Experience (9)
    • Personalization & Targeting (21)
    • SEO & Performance (10)
  • Marketing Technologies (92)
    • Analytics & Measurement (14)
    • Content Management Systems (45)
    • Customer Data Platforms (4)
    • Digital Asset Management (8)
    • Marketing Automation (6)
    • MarTech Stack & Strategy (10)
    • Technology Buying & ROI (3)
  • Software Engineering (310)
    • Business of Software (20)
    • Code (30)
    • Development Practices (52)
    • Digital Transformation (21)
    • Engineering Management (25)
    • General Software (82)
    • Productivity & Workflow (30)
    • Software Architecture (85)
    • Technical Implementation (23)
  • 2025 (12)
  • 2024 (8)
  • 2023 (18)
  • 2022 (13)
  • 2021 (3)
  • 2020 (8)
  • 2019 (8)
  • 2018 (23)
  • 2017 (17)
  • 2016 (40)
  • 2015 (37)
  • 2014 (25)
  • 2013 (28)
  • 2012 (24)
  • 2011 (30)
  • 2010 (42)
  • 2009 (25)
  • 2008 (13)
  • 2007 (33)
  • 2006 (26)

Ab Testing Adobe Adobe Analytics Adobe Target AEM agile-methodologies Analytics architecture-patterns CDP CMS coding-practices content-marketing Content Supply Chain Conversion Optimization Core Web Vitals customer-education Customer Data Platform Customer Experience Customer Journey DAM Data Layer Data Unification documentation DXP Individualization java Martech metrics mobile-development Mobile First Multichannel Omnichannel Personalization product-strategy project-management Responsive Design Search Engine Optimization Segmentation seo spring Targeting Tracking user-experience User Journey web-development

©2025 CMO & CTO | WordPress Theme by SuperbThemes