|
We also need to add some new pieces to our build file,
shown in Example 2-5. This is a somewhat substantial
addition, because we need to compile our Java source in order to use
the schema generation tool, which relies on reflection to get its
details right. Add these targets right before the closing
</project> tag at the end of
build.xml.
Example 2-5. Ant build file additions for compilation and schema generation
1 <!-- Create our runtime subdirectories and copy resources into them -->
2 <target name="prepare" description="Sets up build structures">
3 <mkdir dir="${class.root}"/>
4
5 <!-- Copy our property files and O/R mappings for use at runtime -->
6 <copy todir="${class.root}" >
7 <fileset dir="${source.root}" >
8 <include name="**/*.properties"/>
9 <include name="**/*.hbm.xml"/>
10 </fileset>
11 </copy>
12 </target>
13
14 <!-- Compile the java source of the project -->
15 <target name="compile" depends="prepare"
16 description="Compiles all Java classes">
17 <javac srcdir="${source.root}"
18 destdir="${class.root}"
19 debug="on"
20 optimize="off"
21 deprecation="on">
22 <classpath refid="project.class.path"/>
23 </javac>
24 </target>
25
26 <!-- Generate the schemas for all mapping files in our class tree -->
27 <target name="schema" depends="compile"
28 description="Generate DB schema from the O/R mapping files">
29
30 <!-- Teach Ant how to use Hibernate's schema generation tool -->
31 <taskdef name="schemaexport"
32 classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask"
33 classpathref="project.class.path"/>
34
35 <schemaexport properties="${class.root}/hibernate.properties"
36 quiet="no" text="no" drop="no" delimiter=";">
37 <fileset dir="${class.root}">
38 <include name="**/*.hbm.xml"/>
39 </fileset>
40 </schemaexport>
41 </target>
First we add a prepare target that is intended to
be used by other targets more than from the command line. Its purpose
is to create, if necessary, the classes
directory into which we're going to compile, and
then copy any properties and mapping files found in the
src directory hierarchy to corresponding
directories in the classes hierarchy. This
hierarchical copy operation (using the special
"**/*" pattern) is a nice feature
of Ant, enabling us to define and edit resources alongside to the
source files that use them, while making those resources available at
runtime via the class loader.
The aptly named compile target at line 14 uses the built-in java task
to compile all the Java source files found in the
src tree to the classes
tree. Happily, this task also supports the project class path
we've set up, so the compiler can find all the
libraries we're using. The
depends="prepare" attribute in the target
definition tells Ant that before running the
compile target, prepare must be
run. Ant manages dependencies so that when you're
building multiple targets with related dependencies, they are
executed in the right order, and each dependency gets executed only
once, even if it is mentioned by multiple targets.
If you're accustomed to using shell scripts to
compile a lot of Java source, you'll be surprised by
how quickly the compilation happens. Ant invokes the Java compiler
within the same virtual machine that it is using, so there is no
process startup delay for each compilation.
Finally, after all this groundwork, we can write the target we really
wanted to! The schema target (line 26) depends on compile, so all
our Java classes will be compiled and available for inspection when
the schema generator runs. It uses taskdef
internally at line 31 to define the
schemaexport task that runs the Hibernate
schema
export tool, in the same way we provided access to the code
generation tool at the top of the file. It then invokes this tool and
tells it to generate the database schema associated with any mapping
documents found in the classes tree.
There are a number of parameters you can give the schema export tool
to configure the way it works. In this example (at line 35) we're telling it to display
the SQL it runs so we can watch what it's doing
(quiet="no"), to actually interact with the
database and create the schema rather than simply writing out a DDL
file we could import later or simply deleting the schema
(text="no", drop="no"). For
more details about these and other configuration options, consult the
Hibernate reference manual.
TIP:
You may be wondering why the taskdef for the
schema update tool is inside our schema target,
rather than at the top of the build file, next to the one for
hbm2java. Well, I wanted it up there too, but I
ran into a snag that's worth explaining. I got
strange error messages the first time I tried to build the schema
target, complaining there was no
hibernate.properties on the class path and our
compiled Track class couldn't be
found. When I ran it again, it worked. Some detective work using
ant-verbose revealed
that if the classes directory
didn't exist when the taskdef was
encountered, Ant helpfully removed it from the class path. Since a
taskdef can't have its own
dependencies, the solution is to move it into the
schema target, giving it the benefit of that
target's dependencies, ensuring the
classes directory exists by the time the
taskdef is processed.
With these additions, we're ready to generate the
schema for our
TRACK table.
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|