Spring Finance > Part 4: Spring JS, Dojo & Bean Validation

In this fourth installment of the Spring Finance Manager series you will see some of the Spring JS features and also some examples of the Dojo toolkit features in action. I will also outline how the new Bean Validation API (JSR-303) fits in. In addition, I have implemented the complete domain model for the Spring Finance Manager sample application as outlined in part 1 of this series.

For this article I have tagged a new version (v0.2) of the Spring Finance Manager sample application which is now available at the project hosting site. In this release I have included a HTML based script for Selenium. This can be run using the Selenium IDE so you can save yourself some effort in filling in all these new forms in the sample application while still being able to see all the new JavaScript goodness (provided you run the script slow enough :-) ).

So let’s start with Spring JavaScript.

Spring JS

Spring JavaScript represents a lightweight abstraction over Ajax toolkits. Currently the only toolkit supported is Dojo. In order to use Dojo you would typically install the complete distribution (or a customized subset) in your Web application directory (WEB-INF) of your Spring MVC application. Alternatively, Dojo can be loaded directly from either the AOL Content Delivery Network (CDN) or the Google CDN. A third way, to install Dojo in your Spring MVC application is to load it conveniently from a maven repository as jar archive. This is what I have chosen to do in the Spring Finance Manager application.

To allow the loading of Dojo resources within the jar bundle you need to configure a resources Servlet in your web.xml:

<servlet>
 <servlet-name>Resource Servlet</servlet-name>
 <servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
</servlet>
<servlet-mapping>
 <servlet-name>Resource Servlet</servlet-name>
 <url-pattern>/resources/*</url-pattern>
</servlet-mapping>

Then you need to load the Spring JS and Dojo resources (.js and some .css files) in your jsp pages. I have done this in the seperate header.jsp file so I don’t have to do it in all content files:

<style type="text/css" media="screen">
 @import url("<c:url value="/resources/dojo/resources/dojo.css"/>");
 @import url("<c:url value="/resources/dijit/themes/tundra/tundra.css"/>");
</style>     

<script djconfig="parseOnLoad: true"
 src="<c:url value="/resources/dojo/dojo.js"/>" type="text/javascript"></script>
<script type="text/javascript"
 src="<c:url value="/resources/spring/Spring.js" />"> </script>
<script type="text/javascript"
 src="<c:url value="/resources/spring/Spring-Dojo.js" />"></script>
<script type="text/javascript">dojo.require("dojo.parser");</script>

That’s all you need to do to make Dojo available to be used in your Web layer.

Now, let’s assume you want to enable simple validation for a text box in the WEB-INF/jsp/person/create.jsp form. For this all you need to do is to include a Spring JS decorator for this text field:

<div>
 <label for="name">Name:</label>
 <form:input cssStyle="width:250px" maxlength="30" path="name" size="30"/>
 <form:errors path="name" cssClass="errors"/>
 <script type="text/javascript">
 Spring.addDecoration(new Spring.ElementDecoration({
 elementId : "name",
 widgetType : "dijit.form.ValidationTextBox",
 widgetAttrs : {
 promptMessage: "Enter Name",
 required : true}}));
 </script></div>

This decoration will create a little message bubble displaying ‘Enter Name’ when the name field gets focus. Further, the decorated name field will show an error when nothing is entered (‘required:true’).

If you want to prevent form submission in case any of the form fields is in an error state, you can apply the following decoration to the submit button of the form:

<input id="proceed" type="submit" value="Save"/>
<script type="text/javascript">
 Spring.addDecoration(
 new Spring.ValidateAllDecoration({
 elementId:'proceed',
 event:'onclick'}));
</script>

Another frequently used decoration is the DateTextBox provided by Dojo. If you have a domain object with a date field such as the Investment object in the Spring Finance Manager application, you need to convert the date entered in the respective text field to a java.util.Date object. For this you use property editors in Spring MVC. In our case the date is required in the following format: “MM/dd/yyyy”. Using a Spring JS / Dojo decorator you can make the user experience much more pleasant by adding:

<form:input path="transactionDate"/>
<script type="text/javascript">
 Spring.addDecoration(
 new Spring.ElementDecoration({
 elementId : "transactionDate",
 widgetType : "dijit.form.DateTextBox",
 widgetAttrs : {
 datePattern : "MM/dd/yyyy",
 required : true}}));
</script>

This pops up a nice date selection dialog when the field gets focus in your form:

As you can see when using the Spring JS decoration approach, the actual Spring form bindings (
) are not touched and therefore form binding still works happily when the user has disabled JavaScript in his Web browser. There are more decorators supported by the Spring JS project. Be sure to take a look at the [http://static.springframework.org/spring-webflow/docs/2.0.x/reference/html/ch11s04.html documentation] page.

Dojo

The Spring JS abstraction does not attempt to hide away all functionalities of the Dojo toolkit, rather it does provide an abstraction for decorating common elements used in Web forms. This allows you to preserve your normal Spring form binding mechanisms. For everything else it is recommended to use Dojo directly. For example, to wrap your content page in a Dojo TitlePane you can simply decorate your element with Dojo:

<script type="text/javascript">dojo.require("dijit.TitlePane");</script>
<div dojoType="dijit.TitlePane" style="width: 100%" title="Show Account">
[...]</div>

Another example is Dojo’s DropDownButton in combination with the TooltipDialog which are used on the ‘Show Account’ page in Spring Finance manager:

<script type="text/javascript">
 dojo.require("dijit.Dialog");
 dojo.require("dijit.form.Button");
</script>
<div id="newInvestmentButton" dojoType="dijit.form.DropDownButton">
 <span>Add New Investment</span>
<div dojoType="dijit.TooltipDialog" id="tooltipDlg" title="Enter Investment Details">
[...]</div>
</div>

For more options you can get great inspiration from the Dojo Feature Explorer.

Spring MVC and JSR 303 Bean Validation

In this new release (v 0.2) of the Spring Finance Manager sample application I have switched from using plain Hibernate Validator on my domain objects to the JSR 303 Bean Validation API. This is a new API which now available as ‘Proposed Final Draft’ with Hibernate Validator 4 (currently still in alpha stage) as the only currently available implementation of the specification.

For my project this works just fine as I am not using more advanced features such as group definitions. However, since the JSR 303 specification offers only a subset of the functionality offered by Hibernate Validator, and because I was too lazy to implement my own validation annotations, I resorted to using a lot of the @Pattern(regexp = “.+”) which is effectively the same as Hibernate Validators @Empty. Also, since I have so far not seen any need for internationalization support in the Spring Finance Manager application I have included the validation messages directly into the annotations:

@Pattern(regexp = ".+", message = "Name must not be empty!")
private String name;

Of course it would be better to have these messages in separate properties files.

Now, since Spring 3.0 does currently not support the JSR 303 yet in its own validation implementation I needed to do some translation in the controllers in order to propagate the message back to the views:

@RequestMapping(value = "account", method = RequestMethod.POST)
public String create(@ModelAttribute("account") Account account, BindingResult result) {
 Assert.notNull(account, "Account must be provided.");
 for (ConstraintViolation<Account> constraint : validator.validate(account)) {
 result.rejectValue(constraint.getPropertyPath(), null, constraint.getMessage());
 }
 if (result.hasErrors()) {
 return "account/create";
 }
 accountService.persist(account);
 return "redirect:/account/" + account.getId();
}

This could be improved a little as the validation is now performed twice: first explicitly in the controllers as shown above, and second, implicitly just before the JPA entity is actually being persisted. So instead of calling it explicitly in the controller I could just check for a ConstraintValidationException which would be thrown by the Bean Validation API. However since this convolutes the code for this example even more I’ll leave it at that.

You may be wondering why we are now using two points for validation; in the view layer through Dojo’s validators, and in the domain layer by using the Beans validation API. The reason is simple, client side validation based on JavaScript is good because it does not require any server round trips and therefore makes the user experience more pleasant, but if JavaScript is disabled there would be no validation if we were not using the Beans Validation API on the server side. Further, if we would expose some of the Spring Finance Management functionalities as Web services via the service layer, the server-side validation would still safeguard the consistency and quality of the data.

So if we switch off JavaScript support in the browser, the application still displays appropriate messages to notify the user instead of throwing an exception:

Conclusion

In this article I showed how to configure and use JavaScript toolkits in Spring MVC applications. To do this you can either directly use your favorite toolkit (I am using Dojo) or use Spring’s JavaScript abstraction layer. Further I shown and discussed how the brand new Beans Validation API (JSR-303) can be integrated into your project.

In the next part of this series, I was planning to write about the integration of Spring Security to safeguard the Spring Finance Manager sample application using authentication and authorization. However, I might be pushing it out by one or two articles in the hope to demonstrate the new expression language features in the upcoming milestone releases of Spring Security 2.5. So, the next article will be a surprise :-) . Maybe Spring Web Flow?

  • Share/Bookmark

16 Responses Subscribe to comments


  1. Viraf Karai

    Thanks for the excellent article. It was indeed very useful. I’m seeing Spring/JPA becoming totally mainstream these days as opposed to Spring/Hibernate (which I like very much too). I wasn’t aware of the Spring-JS project and I will indeed investigate this further. Also, I’m aware about Spring-Webflow, but haven’t researched it. I’ll do so soon since it looks very promising for conversational web applications.

    I’m impressed by the REST integration that Arjen and his team have incorporated into Spring 3.0. I’m really looking forward to using it – especially since the entire framework is now genericized (I believe that Spring 3.0 only works with Java 5 and above).

    Best wishes.

    Apr 07, 2009 @ 09:58


  2. Viraf Karai

    While deploying the application to Tomcat 6 with the maven build on Ubuntu 8.04, I encountered problems with slf4j which causes the deployment to fail – http://www.slf4j.org/faq.html#IllegalAccessError . Apparently, one of the Hibernate JARs uses an older version of slf4j (1.4.2) which results in this problem. The problems disappear after I removed the Hibernate dependency on slf4j in the pom.xml (see below – line # 213 in existing pom.xml)

    org.hibernate
    hibernate-validator
    4.0.0.Alpha3

    org.slf4j
    slf4j-api

    I hope this helps users who may have experienced the sl4j errors like I did.

    Apr 08, 2009 @ 07:33


  3. Viraf Karai

    Looks like your site does not like XML in posts. Here’s my maven pom.xml fix to stop pulling in slf4j from Hibernate. Simply translate the parentheses to XML angle brackets (line # 213 in pom) :-)

    (dependency)
    (groupId)org.hibernate(/groupId)
    (artifactId)hibernate-validator(/artifactId)
    (version)4.0.0.Alpha3(/version)

    (exclusions)
    (exclusion)
    (groupId)org.slf4j(/groupId)
    (artifactId)slf4j-api(/artifactId)
    (/exclusion)
    (/exclusions)
    (/dependency)

    Apr 08, 2009 @ 07:38


  4. sschmidt

    Hi Viraf,

    Sorry for the delayed response :) .

    Thanks for the heads-up with regards to the slf4j problem. Can you please send a bug report to the project code website: http://code.google.com/p/spring-finance-manager/issues/list

    Best,
    Stefan

    Apr 12, 2009 @ 23:54


  5. Viraf Karai

    Stefan:

    I checked out v 0.3 from GoogleCode and imported the project into IntelliJ IDEA. The latest POM fix did the trick.

    Thanks for a great application. I’ll now check out part # 5 – SpringWebflow since I need to educate myself about Spring WF.

    Best wishes.

    Viraf

    Apr 21, 2009 @ 04:01


  6. Jim

    Good stuff. Would be great if you could show an example how Dojo handles populating a comboBox when another comboBox value changes (or populating another field).

    Great stuff!

    May 13, 2009 @ 00:44


  7. sschmidt

    @Jim,

    Yes that would be an interesting thing to do. Unfortunately I am currently quite busy so I won’t have that much time to try it. I guess you would need some JS/Ajax functions in the JSP to handle this appropriately. Spring JS has asynch callback handling capabilities to do this. Alternatively you can use straight Dojo – and I am sure there are plenty of examples out there.

    I would be interested in your experiences if you pursue your trial. If you want you could contribute to the code (use the project site bugtracker) to integrate it into the next version of this application.

    Best,
    Stefan

    May 13, 2009 @ 12:33


  8. Julie

    Hi Stefan,

    I was just wondering if your dateTextBox works on Google Chrome or Firefox? I am following your example to implement a Web Application. It is working fine on Internet explorer, but for some reason the date is not included as part of the post in Chrome/FireFox.

    Just wondering if you might have any ideas.

    Thanks!

    Julie

    Aug 07, 2009 @ 03:35


  9. Stefan Schmidt

    Hi Julie,

    I tested this in Firefox and Opera but not IE at the time (I am a Linux user) so the only thing I can think of right now is that your problem is related to localization. Maybe you take a look at Spring Roo which helps you generate very similar applications to my Spring Finance Manager sample and see if the dojo date selector issue persists.

    -Stefan

    Aug 07, 2009 @ 10:51


  10. Julie

    Hi Stefan,

    I hope you do not mind, but I would like to ask you one more quick question on this. In your application do you take the value selected from the dojo calendar, and submit it successfully to Spring MVC as part of a form?

    Thanks again.

    Julie

    Aug 14, 2009 @ 03:10


  11. Stefan Schmidt

    Julie,

    Yes the date is sent via a form POST (or simulated PUT) to the Spring MVC restful backend. There may be some localization issues if you are using a non english locale. I should probably update the example w/r to this. The localization issue has been addressed in Roo generated applications.

    -Stefan

    Aug 14, 2009 @ 10:40


  12. Julie

    Hi Stefan,

    Thank you again for your reply. No, I am not using a non-english locale. Now that I know you do have a working form post, perhaps I will compare our code bases again and see if I can spot a difference. For some reason firefox/chrome are not viewing my dateTextBox fields as part of the form.

    Thanks again.

    Julie

    Aug 19, 2009 @ 06:23


  13. Arvind Saini

    Most of my knowledge of Spring 3.0, Spring MVC and Hibernate is achieved by reading your tutorials and running FinanceManager examples. I have used Finance Manager as the starting point of one of my recent projects. Thanks a lot for your good work.

    This blog might need some correction regarding the double validation.

    JPA1 entities are not automatically validated by Hibernate Validator. Default validation is done for non-jpa and JPA2 environments. see following link:

    http://docs.jboss.org/hibernate/stable/validator/reference/en/html_single/#d0e2461

    Nov 08, 2009 @ 06:05


  14. Adrian

    Hi, thanks for this post.
    I’m currently gearing up for a large project which I will be leading, and am trying to draw functional parallels between Spring, JEE6, and .NET so as to make a business case for the use of one over another.

    One very nice feature of .NET is the ability to invoke Model validation annotations both on the server side and the client side with very little configuration in the view (see this quick demo http://www.asp.net/mvc/videos/mvc2-model-validation).
    Your demo and others like it allow the client to check for things like empty fields but do not actually run the bean validation until the whole form is submitted. The Spring validator interface will validate the entire bean, not just a single field on a bean. In ajax form validation, if I made a change to a single form field, I would expect a validation message to be returned only for that field, not for every invalid field on the form.

    Can you suggest whether what I’m looking for is just not possible currently in a java environment?

    thanks very much.

    May 14, 2010 @ 19:13


  15. Janaka

    Hi,

    Thanks for your excellent article. i am having a issue to load dojo as a jar file for my POM.xml. can you give a tip to do it?

    Aug 05, 2010 @ 18:43


  16. Steve

    Nice Tut, thanks a bunch.

    Pls, can I have the links to all the series?

    I will appreciate it.

    Oct 22, 2010 @ 21:31

Reply