Sunday, December 2, 2012

Spring's Web MVC - Redirect to the Memory Leak

They say that one rock can cause an avalanche. Lately, one of my Colleagues, Marcin Radoszewski, gave me such a rock. You'll probably never guess what it is, but there is a chance, that you use it in many of your Web Applications. Allow me to introduce this rock to you :)

You probably well know redirect after post pattern. Using Spring Framework you have few ways to implement it, let's focus on one of them, returning the target URL as the String with redirect: prefix.

Suppose that we have controller using this method of redirecting, and we have to pass some parameters during the redirect, let it be some entity ID for example:

@RequestMapping(method = RequestMethod.POST)
public String onPost(...) {
    ...
    return "redirect:form.html?entityId=" + entityId;
}

As you see, our rock doesn't look dangerous, it even doesn't look suspicious :) - What the heck is wrong with that?! - you may ask. Well, to explain that, we have to take a look at the way how Spring Framework handles the value returned by you.

You may start from reading Resolving views in Spring Framework documentation, and then take a closer look at the source code of AbstractCachingViewResolver, which is base class for many different View Resolvers in Spring, including: JSP, FreeMarker, Velocity, Jasper Reports, Tiles and XSLT view resolvers.

When resolveViewName method is called on AbstractCachingViewResolver it uses HashMap based view cache to speed up view resolving in the future calls, and cache key is by default created using view name and current locale.

Now to the clue :) - when you use the above method of redirecting, Spring Framework uses the whole String returned from your controller's method as the view name, including all parameters included in the target URL. Each time you perform the redirect, the parameters may vary, thus such a redirect will leave one additional entry in view cache of  AbstractCachingViewResolver, causing memory leak.

How soon that will kill my application? - you may ask. That depends on the amount of memory assigned to JVM, and the number of performed redirects :) - I've made some tests using: -Xmx64M option, with simple application build from only one controller - see this example. After about 76400 redirects the application died with OutOfMemoryError: Java heap space.
 


Follow-ups:


This article has been republished on Java Code Geeks (12/07/2012), and on Dzone's Javalobby (12/10/2012).

Monday, August 13, 2012

JPQL - pagination on Oracle Database with Hibernate

In your daily work, you rely on many different libraries, trusting they will serve you well, being perfect piece of code ... do you? ... really?! Then it's time to realize that you are perfectly wrong :) Increasing complexity of code leads to new possibilities of making errors :) Many of them are lurking in the libraries used by you, even if they are used for years by thousands of developers.

Let's find some example. Suppose that we are using JPA, and have an entity named Employee, which contains at least two properties: name and id. Suppose that we want to display all employees ordered by name, and paginated. To fetch them from the underlying database we will need JPQL query like this:

select e from Employee e order by e.name

We will paginate it using setFirstResult and setMaxResults methods of javax.persistence.Query interface. Now we need a JPA provider and database to make it work, let's choose Hibernate, and Oracle (10+).

At first try everything works perfectly :) - but let's assume that we have employees sharing the same name, for ex. 20 of them having name 'Smith' (identifiers between 1 and 20), 10 having name 'Donovan' (identifiers between 21 and 30) and 10 having name 'Johnson' (identifiers between 31 and 40) - total 40 employees. Let's try to display 5 employees on single page, and see what will happen:

Page 1 - employees having ID: 21, 25, 24, 23, 22 - all having name 'Donovan' - good :)
Page 2 - employees having ID: 26, 25, 24, 23, 22 - all having name 'Donovan' - but 4 of them were already displayed on first page (!)
Page 3 - employees having ID: 31, 35, 34, 33, 32 - here comes the 'Johnson' name - good again :)
Page 4 - employees having ID: 36, 35, 34, 33, 32 - 'Johnson' again, and again 4 of them were already displayed on third page (!!)
Page 5 - employees having ID: 1, 17, 18, 19, 20 - here comes the 'Smith' name - good again :)
and finally the real surprise - Pages 6, 7 and 8 contains same employees - having ID: 16, 17, 18, 19, 20

Don't you think something is wrong here ?! ;) Well, the reason of this strange error is visible when you check SQL queries generated by Hibernate:

for the first 5 rows and:


for the rows 6 - 10 (and similar for next pages).

What the heck?! - you may say - These beautiful SQL queries are suggested for pagination on Oracle's website - see Tom Kyte's article: On ROWNUM and Limiting Results - sure :) - but the one who implemented it in Hibernate didn't read this article too deeply, skipping this important part:

One important thing about using this pagination query is that the ORDER BY statement should order by something unique. If what you are ordering by is not unique, you should add something to the end of the ORDER BY to make it so.

As you see, correct JPQL query leads to invalid SQL query for Hibernate / Oracle combination, and the error shows himself only for some combinations of data in the database - it is very difficult to spot because of that.

Do you still think that libraries used by you are perfect? :)

PS: This article has been created thanks to one of my Colleagues - Joanna Głowińska - her awesome work on SQL queries in some of our projects lead me to the above thoughts.



Follow-ups:


This article has been republished on Dzone's Javalobby (08/27/2012), with interesting comments from Gavin King, Karl Peterbauer, Andrew Thorburn, and Tomasz Wermiński.

Monday, March 19, 2012

Suppressing FindBugs warnings

Few days ago I spoke with my Friend, Tomek, about suppressing FindBugs warnings. Here is brief summary of our conversation, which may be interesting for you.

There is one simple method for suppressing the FindBugs warnings - usage of edu.umd.cs.findbugs.annotations.SuppressWarnings annotation. Just add it in place where FindBugs reported problem, and use appropriate bug code.

You should start with adding com.google.code.findbugs:annotations:2.0.0 jar to the project dependencies. Then open bug reported by FindBugs, and find its code, like in this example:


Finally add something like this to the method holding the code marked by FindBugs:


That's all, clear the FindBugs markers, and run it again, the problem will not be reported in this place again.

Nice! Isn't it? - No, it isn't :( - Why you may ask? - Because there is another annotation in java.lang package with exactly the same name (!), used for suppressing different kind of warnings. Shouldn't it be used instead? - Well ...

Another question is if we want to add another jar to the project dependencies just for suppressing FindBugs warnings - thank God the FindBugs authors marked this annotation with retention policy 'CLASS', which means the jar will not be required when running the project (ex. in web application container).


Follow-ups:


This article has been republished on Dzone's Javalobby (03/23/2012), with interesting comment from Fabrizio Giudici.

He is right that even RUNTIME retention doesn't require the jar itself, as long as the classes coming from it are not referenced directly, ex. if you have class A annotated with annotation B coming from some jar, and you don't include this jar in runtime classpath, using A.class.getAnnotation(B.class) will cause an error as expected (because class B is not available on classpath), while A.class.getAnnotations() will silently ignore B in this case.

See also Why doesn't a missing annotation cause a ClassNotFoundException at runtime?

Wednesday, March 7, 2012

FindBugs and JSR-305

Suppose that group of developers work in parallel on parts of big project - some developers are working on service implementation, while others are working on code using this service. Both groups agreed on service API, and started working separately, having in mind the API assumptions...

Do you think this story will have happy end? Well, ... - maybe :) - there are tools which can help achieve it :) - one of them is FindBugs, supported with JSR-305 (annotations for software defect detection).

Let's take a look at the service API contract:


As you see there are annotations like @Nonnull or @CheckForNull added to the service method signatures. The purpose of their usage is to define the requirements for the method parameters (ex. identifier parameter cannot be null), and the expectations for the values returned by methods (ex. service method result can be null and you should check it in your code).

So what? - you may ask - should I check them in the code by myself or trust the co-workers that they will use the guidelines defined by those annotations? Of course not :) - trust no one, use the tools which will verify the API assumptions, like FindBugs.

Suppose that we have following service API usage:


Let's try to verify the code against the service API assumptions:


FindBugs will analyze your code, and switch to the FindBugs perspective showing potential problems:

Null passed for nonnull parameter
Possible null pointer dereference

Similar way, guys writing the service code may verify their work against defined API assumptions, for ex. if you run FindBugs for the very early version of service implementation:


Following error will be found:


As you see, nothing can hide from the FindBugs and his ally - JSR-305 ;)

Few links for the dessert:


Follow-ups:


This article has been republished on Java Code Geeks (03/15/2012) and Dzone's Javalobby (08/29/2012).

Sunday, February 19, 2012

Spring MVC - Flash Attributes

Latest Spring Framework incarnation (3.1) brought interesting feature called Flash Attributes. It is remedy for the problem mentioned a long time ago, in one of my posts: Spring MVC - Session Attributes handling. This problem can be described in few words: if we want to pass the attributes via redirect between two controllers, we cannot use request attributes (they will not survive the redirect), and we cannot use Spring's @SessionAttributes (because of the way Spring handles it), only ordinary HttpSession can be used, which is not very convenient.

Below you will find an example of Flash Attributes usage, before you start reviewing it, read Using flash attributes section of Spring documentation.

Suppose that we have two controllers: AController and BController, first one will prepare some data and pass to the second using Flash Attributes after the form submission. On the AController we will have something like this:
@RequestMapping(method = RequestMethod.POST)
public String handleFormSubmission(..., final RedirectAttributes redirectAttrs) {
    ...
    redirectAttrs.addFlashAttribute("AttributeName", value);
    return "redirect:to_some_url_handled_by_BController";
}
When the form will be submitted, attribute value will be stored as Flash Attribute named "AttributeName", and thanks to the Spring, will be passed to BController, where it can be used for example in following way:
@Controller
...
@SessionAttributes("AttributeName")
public class SearchCriteriaHandler {
    ...
    @RequestMapping(method = RequestMethod.GET)
    public void handleGetRequest(@ModelAttribute("AttributeName") final SomeType value) {
        ...
    }
    ...
}

Before your handler method will be called, Spring Framework will populate the Model with the available Flash Attributes - at this point value passed from AController will become a model attribute for the BController. Note, that because we also defined this attribute as the Session Attribute, it will be automatically stored for future usage within this controller, after the GET request handling.

Let me say that I was waiting for this feature for the long time, ;)

Related Posts: Spring MVC - Session Attributes handling

Saturday, January 7, 2012

EasyB, Thucydides and Selenium 2 - another BDD example

Today I'll present you quick example of usage for EasyB - BDD framework for Java :), accompanied by Thucydides - amazing tool for ATDD build on top of Selenium 2.

Suppose that you want to leave something for the humanity, after many sleepless nights you finally discover that it will be a movie database, even more: Internet Movie Database. Now, my Friend, you have two ways: you can start writing this service immediately, forgetting about the eating and sleeping ... When you'll find yourself abandoned by all your Friends, and lost completely in the endless code you wrote, without helpful hand from the tests you were too busy (or even worse, too proud) to wrote ... You'll find the path to enlightenment - second way. Slower, but built on rock solid foundations - ATDD, BDD, and maybe even few more acronyms ;)

Before you yell: "Teach me this way!" few words of explanation. I'm not the Master Yoda. I'm still learning, as you do, and will whole my life, but maybe some parts of my daily exercises will help you somehow ...

Back to the example :) - What we do first, is defining the core functionality required by our service, and describing it in EasyB syntax. Note that in this post we will focus on testing service only. Instead of writing the service, we will use existing Internet Movie Database, and verify if it matches our expectations:


What you see is one of the use cases I assumed for the service. How can we bring it to life now? For example, using Apache Maven, if you decide to choose it as a build system for your project, as I did.

What you need is adding to your pom.xml file few lines defining the EasyB plugin (under build/plugins section):


Now we may try to run this scenario and see what EasyB will tell us. We can do it for ex. with:
mvn clean test easyb:test
Report generated by EasyB looks like this one:


Interesting, but the real fun begins with Thucydides usage. First we have to get back to Apache Maven configuration, and change the report type generated by EasyB from HTML to the default one (XML), otherwise there will be nothing to process for Thucydides.


Now we may try to run our scenario in following way:
mvn clean test easyb:test thucydides:aggregate
and start admiring report generated by Thucydides, which looks like this one:

Summary Page
Features Summary
Stories Summary
Story Details
At this point you probably think - Gosh, looks nice, but how it can be useful for me, as the developer?!

Now we get to the clue :) - as you probably noticed, some steps defined in the scenario are in pending state. This is the moment when the Business Management Team role ends ;), and starts our own :), because we, as the Developers, have to implement the tests standing behind the scenarios. :)

You may also wonder if Thucydides role here is beautifying the reports only - of course not! - it shows its potential when we start to implement tests :).

Let's return to our scenario description:


First of all, we group all features and use cases of our application in 3 level structure - Application - Feature - Use Cases (Scenarios):


Now we implement the steps defined in scenario for the system:


and for the user:


And finally the code reflecting pages of the service, for welcome page:


and search results:


After implementing the code standing behind our scenario, we can run it again and compare the results with expectations:

Summary Page
Features Summary
Stories Summary
Story Details
Thucydides by default creates screenshots of tested application on each UI change (it can be changed to document step failures only), which you can see below:

Welcome page opened (Given)

Title search beginning (When)

UI change - Search Type selected

UI change - search query entered

UI change - form submitted

Search results verification (Then)
Quick summary at the end ;) - EasyB looks like the great tool for BDD, even more attractive when accompanied by Thucydides and Selenium 2. The example above is very quick and simple, but maybe interesting for you, if you are still reading my post ;)

Few lectures for the dessert: