This chapter covers
2.1 Starting a Hibernate project
2.1.4 Running and testing the application
To run the application, you need to compile it first and start the database manage-ment system with the right database schema.
Ant is a powerful build system for Java. Typically, you’d write a build.xml file for your project and call the build targets you defined in this file with the Ant command-line tool. You can also call Ant targets from your Java IDE, if that is supported.
Compiling the project with Ant
You’ll now add a build.xml file and some targets to the “Hello World” project. The initial content for the build file is shown in listing 2.8—you create this file directly in your WORKDIR.
<project name="HelloWorld" default="compile" basedir=".">
<!-- Name of project and version -->
<property name="proj.name" value="HelloWorld"/>
<property name="proj.version" value="1.0"/>
<!-- Global properties for this build -->
<property name="src.java.dir" value="src"/>
<property name="lib.dir" value="lib"/>
<property name="build.dir" value="bin"/>
<!-- Classpath declaration -->
<path id="project.classpath">
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
<include name="**/*.zip"/>
</fileset>
Listing 2.8 A basic Ant build file for “Hello World”
</path>
<!-- Useful shortcuts -->
<patternset id="meta.files">
<include name="**/*.xml"/>
<include name="**/*.properties"/>
</patternset>
<!-- Clean up -->
<target name="clean">
<delete dir="${build.dir}"/>
<mkdir dir="${build.dir}"/>
</target>
<!-- Compile Java source -->
<target name="compile" depends="clean">
<mkdir dir="${build.dir}"/>
<target name="copymetafiles">
<copy todir="${build.dir}">
<target name="run" depends="compile, copymetafiles"
description="Build and run HelloWorld">
<java fork="true"
The first half of this Ant build file contains property settings, such as the project name and global locations of files and directories. You can already see that this build is based on the existing directory layout, your WORKDIR (for Ant, this is the same directory as the basedir). The default target, when this build file is called with no named target, is compile.
Next, a name that can be easily referenced later, project.classpath, is defined as a shortcut to all libraries in the library directory of the project. Another shortcut for a pattern that will come in handy is defined as meta.files. You need to handle configuration and metadata files separately in the processing of the build, using this filter.
The clean target removes all created and compiled files, and cleans the project. The last three targets, compile, copymetafiles, and run, should be self-explanatory. Running the application depends on the compilation of all Java source files, and the copying of all mapping and property configuration files to the build directory.
Now, execute ant compile in your WORKDIR to compile the “Hello World”
application. You should see no errors (nor any warnings) during compilation and find your compiled class files in the bin directory. Also call ant copymetafiles once, and check whether all configuration and mapping files are copied correctly into the bin directory.
Before you run the application, start the database management system and export a fresh database schema.
Starting the HSQL database system
Hibernate supports more than 25 SQL database management systems out of the box, and support for any unknown dialect can be added easily. If you have an existing database, or if you know basic database administration, you can also replace the configuration options (mostly connection and dialect settings) you created earlier with settings for your own preferred system.
To say hello to the world, you need a lightweight, no-frills database system that is easy to install and configure. A good choice is HSQLDB, an open source SQL database management system written in Java. It can run in-process with the main application, but in our experience, running it stand-alone with a TCP port listening for connections is usually more convenient. You’ve already copied the hsqldb.jar file into the library directory of your WORKDIR—this library includes both the database engine and the JDBC driver required to connect to a run-ning instance.
To start the HSQLDB server, open up a command line, change into your WORKDIR, and run the command shown in figure 2.4. You should see startup mes-sages and finally a help message that tells you how to shut down the database sys-tem (it’s OK to use Ctrl+C). You’ll also find some new files in your WORKDIR, starting with test—these are the files used by HSQLDB to store your data. If you want to start with a fresh database, delete the files between restarts of the server.
You now have an empty database that has no content, not even a schema. Let’s create the schema next.
Exporting the database schema
You can create the database schema by hand by writing SQL DDL with CREATE statements and executing this DDL on your database. Or (and this is much more convenient) you can let Hibernate take care of this and create a default schema for your application. The prerequisite in Hibernate for automatic generation of SQLDDL is always a Hibernate mapping metadata definition, either in XML map-ping files or in Java source-code annotations. We assume that you’ve designed and implemented your domain model classes and written mapping metadata in XML as you followed the previous sections.
The tool used for schema generation is hbm2ddl; its class is org.hibernate.
tool.hbm2ddl.SchemaExport, so it’s also sometimes called SchemaExport. There are many ways to run this tool and create a schema:
■ You can run <hbm2ddl> in an Ant target in your regular build procedure.
■ You can run SchemaExport programmatically in application code, maybe in your HibernateUtil startup class. This isn’t common, however, because you rarely need programmatic control over schema generation.
■ You can enable automatic export of a schema when your SessionFactory is built by setting the hibernate.hbm2ddl.auto configuration property to create or create-drop. The first setting results in DROP statements fol-lowed by CREATE statements when the SessionFactory is built. The second setting adds additional DROP statements when the application is shut down and the SessionFactory is closed—effectively leaving a clean database after every run.
Figure 2.4 Starting the HSQLDB server from the command line
Programmatic schema generation is straightforward:
Configuration cfg = new Configuration().configure();
SchemaExport schemaExport = new SchemaExport(cfg);
schemaExport.create(false, true);
A new SchemaExport object is created from a Configuration; all settings (such as the database driver, connection URL, and so on) are passed to the SchemaExport constructor. The create(false, true) call triggers the DDL generation process, without any SQL printed to stdout (because of the false setting), but with DDL immediately executed in the database (true). See the SchemaExportAPI for more information and additional settings.
Your development process determines whether you should enable automatic schema export with the hibernate.hbm2ddl.auto configuration setting. Many new Hibernate users find the automatic dropping and re-creation on Session-Factory build a little confusing. Once you’re more familiar with Hibernate, we encourage you to explore this option for fast turnaround times in integration test-ing.
An additional option for this configuration property, update, can be useful during development: it enables the built-in SchemaUpdate tool, which can make schema evolution easier. If enabled, Hibernate reads the JDBC database metadata on startup and creates new tables and constraints by comparing the old schema with the current mapping metadata. Note that this functionality depends on the quality of the metadata provided by the JDBC driver, an area in which many driv-ers are lacking. In practice, this feature is therefore less exciting and useful than it sounds.
WARNING We’ve seen Hibernate users trying to use SchemaUpdate to update the schema of a production database automatically. This can quickly end in disaster and won’t be allowed by your DBA.
You can also run SchemaUpdate programmatically:
Configuration cfg = new Configuration().configure();
SchemaUpdate schemaUpdate = new SchemaUpdate(cfg);
schemaUpdate.execute(false);
The false setting at the end again disables printing of the SQLDDL to the con-sole and only executes the statements directly on the database. If you export the DDL to the console or a text file, your DBA may be able to use it as a starting point to produce a quality schema-evolution script.
Another hbm2ddl.auto setting useful in development is validate. It enables SchemaValidator to run at startup. This tool can compare your mapping against
the JDBC metadata and tell you if the schema and mappings match. You can also run SchemaValidator programmatically:
Configuration cfg = new Configuration().configure();
new SchemaValidator(cfg).validate();
An exception is thrown if a mismatch between the mappings and the database schema is detected.
Because you’re basing your build system on Ant, you’ll ideally add a schemaex-port target to your Ant build that generates and exports a fresh schema for your database whenever you need one (see listing 2.9).
<taskdef name="hibernatetool"
classname="org.hibernate.tool.ant.HibernateToolTask"
classpathref="project.classpath"/>
<target name="schemaexport" depends="compile, copymetafiles"
description="Exports a generated schema to DB and file">
<hibernatetool destdir="${basedir}">
<classpath path="${build.dir}"/>
<configuration
configurationfile="${build.dir}/hibernate.cfg.xml"/>
<hbm2ddl drop="true"
create="true"
export="true"
outputfilename="helloworld-ddl.sql"
delimiter=";"
format="true"/>
</hibernatetool>
</target>
In this target, you first define a new Ant task that you’d like to use, Hiber-nateToolTask. This is a generic task that can do many things—exporting an SQL DDL schema from Hibernate mapping metadata is only one of them. You’ll use it throughout this chapter in all Ant builds. Make sure you include all Hibernate libraries, required third-party libraries, and your JDBC driver in the classpath of the task definition. You also need to add the hibernate-tools.jar file, which can be found in the Hibernate Tools download package.
Listing 2.9 Ant target for schema export
The schemaexport Ant target uses this task, and it also depends on the com-piled classes and copied configuration files in the build directory. The basic use of the <hibernatetool> task is always the same: A configuration is the starting point for all code artifact generation. The variation shown here, <configuration>, understands Hibernate XML configuration files and reads all Hibernate XML mapping metadata files listed in the given configuration. From that information, an internal Hibernate metadata model (which is what hbm stands for everywhere) is produced, and this model data is then processed subsequently by exporters. We discuss tool configurations that can read annotations or a database for reverse engineering later in this chapter.
The other element in the target is a so-called exporter. The tool configuration feeds its metadata information to the exporter you selected; in the preceding example, it’s the <hbm2ddl> exporter. As you may have guessed, this exporter understands the Hibernate metadata model and produces SQLDDL. You can con-trol the DDL generation with several options:
■ The exporter generates SQL, so it’s mandatory that you set an SQL dialect in your Hibernate configuration file.
■ If drop is set to true, SQLDROP statements will be generated first, and all tables and constraints are removed if they exist. If create is set to true, SQL CREATE statements are generated next, to create all tables and constraints. If you enable both options, you effectively drop and re-create the database schema on every run of the Ant target.
■ If export is set to true, all DDL statements are directly executed in the data-base. The exporter opens a connection to the database using the connec-tion settings found in your configuraconnec-tion file.
■ If an outputfilename is present, all DDL statements are written to this file, and the file is saved in the destdir you configured. The delimiter charac-ter is appended to all SQL statements written to the file, and if format is enabled, all SQL statements are nicely indented.
You can now generate, print, and directly export the schema to a text file and the database by running ant schemaxport in your WORKDIR. All tables and con-straints are dropped and then created again, and you have a fresh database ready.
(Ignore any error message that says that a table couldn’t be dropped because it didn’t exist.)
Check that your database is running and that it has the correct database schema. A useful tool included with HSQLDB is a simple database browser. You can call it with the following Ant target:
<target name="dbmanager" description="Start HSQLDB manager">
<java
classname="org.hsqldb.util.DatabaseManagerSwing"
fork="yes"
classpathref="project.classpath"
failonerror="true">
<arg value="-url"/>
<arg value="jdbc:hsqldb:hsql://localhost/"/>
<arg value="-driver"/>
<arg value="org.hsqldb.jdbcDriver"/>
</java>
</target>
You should see the schema shown in figure 2.5 after logging in.
Run your application with ant run, and watch the console for Hibernate log output. You should see your messages being stored, loaded, and printed. Fire an SQL query in the HSQLDB browser to check the content of your database directly.
You now have a working Hibernate infrastructure and Ant project build. You could skip to the next chapter and continue writing and mapping more complex business classes. However, we recommend that you spend some time with the
Figure 2.5 The HSQLDB browser and SQL console
“Hello World” application and extend it with more functionality. You can, for example, try different HQL queries or logging options. Don’t forget that your database system is still running in the background, and that you have to either export a fresh schema or stop it and delete the database files to get a clean and empty database again.
In the next section, we walk through the “Hello World” example again, with Java Persistence interfaces and EJB 3.0.