ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Lightweight R/O Mapping
Pages: 1, 2, 3, 4, 5, 6, 7

Accordingly, the getter methods are equipped with @ParameterAssociation annotations to connect the properties of the JavaBean to the parameters in an update, delete, or insert call. This annotation applies to the getter methods only, because Amber uses the getter methods to retrieve the values to fill in the parameters. Because of JDBC, it is necessary to index the parameters. This can be redundant, depending on the underlying database and whether stored procedures are used or not, but for completeness and to follow the JDBC API they need to be provided. The annotation property isAutoIdentity will be discussed when we get to writing data into the database.

It is necessary to provide a no-argument constructor in order for objects of this class to be constructed automatically (via reflection). In the class above, there is a no-argument constructor available, since we did not provide any other, but we need to be careful when we add additional constructors to the class, because then we would need to provide one explicitly for Amber.

The result is a JavaBean that shows exactly from where in the database its content is taken and to where it is written. There is no need for an external specification file. Note that we could actually set up any class in this fashion, not just JavaBeans.

You may wonder: why use annotations? Why not use an implicit association via the property names, since we are dealing with JavaBeans anyway? This is done in order to retain one degree of freedom in our design. In other words, we Java guys do not want to be dependent on how the ER model designers name their table columns. If you are used to working with tables, you might not agree with this, but when you are using stored procedures, you have to deal with joined tables and views that sometimes have to use distinguished names.

Amber's Connectors and JDBC

Before we go ahead with reading and writing, we need to establish a connection to the database. Amber uses a Connector to access the database. In short, this is the combination of a database driver and a corresponding connection URL. A ConnectorFactory is used to manage the available connections in an application. To initialize a simple connection to an SQL server using a native type-4 driver, one would use the following code. We assume the server name to be localhost, the database name to be jedi, the login to be use, and finally, the password to be theforce. For brevity, I will omit all exception-handling in the code below.

String driverClassName = 
String url = 
   "jdbc:microsoft:sqlserver://" + 
   "localhost;databasename=jedi;" + 

Amber's Connector is associated with a String, alias under which it remains accessible from the ConnectorFactory. Here, we're going to use the alias starwars.

   "starwars", driverClassName, url 
Since a Connector is a lightweight wrapper around a JDBC connection, we can, in general, do anything with it that we might originally be doing with such a connection.


Wrapped around such a Connector is a BeanReader object, which takes a Connector and a Class that tells the reader what type of bean should be read from the database. The problem of reading a list of Jedi objects is then reduced to the following lines.

Connector connector = 
   ConnectorFactory.createConnector( "starwars" );
BeanReader reader = 
   new BeanReader( Jedi.class, connector );
Collection<Jedi> jediList = 
      "select * from jedi" 

This code employs a new Java language feature called generics that is available as of J2SE 5.0. In the line that declares the Collection, the syntax says that the Collection called jediList consists uniformly of objects that are of the type Jedi. The compiler will issue a warning here, since the reader only knows at runtime what kind of class it is going to create. Because of type erasure in the generics implementation of J2SE 5.0, it is not possible to safely cast the result. And, sadly, it is also not possible to write the BeanReader class as BeanReader<Jedi> for the same reason. In short, using Java reflection and generics don't mix.

Pages: 1, 2, 3, 4, 5, 6, 7

Next Pagearrow