While trying JFormattedTextField, I had this requirement to show placeholder to the user to guide him while providing the date input. There was also a need to pop up user with the error message, if the input was incorrect. (Yeah, I understand that many prefer inline error messages than the pop-ups but then requirements are requirements.) One way could be to provide a MaskFormat to the JFormattedTextField and use directly validates the date, yourself using the pattern. What I tried is used both the DateFormat and MastFormat with the JFormattedTextField. The code can be modified for individual needs but the idea is to provide an input verifier to the JFormattedTextField. Use the formatter set for JFormattedTextField to verify the inputs. Along with these, also install a mask formatter to show placeholders to user.

Code to create a JFormattedTextField to verify dateinputs:

package com.aminur.swing;

import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import java.util.Date;

import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JOptionPane;
import javax.swing.text.DateFormatter;
import javax.swing.text.MaskFormatter;


public class DateFormattedTextFieldVerifier
{

  private String mask = null; // e.g "##/##/####";
  private SimpleDateFormat format;
  private DateFormatter df;
  protected String datePattern; // = "dd/MM/yyyy";
  private String placeholder; // e.g "__/__/____";
  private char placeholderChar; 
  private DateVerifier objDateVerifier;
  private JFormattedTextField dateTextField;
  private String patternString;

  public static JFormattedTextField getFormattedTextField(String pattern)
  {
    return (DateFormattedTextFieldVerifier.getFormattedTextField(pattern, true, false, null, null,
                                                                 null));
  }

  
  public static JFormattedTextField getFormattedTextField(String pattern, boolean showPopUp,
                                                          boolean installMask, String mask,
                                                          String maskPlaceholder,
                                                          Character placeholder)
  {
    DateFormattedTextFieldVerifier thisClass =
      new DateFormattedTextFieldVerifier(pattern, showPopUp, installMask, mask, maskPlaceholder,
                                         placeholder);
    return thisClass.dateTextField;
  }

  

  private DateFormattedTextFieldVerifier(String pattern, boolean showErrorPopUp,
                                         boolean installMask, String mask, String maskPlaceholder,
                                         Character placeholderChar)
  {
    patternString = pattern;
    format = new SimpleDateFormat(pattern);
    df = new DateFormatter(format)
    {
      public Object stringToValue(String string)
        throws ParseException
      {
        if (string == null || string.length() == 0 || string.equals(placeholder))
        {
          return null;
        }
        return super.stringToValue(string);
      }
    };
    
    format.setLenient(false);
    dateTextField = new JFormattedTextField(df);
    if (installMask)
    {
      placeholder = maskPlaceholder;
      this.mask = mask;
      this.placeholderChar = placeholderChar.charValue();
      installMask(dateTextField);
      dateTextField.setFocusLostBehavior(JFormattedTextField.PERSIST);
      dateTextField.addFocusListener(new FocusAdapter()
      {

        public void focusGained(FocusEvent e)
        {
          installMask(dateTextField);
        }
      });
    }
    objDateVerifier = new DateVerifier(format, placeholder, showErrorPopUp, installMask);
    dateTextField.setInputVerifier(objDateVerifier);
  }


  private void installMask(JFormattedTextField tfObject)
  {
    MaskFormatter objMask = new MaskFormatter()
    {
      public void install(JFormattedTextField ftf)
      {
        String currentText = ftf.getText();
        super.install(ftf);
        if (ftf != null) 
        {
          if (currentText != null && currentText.length() > 0)
          {
            ftf.setText(currentText);
          }
        }
      }


      public String valueToString(Object obj)
        throws ParseException
      {

        if (obj instanceof Date)
        {
          return (format.format((Date) obj));
        }
        return super.valueToString(obj);
      }
    };
    try
    {
      objMask.setMask(mask);
      objMask.setAllowsInvalid(true);
      objMask.setPlaceholderCharacter(placeholderChar);
      objMask.install(tfObject);
    }
    catch (Exception pe)
    {

      System.out.println("Exception " + pe);
    }

  }

  class DateVerifier
    extends InputVerifier
  {
    private DateFormat dateFormat = null;

    private boolean isPopupErrorEnable = true;
    private String formatPlaceholder = null;
    private boolean useMask;

    DateVerifier(DateFormat df, String fPlaceholder, boolean isPopupErrorEnable, boolean useMask)
    {
      this.dateFormat = df;
      this.isPopupErrorEnable = isPopupErrorEnable;
      this.useMask = useMask;
      formatPlaceholder = fPlaceholder;
    }

    private boolean isDateValid(String p_Date)
      throws ParseException
    {

      try
      {
        dateFormat.parse(p_Date);
        return true;
      }
      catch (ParseException dfe)
      {
        throw dfe;
      }
    }

    public boolean verify(JComponent input)
    {
      try
      {
        if (input instanceof JFormattedTextField)
        {
          JFormattedTextField jtf = (JFormattedTextField) input;
          String currentValue = jtf.getText();
          if (currentValue == null || currentValue.equalsIgnoreCase(formatPlaceholder) ||
              currentValue.length() == 0)
          {
            jtf.setValue(null);
            jtf.commitEdit();

            
            return true;
          }
          try
          {
            isDateValid(jtf.getText());
            jtf.commitEdit();
            return true;
          }
          catch (Exception e)
          {
            if (isPopupErrorEnable)
            {
              JOptionPane.showMessageDialog(jtf.getParent(),
                                            e.getMessage() + "\n Please specify date as " +
                                            patternString, "Date Error..",
                                            JOptionPane.ERROR_MESSAGE);
            }
            jtf.selectAll();

            return false;
          }
        }
      }
      catch (Exception ex)
      {

        ex.printStackTrace();
        return false;
      }
      return true;
    }
  }
}

Edited : 06 June 2013: On request from a blog reader, below is a sample Java Panel client to demonstrate the usage.


package client;

import com.aminur.swing.DateFormattedTextFieldVerifier;

import java.awt.Dimension;
import java.awt.event.ActionEvent;

import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class TestPanel
  extends JPanel
{
  private JButton testButton;
  private JFormattedTextField form_date;

  
  public TestPanel()
  {
    initPanelComponents();
  }

  
  @SuppressWarnings("unchecked")
  private void initPanelComponents()
  {

    testButton = new JButton();
    form_date = DateFormattedTextFieldVerifier.getFormattedTextField("dd/MM/yyyy", 
                                                                     true, 
                                                                     true, 
                                                                     "##/##/####", 
                                                                     "__/__/____", 
                                                                     '_');

    testButton.setText("Test");
    form_date.setPreferredSize(new Dimension(200,25));
    testButton.addActionListener(new java.awt.event.ActionListener()
    {
      public void actionPerformed(java.awt.event.ActionEvent evt)
      {
        testButtonActionPerformed(evt);
      }
    });

    add(form_date);
    add(testButton);

  }

  private void testButtonActionPerformed(ActionEvent evt)
  {

  }

  public static void main(String[] args)
  {
    JFrame f = new JFrame("JFormatted Input Verifier demo");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setSize(800, 600);
    TestPanel testPanel = new TestPanel();
    f.add(testPanel);
    f.setVisible(true);
  }

}