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

Tuesday, December 7, 2010

JPA - insert instead of update

Few days ago I was digging through the code in some project to find the reason why EclipseLink (2.1.1) is performing database insert instead of update. Let me say, that it was the hardest thing to find in my whole JPA-using developer career - so for the records, and to let you find it faster than me ;)

There was an association between entities Alpha and Beta, made in following manner:
public class Alpha ... {
    ...
    private Beta beta;

    @ManyToOne(..., optional = false)
    @JoinColumn(name = "beta_id")
    @JoinFetch(JoinFetchType.INNER)
    public Beta getBeta() { 
        return beta;
    }
    ...
}
I wrote about the @JoinFetch annotation in one of my previous posts already (see: JPA Demystified (episode 1) - @OneToMany and @ManyToOne mappings) - it is used here, to fetch the associated Beta along with the Alpha, in one query.

In the project analyzed by me, instance of Alpha was created at one point, edited in few steps, with persisting into database between the steps. Everything was fine after the first step. Alpha was written into database (first insert), but after the second step, primary key violation occurred each time I tested it (same entity was again inserted into DB, while it should be updated at this point).

My first hint was missing equals and hashcode methods on Alpha and Beta. I've added it, but it doesn't helped at all. So I meet with the best friend of all Developers - Debugger :) - and started to dig into the project and EclipseLink source code. At this point let me give you first suggestion - when you trace the JPA problems use the Debugger and verify performed database operations in parallel, because only both those things can give you full view of the problem lurking beneath the Application's surface ;)

Watching the SQL queries, I've found that EclipseLink is performing query fetching the Alpha along with the Beta (as directed by @JoinFetch annotation), right before the invalid insert. Matching this operation to the Java code, I've found that EclipseLink is trying to check what has changed in the Alpha entity, to perform only the required updates to the database. The SQL query was using inner join ...

Do you suppose what was wrong? :) - There was no Beta entity associated to the Alpha, and therefore this query - "select ... from Alpha inner join Beta ..." was returning no records at all. At this point EclipseLink was assuming that Alpha entity was not written into database yet, and tried to do it again - Alpha has already generated identifier (while first insert into database), and ... beautiful exception :)

What you should learn from the above situation is that optional attribute of association definition is informational only! - It's provider choice to throw an exception if the associated value will be null, or do something completely else, as you see EclipseLink developers are ignoring it silently :(

Last but not least - use @JoinFetch(JoinFetchType.INNER) if and only if you are absolutely sure, that associated entity will always exist - ex. when the database scheme doesn't allow other possibility. Don't trust JPA provider completely ;)