Sorry, had to wait for my thread to be approved.
Now, here are the same snippets of code from my real-life application, which, from what I can tell, is pretty much written the same way and so should work the same way:
web.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>migrationapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>migrationapp</servlet-name>
<url-pattern>/do/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<jsp-config>
<taglib>
<taglib-uri>/spring</taglib-uri>
<taglib-location>/WEB-INF/tld/spring-form.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
migrationapp-servlet.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:component-scan base-package="[my.base.package]"/>
<context:annotation-config/>
<tx:annotation-driven/>
<bean id="validator" class="org.springmodules.validation.bean.BeanValidator">
<property name="configurationLoader">
<bean class="org.springmodules.validation.bean.conf.loader.annotation.AnnotationBeanValidationConfigurationLoader"/>
</property>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator" ref="validator"/>
</bean>
</property>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<qualifier value="main"/>
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://hostname:1433;databasename=migrationApp"/>
<property name="username" value="migrationApp"/>
<property name="password" value="password"/>
</bean>
</beans>
UserAccountForm.java
Code:
import org.springmodules.validation.bean.conf.loader.annotation.handler.*;
...
public class UserAccountForm
{
@NotNull(message="The percentage cannot be blank!")
@Max(value=50,message="The percentage cannot be greater than 50!")
@Min(value=1,message="The percentage cannot be less than 1!")
private int percentage;
@NotBlank(message="The username is required!")
@MaxLength(message="The username is too long!", value=100)
private String username;
@NotBlank(message="The email address is required!")
@MaxLength(message="The email address is too long!", value=100)
@Email(message="The email address provided is not a valid email address!")
private String email;
@NotBlank(message="The password is required!")
@MinLength(message="The password must be at least 6 characters!", value=6)
@MaxLength(message="The password must not be more than 20 characters!", value=20)
private String password;
@NotBlank(message="You must confirm the password!")
@Expression(value="passwordConfirm EQUALS password", message="The passwords do not match!")
private String passwordConfirm;
private boolean administrator = false;
...
views/users/new.jsp
Code:
...
<form:form method="post" modelAttribute="newAccountForm">
<table width="100%" bgcolor="#FFFFFF" border="0" cellspacing="2" cellpadding="0">
<tr>
<td align="right" width="20%">Increase (%):</td>
<td width="20%">
<form:input path="percentage"/>
</td>
<td width="60%">
<form:errors path="percentage" cssClass="error"/>
</td>
</tr>
<tr>
<td>Username</td>
<td>
<form:input path="username"/>
</td>
<td>
<form:errors path="username" cssClass="error"/>
</td>
</tr>
<tr>
<td>Email Address</td>
<td>
<form:input path="email"/>
</td>
<td>
<form:errors path="email" cssClass="error"/>
</td>
</tr>
<tr>
<td>Password</td>
<td>
<form:password path="password"/>
</td>
<td>
<form:errors path="password" cssClass="error"/>
</td>
</tr>
<tr>
<td>Confirm Password</td>
<td>
<form:password path="passwordConfirm"/>
</td>
<td>
<form:errors path="passwordConfirm" cssClass="error"/>
</td>
</tr>
<tr>
<td colspan="3">
<form:checkbox path="administrator"/> This user is an administrator
</td>
</tr>
</table><br/>
<br/>
<input type="submit" value="Add User"/>
</form:form>
...
UserAccountController.jsp
Code:
@Controller
@RequestMapping("account")
public class UserAccountController
{
...
@RequestMapping(value="new", method=RequestMethod.GET)
public String addAccount(Map<String, Object> model)
{
this.logger.info("Generating the form to add an account.");
model.put("title", this.title + " :: Add Account");
model.put("newAccountForm", new UserAccountForm());
return "users/new";
}
@RequestMapping(value="new", method=RequestMethod.POST)
public ModelAndView addAccount(@Valid UserAccountForm form, BindingResult binder, Map<String, Object> model)
{
this.logger.info("Form submitted to add an account.");
model.put("title", this.title + " :: Add Account");
if(binder.hasErrors())
{
this.logger.warn("Form had errors in it: " + binder.getAllErrors().get(0).getCode() + " (" + binder.getAllErrors().get(0).getDefaultMessage() + ")...");
model.put("newAccountForm", form);
return new ModelAndView("users/new");
}
...
}
Again, this works almost identically, including that when any of the fields are invalid a warning gets saved to the log, however, the HTML output around the errors tag is
Which isn't very helpful at all. I have hammered at this one problem for days. Everything else is working perfectly - I can CRUD against the database on both projects, if I fail validation I get sent back to the form and a warning gets logged ... it's just that on the tutorial application the validation annotation "message" is displayed, and on the real-life application the span isn't even printed out, much less with the message.
There are no warnings, errors or exceptions in the log file other than those I have intentionally logged to it when validation rules are violated. No informational messages indicate why the form:errors tags aren't displaying the errors.
I do not have a messages.properties file (yet) on EITHER application. I'm relying solely on the annotation default message for now. I have tried adding a message.properties file to the WEB-INF/classes directory (and the appropriate configurations) but that didn't help any, and since it works without it in the tutorial, it should work without it in the real-life application.
I have all the same JARs in the projects. I can provide a list of them if need be.
Any ideas? Thanks in advance for any help.