Attempt to convert String to type "java.util.Date", but there is no PropertyEditor for that type

Solution Verified - Updated -

Environment

  • JBoss Enterprise Application Platform (EAP) 6.x

Issue

  • A custom tag in our apptries to evaluate a string to a date, for example:
    Date d = (Date)ExpressionEvaluatorManager.evaluate("dateString", this.dateString, Date.class, this, this.pageContext);
  • After upgrading to EAP 6, this fails like so:
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/].[jsp]] (http-/0.0.0.0:8080-3) JBWEB000236: Servlet.service() for servlet jsp threw exception: javax.servlet.jsp.JspException: An error occurred while evaluating custom action attribute "value" with value "2015-07-02 08:21:00.0": Attempt to convert String "2015-07-02 08:21:00.0" to type "java.util.Date", but there is no PropertyEditor for that type (null)
    at org.apache.taglibs.standard.lang.jstl.Evaluator.evaluate(Evaluator.java:151) [jboss-jstl-api_1.2_spec-1.0.6.Final-redhat-1.jar:1.0.6.Final-redhat-1]
    at org.apache.taglibs.standard.lang.jstl.Evaluator.evaluate(Evaluator.java:171) [jboss-jstl-api_1.2_spec-1.0.6.Final-redhat-1.jar:1.0.6.Final-redhat-1]
    at org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager.evaluate(ExpressionEvaluatorManager.java:117) [jboss-jstl-api_1.2_spec-1.0.6.Final-redhat-1.jar:1.0.6.Final-redhat-1]

Resolution

  • You can correct this by calling the following to manually set the PropertyEditorManager path as it was on EAP 4.2:
      String[] currentPath = PropertyEditorManager.getEditorSearchPath();
      int length = currentPath != null ? currentPath.length : 0;
      String[] newPath = new String[length + 2];
      System.arraycopy(currentPath, 0, newPath, 2, length);

      newPath[0] = "org.jboss.util.propertyeditor";
      newPath[1] = "org.jboss.mx.util.propertyeditor";

      PropertyEditorManager.setEditorSearchPath(newPath);
  • That could be done in a ServletContextListener to ensure that is set up upon application start up, but perhaps just replacing the evaluate call is easy enough of a solution instead. Note that you'd need to add the common-core module to the dependencies in $EAP_HOME/modules/system/layers/base/javax/servlet/jstl/api/main/module.xml for the DateEditor to be found by the app:
<module xmlns="urn:jboss:module:1.1" name="javax.servlet.jstl.api">
    <dependencies>
        <!-- org.xml.sax -->
        <module name="javax.api" export="false"/>
        <module name="javax.servlet.api" export="false"/>
        <module name="javax.servlet.jsp.api" export="false"/>
        <module name="org.apache.xalan" export="false"/>
        <module name="org.jboss.common-core" export="true"/>
    </dependencies>

Root Cause

  • When you call evaluate, it is going to use the JSTL Coercion class to try to coerce the provided object (a String) in to the specified class (Date). This coerce attempt tries to find and use a PropertyEditor to provide the converted result:
  public static Object coerceToObject(Object pValue, Class pClass, Logger pLogger)
    throws ELException
  {
    if (pValue == null) {
      return null;
    }
    if (pClass.isAssignableFrom(pValue.getClass())) {
      return pValue;
    }
    if ((pValue instanceof String)) {
      String str = (String)pValue;
      PropertyEditor pe = PropertyEditorManager.findEditor(pClass);
      if (pe == null) {
        if ("".equals(str)) {
          return null;
        }

        if (pLogger.isLoggingError()) {
          pLogger.logError(Constants.NO_PROPERTY_EDITOR, str, pClass.getName());
        }

        return null;
      }
      try
      {
        pe.setAsText(str);
        return pe.getValue();
      }
  • The exception indicates a PropertyEditor for "java.util.Date" is not found, so the evaluate call and coercion attempt cannot succeed on EAP 6. The oracle java docs clarify how a PropertyEditorManager looks up a PropertyEditor:
The PropertyEditorManager uses three techniques for locating an editor for a given type. First,
it provides a registerEditor method to allow an editor to be specifically registered for a given
type. Second it tries to locate a suitable class by adding "Editor" to the full qualified classname
of the given type (e.g. "foo.bah.FozEditor"). Finally it takes the simple classname (without the
package name) adds "Editor" to it and looks in a search-path of packages for a matching class.
  • So EAP 4.2 provided a PropertyEditor for java.util.Date found in the above manner while EAP 6 does not. EAP 4.2 provides the org.jboss.util.propertyeditor.DateEditor class in the jboss-common.jar, which would have served as the java.util.Date PropertyEditor for that evaluate call to work previously. In EAP 4.2, org.jboss.system.ServiceConfigurator calls the following when it is loaded at start up:
   static
   {
      PropertyEditors.init();
   }
  • This org.jboss.util.propertyeditor.PropertyEditors.init() call sets the PropertyEditorManager path to include org.jboss.util.propertyeditor and org.jboss.mx.util.propertyeditor. So EAP 4.2 was specifically setting the PropertyEditorManager path so that it could find the DateEditor in the jboss-common.jar by scanning the org.jboss.util.propertyeditor package. It doesn't look like the PropertyEditors was even loaded and init'd for JSTL specifically, so it looks like it was just a happy coincidence that it did provide the DateEditor for that particular JSTL coercion call to work.
  • EAP 6 provides the DateEditor class in the common-core module, but PropertyEditors.init() is no longer called in EAP 6 and neither is java.beans.PropertyEditorManager.setEditorSearchPath() called anywhere else. So without being given a path, the PropertyEditorManager scans no packages, doesn't find the DateEditor, and JSTL has nothing to try to coerce the String to a Date as it happened to on EAP 4.2.

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.

Comments