Aug 22

I write web applications in Java, and have been doing so for some time now. I like to think that I’ve become pretty good at it, and I can usually get something working quickly and efficiently. This means that my choice of frameworks and tools is somewhat specialised, and others would make a different choice, perhaps Grails or Ruby on Rails. This article is not about which framework is superior to another, but rather what I’m currently using and why it’s good for me right now.

Next year, it should be different otherwise I’m not really progressing.

IDE

Intellij IDEA. I used to be an Eclipse evangelist, but then my friend Gareth introduced me to
Intellij and I never looked back. Well, maybe once or twice when I had to reorient myself within the new IDE, but once I got the hang of it then that was it. Everything just works really well, and the refactoring is amazing. Especially in XML and JavaScript. Oh, you thought refactoring was just for Java? I invite you to download the freebie version of Intellij and try out the goodness for yourself. If you’re a contractor like me you’ll find that the productivity increase pays for the IDE within a day or two.

Build systems

I’ve written about this before, but there is only one build system for me at the moment: Maven. I think it reduces the problem of creating portable builds (and environments) to a pretty simple format. It’s a pretty straightforward way of allowing a disparate team of developers to work on different aspects of a large project. In my opinion, a build system should be able to get a new developer productive within 30 minutes. That includes time reading the wiki to locate the appropriate project and check it out of version control. It also includes the time taken for the developer to figure out (using only the documentation) how to build and deploy it locally with a sample set of data and a demonstration page so they can see how the application is supposed to work. If your set up does not allow a developer to do this, then – seriously – look at your systems.

In Maven, the way I’ve got my stuff set up, you get a fully operational environment as described above by doing the following:

1) Check out your project from version control
2) Type mvn clean jetty:run at the command line in the project checkout directory
3) Navigate to localhost:8080/SomeApp in the browser (the wiki will tell you where to go)

That’s it, and it’s the same procedure for all applications at all tiers of the stack. The act of
issuing that command will automatically ensure that the correct supporting versions of any other JARs and WARs are downloaded, included and executed within the same Jetty instance. This gives a complete set of interactivity so that a developer knows they have a representative slice of the overall system. Not bad for a single memorable command, eh?

Web services with RESTEasy and JAXB

I used to use SpringMVC for my web front end. It remains an excellent implementation of the standard Model/View/Controller design pattern that made front end design much simpler than the frameworks that had gone before – I’m looking at Struts here. Now, I’m hooked on an even simpler framework that trivialises the whole creation of web services to a mere typing exercise: RESTEasy. Wow. What a revelation! I’m sure that in Spring 3+ they’ve done something similar (and I will take a look, I promise) but right now RESTEasy is my best friend. Here’s an example of creating a simple web service to respond to a GET request:

@Path("/hello")
public class Hello {
 @GET
 @Path("/{name}")
 public String example(@PathParam("name") String name) {
 return String.format("Hello, %s",name);
 }
}
HTTP GET /ExampleApp/hello/bob
Hello, bob

It’s difficult to imagine a simpler way of coding that service up. Nothing is wasted, the web.xml is trivial and the same for pretty much all the web services on the back end. And it integrates with Spring too. And JAXB. And JSON. And Maven. In fact, it’s damn near perfection.

And what’s so good about JAXB I hear you ask? Well, let me tell you. Take a POJO, apply some simple annotations and hand it over to RESTEasy. All that hard effort of turning it into XML or JSON or whatever for transmission to the outside world is all taken away. Consider a simple class that provides a list of Users formatted as a paged result set:

@XmlRootElement(name="Result")
public class Result {
 @XmlElementWrapper(name="Users")
 @XmlElement(name="User")
 private List<User> users=new ArrayList<User>();
 @XmlAttribute(name="firstResult")
 private int firstResult;
 @XmlAttribute(name="batchSize")
 public int getBatchSize() {
 return users.size();
 }
 public void setFirstResult(int firstResult) {
 this.firstResult=firstResult;
 }
}

Assume that User has been created and marked up in a similar fashion. Put this into a RESTEasy web service, like so

@Path("/search")
public class SearchService {
 UserDao userDao = new UserDao();
 @GET
 @Path("/{query}")
 public Result example(@PathParam("query") String query) {
 return userDao.search(query);
 }
}

You’ll see the following

HTTP GET /ExampleApp/search/bob
<Result firstResult="1" batchSize="1">
 <Users>
 <User>
 <Name>Bob</Name>
 </User>
 </Users>
</Result>

Neat and very obvious how it all works so maintenance issues drop off.

Database access with JPA Now I jumped on the Hibernate wagon with everyone else. It solved a huge problem in the ORM world in a neat and elegant manner. It also educated mere mortals into the proper way to think about the way our applications dealt with database issues. I’m thinking of sessions, lazy loading, avoiding the dredge anti-pattern, entity to table mappings and on and on.

In fact Hibernate was so good that it sparked a complete revisit of the awful EJB approaches so that EJB3 is actually palatable – if you’re starved of any alternative that is. I’m still not convinced that EJB is compatible with an Agile approach to development. I’ve not yet seen an EJB work efficiently in a Jetty environment that neatly supports JUnit integration testing against an in-memory HSQL database. Spring on the other hand manages that feat with ease, particularly in JUnit4.

One good thing about EJB3 is the creation of the JPA and JTA specifications, which formalised what had been going on in Hibernate for ages before. All those lovely annotations were ratified and the persistence layer took a major leap forward. As a developer this puts me in a good position where I can be ambivalent about the implementation technology behind the annotations. Want me to code up your DAOs using JPA and JPQL, that’s fine. Want the same done with Hibernate and HSQL, just gimme a mo to tweak some queries and you’re good to go.

Automated functional testing

I’ve discussed this elsewhere too, but I thought I’d include a mention here for completeness. No development stack is complete without catering for automated testing. Everyone reading this naturally has a unit test for everything – don’t you? You don’t?! You’d better get started then, ‘cos everyone else has. However, once you’ve got your unit tests working nicely with both dependency injection and mocking approaches. Which reminds me, I’d recommend JMockit over JMock these days due to it’s better handling of static methods which are sometimes forced on us by legacy code. Then it’s time to consider the functional testing. For some reason everyone seems to adopt the line of “Oooh, I’d love to do that but I just don’t have the time.”, which in my opinion doesn’t add up. Every developer should strive to make their days easier, and having the safety net of a  comprehensive set of functional tests is essential. Take a look at my detailed article on the most excellent SeleniumRC for more information.

Performance

With the above technologies, I can usually get a full-blown, integration tested RESTful web service off the ground and operational against a database within 2 hours. Most of that time is spent typing and configuring for the particular problem I’m facing. I know other frameworks exist that could speed that up (Appfuse and Spring Roo, er, spring to mind – sorry). And, yes,
I do have templates to solve standard problems. However, within the constraints imposed by my clients who want to use, or be guided into using, a particular technology, this is a pretty good delivery time.

Share
Jan 27

Nope. Well that was easy. Except you probably do.

According to the Don’t Repeat Yourself (DRY) principle, all code and reference material should have a single point of reference that is both unambiguous and easy to find.

Most major development efforts will be spread over several large projects. As a natural result of this there is going to be some duplication between, at least, the fundamental utility and data access classes. One approach in combating this duplication is to create a project that could absorb a lot of the commonality found in several diverse applications into a single module for inclusion in each.

As most developers know, the Apache Foundation have provided a vast array of common extensions to the Java language – some of which have been included in later versions of the language itself because they were so useful. However, as a taster, there are file utilities, specialised collections, string manipulation methods, date handlers, logging frameworks all of which provide a standardised approach to solving commonly found problems. Rather than roll your own library, why not take the best of breed from Apache and ask new developers coming to the company if they have familiarity with these libraries? The learning curve drops away the more you depend on freely available standard software.

Even after refactoring the existing code to use the various Apache Commons libraries, the size of the common project will increase. It is important to keep it focused so that it does not swell to be an all-encompassing uber-module that all projects must depend on. As the packages contained within the distributable JAR get too numerous, split them out into sub-modules that are highly targeted. A JAR for utilities, another for DAO interfaces, another for web utilities. Different projects can then use these highly specific, and loosely coupled, collections of foundation classes to meet their exact needs without needing a load of extraneous dependencies to also be included.

If you are using a build process like Maven then the issue of dependency management becomes trivial. Developers can make updates to the common modules and release new versions of the JAR into the company repository (managed by Artifactory for example). Other developers are unaffected until they decide to update their project file to include this higher release version. This allows them to continue without the new features saving the upgrade to a later time that suits them.

As these modules begin to grow in size it becomes difficult to keep track of all that useful code that your developers have spent a lot of time creating. It is at  this point you should consider introducing the role of a Code Librarian. This role, ancillary to normal development duties, is responsible for the maintenance of code that is deemed to be useful in more than one project. They can also assist with refactoring the original design of the code so that it fits with a wider audience. Typically the code librarian would sit in on code reviews, or be called over if doubt has arisen. They can then point out where the developer has written code themselves that should have been brought in from a common library, or to find ways of incorporating new code into the library.

The creation of a well-maintained centrally-managed code repository drastically reduces the amount of time and effort it takes to get a new project off the ground and out into production. It also greatly reduces the amount of developer time spent debugging. If the supporting documentation, such as a Wiki, contains good examples and references to other similar classes with slightly different applications then developers will quickly find themselves avoiding the re-invention of the wheel. For an example of this, take a look at the YUI framework documentation.

Share
Tagged with:
Jan 26

So you’ve implemented a bunch of unit tests and you’re feeling confident that your system works as expected. Then you realise that you now have to work through all those different use cases one by one every time you make a change just to be sure that you haven’t somehow broken the front end. Surely there must be a way of automating this process? There is, and it’s called Selenium.

In this article I’m going to focus on how to introduce Selenium into your development process assuming that you have developed a reasonably large web application based on Java technology. Selenium will work quite happily with a wide variety of other development languages, but since I’m not so familiar with them I’ll leave that to others to explain.

So, having lost 90% of my readers, I’ll struggle on.

I define a functional test as one that essentially mimics a user working through a particular collection of use cases. In the case of a web application, this means that a functional test needs to remotely control a browser; fill in various forms or click links; and verify that the responses from the server are as they should be. Typically in the Java world some variant of HttpUnit is used for this purpose but this only represents the behaviour of a single browser – the HttpUnit implementation.

As an aside, it should be noted that there is a strong correlation between functional tests and requirements. It is indeed possible to create a functional test matrix that allows requirements to be ticked off as their corresponding functional tests are seen to pass. This follows both the DRY principle and the Agile manifesto maxim of “Working code is the best metric”.

So what does Selenium do? Specifically, in it’s Selenium Remote Control (SeleniumRC) form it acts as a bridge between the browser and your automated build process. You write your tests in JUnit as usual ensuring that your assertions target the responses coming back from a Selenium browser object. For example:

selenium().open("http://localhost:8080/mywebapp/index.html");
assertTrue(selenium().isTextPresent("Hello World");

The selenium() method provides access to the underlying browser. If the assertion fails then the test case fails and the usual reporting mechanism takes over.

OK, so what is going on here? Essentially, selenium() communicates with a SeleniumRC server instance, which is just a single JAR running in the background somewhere, and instructs it to fire up a browser, point it at the given URL, wait for the page to load, then check if the given text is present in the response. Not bad for 2 lines of code. Now here is where SeleniumRC gets very clever: first, you can instruct it to fire up an instance of pretty much any browser you like; second, it will inject some JavaScript into the page which will allow Selenium to perform deep selections within the browser DOM.

That abstraction of the browser, and the corresponding deep inspection, makes Selenium extremely powerful when used in a large scale environment. Since Internet Explorer does not sit well with other versions it is usually necessary to create a collection of virtual machines each with their own version of IE and SeleniumRC installed. Other virtual machines can be created that allow Firefox, Opera, Chrome, Safari etc to be installed in a variety of combinations. However, the same suite of functional tests can be executed against them without change (so long as you use CSS selectors throughout otherwise IE runs like a dog). In a Maven environment this can be implemented as a series of executions each with a few environment parameters that can be passed to the test suite. The environment parameters indicate where the SeleniumRC server is to be found (the VM) and what browser it should target. For example (in build/plugin):

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<!-- Default configuration is to skip -->
<configuration>
 <skip>true</skip>
</configuration>
<executions>
 <execution>
 <!-- Test with Firefox 3 -->
 <id>1_functionalTestWithFirefox</id>
 <phase>verify</phase>
 <goals>
 <goal>test</goal>
 </goals>
 <configuration>
 <skip>${maven.test.skip}</skip>
 <environmentVariables>
 <selenium-rc.server-host>selenium-xp-ie7ff3</selenium-rc.server-host>
 <selenium-rc.server-port>4444</selenium-rc.server-port>
 <selenium-rc.browser-type>*chrome</selenium-rc.browser-type>
 </environmentVariables>
 </configuration>
 </execution>
</executions>
</plugin>

But wait, there’s more.

Since a functional test is considered as a collection of use cases it makes sense to structure the testing environment to follow this pattern. Essentially a series of standard unit tests are created with a FunctionalTest suffix to make their purpose clearly visible. These are usually packaged in line with the various system modules that they test. The functional test simply delegates to the use cases they wrap (passing in a reference to themselves to allow the use case to access test methods). Since there is a lot of common functionality between functional tests (such as the initial creation of the Selenium browser reference) it makes sense to introduce an abstract base class that provides these references. For example:

package org.example.web.functest.security;
@RunWith(BlockJUnit4ClassRunner.class)
public class LoginAdminFunctionalTest() extends AbstractWebTestCase {
  ...
  @Test
  public void loginAdmin() {

    LoginAdminUseCase login = new LoginAdminUseCase(this);
    login.execute();
  }
}

By contrast, the use cases are simply implementations of the Command pattern which do all the work. They have a UseCase suffix to allow for quick identification, and typically extend an abstract base class to provide useful common methods. Extending org.junit.Assert will provide direct access to assertion methods. For example:

package org.example.web.functest.security.usecase;
public class LoginAdminUseCase() extends AbstractUseCase {
  public LoginAdminUseCase(AbstractWebTestCase tester) {
    // The abstract super class provides various selenium methods via tester
    super(tester);
  }

  public void execute() {

    selenium().windowMaximize();
    selenium().deleteAllVisibleCookies();

    // Obviously the URL here would be passed
    // as a parameter by the build process
    selenium().open("http://localhost:8080/mywebapp/login.html");

    // Assumes that AbstractUseCase extends Assert
    assertEquals("My Login Page", selenium().getTitle());

    selenium().type("username", "admin");
    selenium().type("password", "admin");
    selenium().click("submit");

    // Convenience method to introduce standard short delay
    waitForPageToLoad();

    assertEquals("Administration console", selenium().getTitle());

  }
}

Any number of functional tests could re-use the LoginAdminUseCase in any combination. It would be trivial to include a LogoutUseCase that clicked a common logout link. In fact, at the end of every test as part of the tearDown() sequence the LogoutUseCase could be invoked.

I have glossed over several important implementation details in the interests of brevity. For example, the issue of what acts as the container for the web application, and how this can be invoked before testing starts. My favoured approach to this is twofold: one for developers the other for continuous integration servers.

The developer version uses Jetty to act as a lightweight servlet container that can be stopped and started very quickly; is responsive to changes in the web application (e.g. a JSP or CSS adjustment) while running; and allows for programmatic configuration within the functional test module. This allows a developer to work in a much smaller environment with perhaps a single functional test driving their work so there is very little repetitive typing or page navigation going on. Since the environment responds immediately to changes very rapid progress can be made.

By contrast, the continuous integration version relies on Maven to start and stop some larger application container that is representative of the final deployment environment. In the case of Glassfish this is the asadmin plugin, but others exist for different containers (notably the general purpose deployment plugin for Cargo).

In addition to the container, the database must also be regulated so that provides predictable results. Usually, after the application container has been stopped a script is executed against the database to drop all objects and rebuild. Clearly the test database is a minimal subset of the actual production schema. It must be large enough to allow a wide range of use cases to be explored, but small enough so that it doesn’t dominate the build process.

Once the application container is restarted, then the build process can begin the functional test suite with each of a variety of browsers being targeted at the system under test. The individual functional test results are collected and presented as part of the final build result.

Share
Tagged with:
Jan 26

In this article I aim to examine whether or not stored procedures should be used instead of Hibernate based queries. I’ll assume that both Java developers and DBAs are likely to be reading this, so here is a quick glossary of common design patterns found in Hibernate applications:

Data Transfer Objects (DTOs) are used to transfer state information between layers in an application. They tend to represent the business domain and it’s relationships quite closely, and contain mapping information so that they can be persisted within the database.

Data Access Objects (DAOs) are used to perform all persistence operations: creating, retrieving, updating and deleting data from the database by means of manipulating DTOs. If a DTO is deleted, this is mapped to a SQL delete operation on the database.

Object/Relational Mapping (ORM) is the process by which application business state is transferred into relational data.

Assumptions

The issue of whether to go wholly for a Hibernate based query approach, or, on the other side of the coin, a wholly stored procedure one is highly contentious with many strong arguments being presented for and against either approach. So let’s start by introducing some important assumptions:

1) both developers and DBAs are working for the same company and so are attempting to achieve the same objective of a simple to use process that promotes good practice;

2) the choice of RDBMS is not going to change in the near future so database independence is not an issue;

3) any move away from an entirely stored procedure approach will remove the burden of data consistency from the DBAs and place it on the application development team (programmers with DBAs acting as advisors);

4) the issue of “dynamic SQL” where SQL statements are created on the fly by, for example, concatenating strings without using parameters is not acceptable under any circumstances (do I hear SQL injection attack?) so all SQL generated within the application can be assumed to be parameterised;

5) application generated SQL is assumed to have come from an O/R mapping solution, such as Hibernate, not directly coded into the application;

6) long running queries acting on millions of rows are expected to be run as stored procedures since the network cost of moving the data over the wire would outweigh any performance improvement available through highly optimized application code.

Overall, there are only 3 choices available: persistence entirely through stored procedures; entirely through Hibernate; or a hybrid approach. Within the hybrid approach there is only the degree to which stored procedures are used within the application.

I have found that here are many myths and arguments associated with the stored procedure vs application SQL debate which collapse under close scrutiny. Here are a few (I’m sure that there are more):

1) Debugging stored procedures is hard

Many developers become used to working within a single IDE, and feel uncomfortable when forced to move outside it. In the case of stored procedures, it is frequently necessary for a Java developer to make use of an application such as Toad or JDeveloper to pick their way through a difficult SQL statement. To use this as an excuse not to use stored procedures is just laziness. The tools are there – learn to use them.

2) Stored procedures improve security

By only permitting data retrieval through stored procedures the impact of inappropriate or erroneous queries against the tables is greatly reduced leading to improved data security. Hmm. The only security that stored procedures provides is through the login credentials of the connecting user. If the application can delete users, then the connecting user can do so, if only by calling the stored procedure instead of typing in the SQL.

3) Stored procedures are faster than application SQL

While stored procedures are often considered to be the equivalent of assembly language for an RDBMS, the perceived performance gain is not always met. Almost all RDBMS implementations provide a caching mechanism such that the first time a query is encountered it incurs a performance penalty while it is parsed and compiled. Subsequent calls can immediately take advantage of the pre-compiled version and it doesn’t matter if this comes from within the RDBMS or the calling application. There are some very clever people behind these compilers and they will create a near optimal SQL statement. I’ll assume that the network lag for actually transmitting the query is assumed to be negligible.

For completeness, the case of stored procedures for update routines should be mentioned. An application can easily generate optimal update SQL for a single field involving a single parameter. In contrast, a stored procedure implementation will normally end up having to provide an “all fields” update mechanism with nullable parameters. This in turn leads to null checking logic within the stored procedure that is technically unnecessary.

Also important is that a stored procedure can take advantage of specialized functions available in the database that a generalized mapping solution, such as Hibernate, cannot emulate. There is, of course, the possibility of hard coded native SQL in the application but this should be frowned upon.

4) Stored procedures provide a single point of update

Given that all retrieval operations come from stored procedures, then any change to the implementation of those stored procedures is conducted behind the scenes and does not affect the applications that depend on it. Thus exclusive use of stored procedures introduces a single point of update should refactoring need to take place.

I agree that this is true up to a point, but consider the situation when an additional column is added to a table that needs to be included in the application. All stored procedures will need updating to include the new field, which will probably involve changing the signature of the stored procedure. This in turn will require that code in the application must be changed to support the new signature (even if the application does not make use of the new field).

Clearly this update process can be optimized, perhaps through versioned stored procedures or overloading with additional parameters, but the application is never completely isolated from the database. Over the course of time a large number of variants on the same theme may appear if multiple applications are served through the same API.

ORM frameworks like Hibernate overcome this by only including the required fields in their queries and relying on nullable fields being present. This helps to decouple them from changes to the underlying resultsets due to additional fields.

5) Data remains consistent because of stored procedures

A common argument for the use of stored procedures maintains that there is a guarantee that the data will always be consistent. This comes about due to a misunderstanding in the use of the term consistency. Consider the case when an application calls a sequence of stored procedures in order to fulfill a business process, but due to a coding error the last one is missed out.

The database is consistent from a mathematical point of view, but from a semantic point of view it is incomplete. If this sequence of calls was entirely within the application then only the developers can be blamed for the semantic error, whereas by forcing stored procedures then it is difficult to apportion blame – the database didn’t complain so it must be right.

In response, the DBA will necessarily have to include business logic in the stored procedures to enforce semantic consistency which negates the reasoning behind using stored procedures in the first place.

6) Stored procedures are application neutral

Once the API is written for the schema then any application can make use of them. Queries buried within JAR files tend to bind an application to a particular object model that may not be suitable.

This can be overcome by ensuring that application queries do not stray outside of the persistence layer, and that the persistence layer is designed against the specific requirements of the application which uses it. Reusable DTOs can then be ported to a common persistence framework but this does lead to a fair amount of complexity within the persistence layer dependency tree. I’d suggest using dependency management frameworks such as Maven or Ivy which can manage this transparently for you.

In order to make this approach work in the pure stored procedure approach, it is necessary to ensure that no knowledge of the database schema is present within the application. Table names should not be available, and columns and their types should be mapped internally to arbitrary names that are presented only through resultsets from the stored procedures. Therefore the application targets an abstract model presented by the stored procedure API which will completely decouple the application from any changes made behind the scenes.

Clearly, the creation of such an abstract model, in addition to that of the schema, is no easy task and the benefits it brings may be questionable. Is it really worth the effort?

7) Stored procedures make it obvious where the SQL is

Stored procedures benefit from easy and obvious navigation – they are in the database API packages. In addition, all databases provide a wealth of tools to both profile and subsequently optimize the queries as part of the development process, rather than as an afterthought when performance degradation is noticed.

In the application, the actual SQL being run is buried in the depths of the mapping framework and usually only appears in the debug logs. The location in the application code where this query is constructed is not always clear – it should be in the DAOs but can be hidden in annotations on DTOs. Consequently, it takes some time and skill to identify where the query is being constructed, and how to alter the structure to make it more efficient. However, by following well known design patterns for entity mapping, these inefficiencies can be ironed out early and permanently.

8) Hibernate is slow because it makes unnecessary calls

Hibernate can be made slow through the inappropriate use of eager fetching strategies where unnecessary associations are explored. This is known as the Dredge anti-pattern. If Hibernate is configured to only use lazy fetching then it can provide the optimal solution for data retrieval, outperforming stored procedures in some cases.

This bold statement needs an example to back it up. Consider the situation of a 3 way relationship between User, Role and Authority. The requirement is to fetch all Users with a first name of “Bob” (a set of 10 Users), along with all their Roles and Authorities. Hibernate can build this object graph in 3 queries: one for each entity followed by application side merging.

In contrast, a pure stored procedure approach will require a routine to filter on the User table to get the ones with the correct first name. Then the Role fetch routine will have to be called to get the Roles for each of the Users, then the Authorities fetch routine will have to be called for each of the Roles. This could lead to a very large number of procedure calls.

Clearly, an alternative would be a single procedure for that specific purpose that returns a union of the tables with inner joins as required, and an assortment of parameters for the filtering. Even then, the resultset will still have to be mapped so the gain from using a stored procedure becomes questionable, especially when the equivalent Hibernate query is 2 lines of obvious code.

9) Hibernate is slow because the SQL generated by the Criteria interface is not consistent

It has been said that Hibernate can also incur a performance hit if all queries are constructed through the Criteria interface instead of directly in HQL. The argument posits that this is because every time the query builder code is executed, say in a DAO, Hibernate will generate new alias names for the tables in the query. In Oracle this means that every time a new Criteria-based query is run, the database must create a QEP – query execution plan – as it is unable to match the SQL it has been given to any in its cache. Creating the QEP can take 30% of the time it takes for Oracle to respond to a SQL statement, so for the second and subsequent executions of the same (but for alias names) SQL statement, Criteria has a built-in overhead that makes it 50% slower than direct HQL.

This is no longer the case with Hibernate 3.3 and above. If it was ever true at all is in doubt since the Hibernate team would certainly aim to create optimal SQL wherever possible. Independent tests demonstrate that the same query is generated by the Criteria interface after repeated calls spanning transactions which is the equivalent of running the application under load. In each case the query remained identical and was therefore able to be cached by Oracle.

There is one grain of truth, though, in that it is necessary to create the query every time using the Criteria interface, whereas using named queries defined in HQL allows for precompilation during application start-up. However, this needs some perspective. The time taken to create a simple “between” query using the Criteria interface is approximately 3ms on an average PC. Embedding HQL within the application is not a good alternative since it does not lead to an intuitive mechanism for maintaining queries with differing fetching strategies, and so the Criteria based approach is deemed the better of the two.

10) Hibernate is difficult to learn

OK, now we’re getting desperate. Constructing a good persistence layer is difficult, regardless of the underlying ORM framework being used. Hibernate provides a wealth of useful tools to reduce the complexity of the resulting layer. In addition there are many examples of how to use Hibernate to solve various persistence problems. Examples include mapping a many to many relationship with attributes; creating an object hierarchy within a single table using discriminators; and managing lazy loading scenarios outside of the persistence layer to name but a few.
Given a sufficient set of examples and a good ER diagram, any reasonable developer should be able to map out DAOs and DTOs for an arbitrary schema in a matter of hours.

Conclusions

Hibernate should be default choice for persistence operations.
When it comes to mapping and then persisting large graphs of DTOs the amount of code that needs to be written is minimal, frequently only requiring a single line of code. Careful construction of DAOs and DTOs using Java generics to enforce type safety further reinforces what is already an excellent persistence framework. The vast majority of work will be conducted by developers in the application domain, using object oriented programming techniques, so it makes sense to provide them with an object persistence model that reduces the complexity of the application.

Share
Tagged with:

You should follow me on TwitterYou should follow me on Twiiter here.

preload preload preload