java hosting


Jenny the db code generator

This program reads a database and generates java source which provides strongly typed access to the database.

Why was Jenny created?

In my opinion, there are two major problems with JDBC:
    1) There are slight differences in SQL, drivers, app servers, database access, etc. that make it clear that a facade is needed. The facade would provide access to the database in plain java (not SQL). All of the implementation specific code is concentrated in one small area instead of spread out all over your application. The DBFacade class fixes this problem.

    2) For any database change, it takes a great deal of discipline to find all of the table names and column names used throughout your code that now function differently. Even the slightest lack of discipline results in a bug that might not be discovered until run time. Strong typing eliminates this problem. This program (Jenny) provides the strong type checking.

For each table and view in a given database, Jenny will create a java source class file. Each of these classes will provide a collection of general purpose methods for working with the table/view. They will also provide a list of all the column names, the table/view name and a nested class called Row that can be used to manipulate a single row in the table.

Many tables have a primary key that is a non-nullable integer called "tablenameID" or sometimes "ID". If Jenny finds this, she will add extra methods to the generated source for working with the primary key.

Some of my goals:
  • Simplicity: Accessing the database needs to be as simple as possible. I decided that this meant using static methods for the table level methods. All connections, statements, result sets and all other objects that need closing are generally managed for you so you don't have to worry about it - thus eliminating about 70% of the code required for typical JDBC access.

  • Unit Testing: I want to auto-generate a Mock class for every table class to facilitate unit testing. This means that I need to have something I can override. Since static methods cannot be overridden, I need a nested class that the static methods use that I can override for my mock classes. This also means that I need to hide all of the Row constructors so a mock object can be returned. This allows unit testing without having to provide SQL in the unit tests or to have a database server running during the testing.

  • Flexibility:I want to be able to allow alternate connections, or to make several database calls with one connection, so every database access method allows me to pass in a connection object. I also want to allow multiple ways to get to the same database; support multiple databases on one database server; support the use of multiple servers being used from one application.

  • Functional Testing: I want to allow for functional testing (sometimes called integration testing - kinda like unit testing, but with more than one class and sometimes the actual database) so I allow all classes to replace the connection source at the facade level.

  • Clear Division of Labor: I want to work with the idea that the database is managed by a DBA and business logic is managed by software engineers. So fancy database stuff is done by the DBA in the database (i.e. joins are handled within views by the DBA). In most big software shops, the software engineer will be accessing data in an existing database that is managed by a DBA that has far more experience with the database than the engineer. Anything that cannot be done through the facade probably needs to be done on the database side.

  • Complexity Reduction: I want to avoid having complex relationships defined in an XML document or embedded in the code. Good engineering is making complicated business logic look SIMPLE! My experiences with object databases, object to relational mapping, CMP and similar tools is that they promise simplicity, but when you get right down to it, it becomes horribly complicated!

  • Self Discipline Not Required! Many solutions similar to Jenny require human engineers to have the discipline to make sure that any changes in one place are reflected in other places. If your table name in your database does not match the table name in your java code, you have a problem! With this solution, you don't need that discipline. Therefore you have more reliable code.

What does Jenny do?

Each generated class will provide some basic methods such as these:
      Row getRow()
      Row getRow( String column , String searchText )
      DBResults search( String column , String searchText , String[] dataColumns )
      Row[] getRows( String column , String searchText )
      Row[] getAllRows()
      DBResults search( String[] dataColumns )
      void update( String column , String searchText , Map data )
      void delete( String column , String searchText )
      void insert( Map data )
    
If an ID field is found, some methods like these will also be added:
      Row getRow( int id )
      void delete( int id )
    
Every class will have a nested class called Row that can provide strong type checking for every field (column) as well as methods like:
       void update()
       void delete()
       void insert()
    
The strong type checking for Row is provided by getters and setters. Suppose you have a table called Employee. Jenny will generate a class called EmployeeTable that will contain a Row class that might have the following methods:
       int getEmployeeID()
       void setEmployeeID( int employeeID )
       String getLastName()
       void setLastName( String lastName )
    
Here's a sample of a business logic method that uses a Jenny generated class:
       // pass in an employee ID and get back the number of
       // tax exemptions that the employee claims
       private int getEmployeeExemptions( int employeeID )
       {
           return EmployeeTable.getRow( employeeID ).getExemptions();
       }
    

This same code using plain JDBC could be 10 to 40 lines long depending on how it would be implemented. You would need to get a connection, create a statement, build your sql string, exceute your statement, wade through the result set, and each of these things need try/catch/finally blocks! Don't forget to close your connection, statement and result set!

How do I use Jenny?

Download jenny.zip

Unzip this - it contains two jar files, jenny-dev.jar, and jenny-prod.jar. Make sure your classpath includes both these files.

From the command line, type:

        java com.javaranch.jenny.dev.Jenny db.properties 

where db.properties is a properties file that describes how Jenny should find your database. This is described further in the tutorial.

Tutorial on Using Jenny    |    Jenny FAQ   



Page maintained by Marilyn de Queiroz