Working with Hibernate in Eclipse
Pages: 1, 2, 3, 4, 5
Actually, on further reflection, because you can only work with a
Query while you've got an active Session, the methods
offered by the DAOs already work the best way they possibly can. You're always
going to have to do your own session management if you want to work with the
query the way I do in this example. You could embed the session management into
the business logic provided in "your" half of the DAO, though, which would give
you the best of both worlds. That's another reason the split-class model offered
by Hibernate Synchronizer is so useful. I explore this insight a bit below.
Anyway, here's the code I first came up with, morally quite equivalent to that on pages 48-49 of the book:
package com.oreilly.hh;
import java.sql.Time;
import java.util.ListIterator;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Query;
import net.sf.hibernate.Session;
import com.oreilly.hh.dao.TrackDAO;
import com.oreilly.hh.dao._RootDAO;
/**
* Use Hibernate Synchronizer's DAOs to run a query
*/
public class QueryTest3 {
public static void main(String[] args) throws HibernateException {
// Load the configuration file and get a session
_RootDAO.initialize();
Session session = _RootDAO.createSession();
try {
// Print the tracks that will fit in five minutes
Query query = session.getNamedQuery(
TrackDAO.QUERY_COM_OREILLY_HH_TRACKS_NO_LONGER_THAN);
query.setTime("length", Time.valueOf("00:05:00"));
for (ListIterator iter = query.list().listIterator() ;
iter.hasNext() ; ) {
Track aTrack = (Track)iter.next();
System.out.println("Track: \"" + aTrack.getTitle() +
"\", " + aTrack.getPlayTime());
}
} finally {
// No matter what, close the session
session.close();
}
}
}
One nice feature that TrackDAO does give us is a static
constant by which we can request the named query, eliminating any chances of
run-time errors due to typos in string literals. I appreciate that! Setting up
and executing a Run configuration for this test class produces the output I'd
expect, as shown in Figure 22.

Figure 22. The query results in Eclipse's console view
As I noted above, after getting this class working, I
realized there was a better way to approach it, given the model offered by
Hibernate Synchronizer. Here's what our TrackDAO object would look
like if we moved the query inside of it, which is where it really belongs, given
that the named query is a feature of the mapping file associated with that data
access object:
package com.oreilly.hh.dao;
import java.sql.Time;
import java.util.List;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Query;
import net.sf.hibernate.Session;
import com.oreilly.hh.base.BaseTrackDAO;
/**
* This class has been automatically generated by Hibernate Synchronizer.
* For more information or documentation, visit The Hibernate Synchronizer page
* at http://www.binamics.com/hibernatesync or contact Joe Hudson at joe@binamics.com.
*
* This is the object class that relates to the TRACK table.
* Any customizations belong here.
*/
public class TrackDAO extends BaseTrackDAO {
// Return the tracks that fit within a particular length of time
public static List getTracksNoLongerThan(Time time)
throws HibernateException
{
Session session = _RootDAO.createSession();
try {
// Print the tracks that will fit in five minutes
Query query = session.getNamedQuery(
QUERY_COM_OREILLY_HH_TRACKS_NO_LONGER_THAN);
query.setTime("length", time);
return query.list();
} finally {
// No matter what, close the session
session.close();
}
}
}
This is nice and clean, and it simplifies the main() method in
QueryTest3 even more:
public static void main(String[] args) throws HibernateException {
// Load the configuration file and get a session
_RootDAO.initialize();
// Print the tracks that fit in five minutes
List tracks = TrackDAO.getTracksNoLongerThan(Time.valueOf("00:05:00"));
for (ListIterator iter = tracks.listIterator() ;
iter.hasNext() ; ) {
Track aTrack = (Track)iter.next();
System.out.println("Track: \"" + aTrack.getTitle() +
"\", " + aTrack.getPlayTime());
}
}
Clearly this is the approach to take when working with named queries and Hibernate Synchronizer. A quick test confirms that it produces the same output, and it's much better code.
Whether or not you want to use Hibernate Synchronizer to generate its own style of data access objects, there is one last major feature to explore.
Editing Mappings
One of the main attractions of Hibernate Synchronizer is its specialized editor for mapping documents. This editor can be configured to automatically regenerate the associated data objects whenever you save files, but that's just a final touch; you might want to use the editor even if you're not using the plugin's code generator. It gives you smart completion of mapping document elements, and a graphical outline view in which you can manipulate them, as well.
There is a trick to getting the editor to work for you, though, at least if
you're starting from the downloaded source code from my Developer's Notebook. In
the download, the mapping documents are named with the extension
".hbm.xml," and the editor is only invoked for files ending with
".hbm". In theory, you can configure the extension mappings within
Eclipse so that both extensions use the plugin's mapping document editor, but I
wasn't able to get that to work, and I saw that someone else on the support
forum had the same problem. So, at least for now, your best bet may be to rename
the files. (If you're going to stick with Ant-based standard code generation, be
sure to update the codegen target in build.xml to use the
new extension, too.)
As soon as I renamed Track.hbm.xml to Track.hbm, its icon in the Package Explorer was updated to look like the Hibernate logo, and the default editor became the plugin's, as shown in Figure 23. For whatever reason, the other Hibernate Synchronizer options (as shown in Figure 17) are available with either extension, but the editor is available only with the shorter version.

Figure 23. The contextual menu for a Hibernate mapping document (with the extension ".hbm")
The editor has context-sensitive completion support for all of the elements you're adding within the mapping document. Figure 24 shows a couple of examples, but no screen shots can really capture the depth and usefulness of a feature like this; I'd very much encourage you to install the plugin and play with it yourself for a while. You will quickly see how helpful it can be in working with mapping documents.


Figures 24 and 25. Completion assistance in the mapping document editor
The outline view, shown in Figure 26, gives you a graphical view of the hierarchy of classes, their mapped elements, named queries, and the like that are present in your mapping document, as well as giving you a menu offering a few wizards to help you create new ones.
![]() |
![]() |
Figures 26 and 27. The mapping editor's outline view, and the "Add property" wizard
The contextual menu within the editor itself also offers a Format
Source Code option you can use to clean up and re-flow the document.
There are already many neat and useful features in this editor, and it'll be
interesting to see how it grows in the future. My only complaint (and a minor
one at that) is that this editor uses a very different approach to helping you
manage quotation marks when you complete XML attributes than the JDT does in
Java code. Switching back and forth between them can be somewhat disorienting.
(The way the JDT works takes a little getting used to itself, but once you start
trusting it, it's almost magical.)

