Sunday, January 30, 2011

STS - @RequestMappings View

Sometimes I wonder if I really know the tools lurking beneath the surface of my Eclipse IDE ;) - today I've discovered @RequestMappings View - part of SpringSource Tool Suite (STS). I know, you probably use it for centuries already ;) - but for me it was really nice surprise :) - The rest of this post is for all the developers having feeling that there should be something like that, but still looking for it ;)

Let's start from the beginning, and open this View:


At the bottom of the Eclipse window you should see something like this:


Let's populate it with some data now ;) - this is the hardest part, because your project should have a Spring Project Nature, my own didn't have it, therefore I had to correct its configuration - adding missing Nature first:


and defining which files contain Spring Beans:


Finally we can find the file defining our application's request handlers, and populate the View with defined mappings:


Which will look somehow like this now:


When you click twice on any of the lines in this view you'll be transfered to the appropriate handler method, like in this example:


I'm still learning this View, and hope that next STS versions (I'm using 2.5.2 currently) will bring more functionality in it.

Saturday, January 29, 2011

jQuery Templates and JSON

Imagine the Web Application executing some functionality on the server using AJAX and processing data returned in JSON format. Very often such a processing is also updating UI with the provided data - recently we gained a powerful ally in this task - jQuery Templates.

This post will give you quick example of using jQuery Templates. We will focus on the client side of this process, assuming that the JSON response will look like this:
{"employer":{"id":1,"employees":[{"id":1,"firstName":"John","benefits":[{"name":"Healthy Employees","id":1,"type":"HEALTH_COVERAGE","startDate":1104534000000,"endDate":null},{"name":"Gold Autumn","id":2,"type":"RETIREMENT_PLAN","startDate":1104534000000,"endDate":null},{"name":"Always Secured","id":3,"type":"GROUP_TERM_LIFE","startDate":1104534000000,"endDate":null}]},{"id":2,"firstName":"Mary","benefits":[]},{"id":3,"firstName":"Eugene","benefits":[]}],"businessName":"Mighty Ducks"}}
And here comes the HTML/JavaScript part:
<html>
    <head>
    ...
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.min.js"></script>
        <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
        <script type="text/javascript">
        $(document).ready(
            function() {
                $("#ajax-trigger").click(
                    function(event) {
                        event.preventDefault();
                        $.getJSON("templates.json", { 'employerId' : 1}, 
                            function(data) {
                                $("#employerList").tmpl(data).appendTo("#ajax-target");
                            });
                    });
            });
        </script>
        <script id="employerList" type="text/x-jquery-tmpl">            
            {{tmpl(employer) "#employerTemplate"}}
        </script>
        <script id="employerTemplate" type="text/x-jquery-tmpl">
            <h1>${businessName}</h1>
            <table>
                <caption>Employees</caption>
                {{each(i, employee) employees}}{{tmpl(employee) "#employeeTemplate"}}{{/each}}
            </table>
        </script>
        <script id="employeeTemplate" type="text/x-jquery-tmpl">
            <tr>
                <td>${firstName}</td>
            </tr>        
        </script>    
    </head>
    <body>
        <div>
            <a href="javacsript:void();" id="ajax-trigger">AJAX</a>
        </div>
        <div id="ajax-target"></div>               
    </body>
</html>
As you see the whole machinery is triggered when you click on the "AJAX" link, then JSON response is fetched from server using $.getJSON and processed using following code:

$("#employerList").tmpl(data).appendTo("#ajax-target");

Which in more human friendly language means - find the element having id employerList and render its content as template using data returned from server, then append the result to element having id ajax-target.
Our first template (employerList) extracts the employer information from the provided data, and calls another template for this specific employer:

{{tmpl(employer) "#employerTemplate"}}

The employer template in turn displays the employer's business name, and for each of its employees calls the last template we use in this example - employeeTemplate

<h1>${businessName}</h1>
<table>
    <caption>Employees</caption>
    {{each(i, employee) employees}}{{tmpl(employee) "#employeeTemplate"}}{{/each}}
</table>

The employee template is very simple in this example, it only displays employee's first name

<tr>
    <td>${firstName}</td>
</tr>

Let's take a look at the above code in action - first the page right after loading:
Nothing special, except the big white space ;) - now after processing the JSON response:
As you see it works :) - and it's pretty fast, this very simple template was rendered on my chrome browser in less than 3 ms.

One and only doubt related to this solution which is troubling me is its compliance with HTML standard, because we put here different html tags inside of script tag - and W3C validator is not happy with that ;) - the question is if we should ...

Few links for the dessert:
  1. jQuery API - Templates
  2. Introducing jQuery Templates 1: First Steps
  3. jQuery Templates is now an Official jQuery Plugin
  4. jQuery JavaScript Templates Tutorial: Nesting Templates 

Saturday, January 15, 2011

Spring - Using Beans in HTTP Servlet

So you want to use your beautiful and shining Spring Beans in ugly and ordinary HTTP Servlet? Don't be ashamed ;) Sometimes we all have to do it, and we do it in many different ways ;) Below you may find few examples.

Old-fashioned way :) - used by me till some beautiful Thursday morning ...
public class BeanTest extends HttpServlet {

    private EmployerManager employerManager;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Do something amazing with the Spring Bean ...
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
        employerManager = applicationContext.getBean("business-logic.EmployerManager", EmployerManager.class);
        super.init(config);
    }

}
As you see, you can access Spring WebApplicationContext and then the desired bean by its identifier. Main disadvantage of this method is the bean identifier hardcoded into Servlet code. Especially if you are performing automatic component scan in Spring (ex. <context:component-scan base-package="[...].logic.impl" />). In this case you have two choices:
  1. Define the identifier of the bean using annotations:
    
    @Service("business-logic.EmployerManager")
    public class DefaultEmployerManager implements EmployerManager {
       ...
    }
    
  2. Use default bean identifier created by Spring in your Servlet - see: Naming autodetected components
Now relax, close your eyes, think about the refactoring the code, and all those hardcoded names which you should change by hand. It's time to forget this method my Friend, as I did. :)

Thankfully there are many young people, with open mind, who don't use the old-fashioned ways of doing things, and invent their own, as did my colleague - Bartek. Below you may find method doing the same as the above one, but based on @Autowired annotation usage.
public class BeanTest extends HttpServlet {

    @Autowired
    private EmployerManager employerManager;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Do something amazing with the Spring Bean ...
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
        super.init(config);
    }

}

SpringBeanAutowiringSupport will inject the appropriate Spring Beans into all your Servlet's properties marked with @Autowired annotation. That's all :) No hardcoding of bean names, no worries about future refactorings. Now relax, close your eyes, ...

Sunday, January 9, 2011

Spring MVC - Session Attributes handling

Spring Framework 2.5 has introduced annotation based programming model for MVC Controllers. Spring Framework 3 has made next step, and deprecated widely used SimpleFormController. Now we are all doomed to use annotations ;) but do we really understand what is going on behind the scenes?

Let's take a look at the @SessionAttributes and SessionStatus today :) If you are not familiar with them, you should start with Specifying attributes to store in a session with @SessionAttributes and Supported handler method arguments and return types before you will continue reading this post.

@SessionAttributes annotation is used on the Controller class level to declare used session attributes. All Model attributes having names or types defined in this annotation will be automatically persisted and restored between the subsequent requests. Sounds easy and beautiful, isn't it? Small declaration instead of boring HttpSession's getAttribute / setAttribute calls. Tempting :), try it and you'll find it can be dangerous too ...

"Automatically persisted" should alarm you :) - where? how? when? and for how long? - you should ask immediately :) - Well, let's take a deeper look at it :)

Strategy used for persisting Model attributes is defined by SessionAttributeStore implementation, Spring Framework by default uses DefaultSessionAttributeStore which in turn relies on HttpSession as the storage (for Servlet environment). You can provide custom implementation of the SessionAttributeStore interface, which you then enable by supplying a custom bean configuration for an AnnotationMethodHandlerAdapter (see Spring MVC pitfall - overriding default beans).

Model attributes are persisted at the end of request handling by AnnotationMethodHandlerAdapter, after calling your handler method responsible for request handling and after determining the ModelAndView for the response. Their names in Model are used as their names in the persistent storage, ex. @SessionAttributes("form") will trigger persisting Model attribute named "form" as HttpSession attribute named "form".

Persisted Model attributes will be removed only if you'll call SessionStatus.setComplete() method in some of your handler methods.

If at this point you still don't have any doubts, let me share my own with you:
  1. Cleaning not needed session attributes is a little tricky, because in a little more complicated applications users usually have possibilities to use Breadcrumb Navigation, some Menus, etc., each of them can cause switching the flow from one to another without calling SessionStatus.setComplete() method (and thus without cleaning the attributes used by the flow). 
  2. Using default SessionAttributeStore implementation and same names for Model attributes for different types of data will sooner or later lead to beautiful ClassCastException. Why? Because when some part of your application will persist attribute of class A under name "form", and user will then switch without cleaning it to other functionality, using also "form" attribute, but expecting it to be of class B, that will not end with the exception only if A extends B.
We all struggle with the HttpSession attributes cleaning, even not using Spring Framework, in fact. Both the problems mentioned by me above can be found outside the Spring Framework based application too. Using this beautiful and shining @SessionAttributes annotation you have to know how does it work, otherwise it will make you mad, instead of helping you.

For the dessert :) - few pitfalls you may encounter while using @SessionAttributes:
  1. When you refer to non-existing session attribute using @ModelAttribute annotation, HttpSessionRequiredException will be raised, like in following example:
    @SessionAttributes("abc")
    public class MyController {
    
        @RequestMapping(method = RequestMethod.GET)
        public void onGet(@ModelAttribute("abc") String something) {
            ...
        }
    }
    
    This exception, like the any other, can be then handled by you, using @ExceptionHandler annotation for example.
  2. SessionStatus.setComplete() method will trigger cleaning of Session Attributes, but only those which Spring will find "actual session attribute". Suppose that you declare 3 session attributes, but use only 1 of them in your handler method parameters, like in following example:
    @SessionAttributes({ "abc", "def", "ghi" })
    public class BindingTestController {
    
        @ModelAttribute("abc")
        public String createABC() {
            return "abc";
        }
    
        @RequestMapping(method = RequestMethod.GET)
        public void onGet(@ModelAttribute("abc") String something) {
            // do nothing :)
        }
    
        @RequestMapping(method = RequestMethod.POST)
        public void onPost(@ModelAttribute("abc") String something, BindingResult bindingResult, SessionStatus sessionStatus) {
            sessionStatus.setComplete();
        }
    
    }
    
    Only the "abc" attribute will be considered as "actual session attribute", and removed on POST request.
  3. Attribute will be flagged as "actual session attribute" while resolving @ModelAttribute annotated method parameters and AFTER request processing - in this case all Model attributes are checked if they should be persisted (according to @SessionAttributes annotation). 
  4. Assuming that you pass the parameter to some flow, using @SessionAttributes mechanism may lead to surprises, sometimes unpleasant :( Suppose that you want to start new flow programmatically, from Controller A, you put the flow parameter on session, under name "parameter", and mark the Controller B (handling the entry point to the flow) with the @SessionAttribute("parameter"). That will not work my Friend, "parameter" will not be restored into B Controller's Model on entry, because it is not an "actual session attribute" (see above), at least before the first request handling. (Spring 3.1 brings remedy for this problem, named Flash Attributes - see my post Spring MVC - Flash Attributes)

Wednesday, January 5, 2011

33rd degree - Conference for Java Masters - Kraków, 6-8 April 2011

As you see I'm still alive :). After the heavy December (ugly virus stroke, Christmas, etc.), it's time to recover and start blogging again :) Something easy to write for the beginning ;)

33rd degree - Conference for Java Masters is coming up (Kraków, Poland) - you may register now on http://33degree.org/registration.html