ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Clinton Begin <clinton.be...@gmail.com>
Subject [New Feature] SQL Map Interface Binding -for your review
Date Sun, 22 May 2005 16:35:13 GMT
The dev list has already seen this. I just want to make sure anyone who 
doesn't subscribe to the dev list gets a chance to provide some feedback...

---------------------------------

Although quite simple, there are some tradeoffs with the typical 
SqlMapClient methods like:

Document doc = (Document) sqlMap.queryForObject("getDocument", new Integer 
(1));

First of all, it is possible that you could spell getDocuments incorrectly. 
Second, the parameter is not strongly typed. So at code time, you could 
easily pass in an inappropriate object. Also, the return type is cast, so 
it's even possible for the statement to return an invalid object (i.e. 
result map returns a Dog instead of a Document). Finally, if you're using 
anything less than J2SE 5.0, you have to wrap primitives with their wrapper 
types. DISCLAIMER: Yes, you should have unit tests to verify this anyway! 
;-)

But what else can we do about this? Well, what if we mapped the 
"getDocument" mapped statement to an interface. For example, this one:

public interface DocumentMapper {
Document getDocument (int id);
}

So basically we have a method that mirrors the queryForList signature, 
except the method name matches the mapped statement name, instead of passing 
it as a parameter. Furthermore, as soon as the SqlMapClient is built, this 
method is validated against the mapped statement to ensure that the proper 
parameter and result types are defined. Finally, using the sucker is a whole 
lot easier:

Document doc = documentMapper.getDocument(1);

No more casting. No more wrapping. No more ambiguous types. No more 
misspelling.

Sounds good, how do I create a Mapper? Well, we already have. The interface 
above is all we need. A simple call to the following SqlMapClient method, 
creates the instance that can be used:

DocumentMapper documentMapper = (DocumentMapper) sqlMap.getMapper(
DocumentMapper.class);

The instance is thread safe, so you can keep this sucker around as a field 
on your DAO or service class.

Best of all, unit testing becomes a snap, as you can mock a DocumentMapper a 
heck of a lot easier than you could the SqlMapClient interface.

Alrighty! So when will it be implemented? It already is. It's in SVN right 
now for your perusal, here's the unit test:

http://svn.apache.org/repos/asf/incubator/ibatis/trunk/java/mapper/mapper2/test/com/ibatis/sqlmap/BindingTest.java


The JavaDoc is below.

The current implementation isn't optimized, nor does it perform full 
validation. In it's current state, it's mostly intended to be easily removed 
if you don't like the idea.

So let us know what you think!

Cheers,
Clinton



----------------------------------------

 getMapper 

public java.lang.Object *getMapper*(java.lang.Class iface)

 Returns a generated implementation of a cusom mapper class as specified by 
the method parameter. The generated implementation will run mapped 
statements by matching the method name to the statement name. The mapped 
statement elements determine how the statement is run as per the following: 
   
   - <insert> -- insert() 
   - <update> -- update() 
   - <delete> -- delete() 
   - <select> -- queryForObject, queryForList or queryForMap, as 
   determined by signature (see below) 
   - <procedure> -- determined by method name (see below) 

How select statements are run is determined by the method signature, as per 
the following: 
   
   - Object methodName (Object param) -- queryForObject 
   - List methodName (Object param [, int skip, int max | , int 
   pageSize]) -- queryForList 
   - Map methodName (Object param, String keyProp [,valueProp]) -- 
   queryForMap 

How stored procedures are run is determined by the method name, as per the 
following: 
   
   - insertXxxxx -- insert() 
   - createXxxxx -- insert() 
   - updateXxxxx -- update() 
   - saveXxxxx -- update() 
   - deleteXxxxx -- delete() 
   - removeXxxxx -- delete() 
   - selectXxxxx -- queryForXxxxxx() determined by method signature as 
   above 
   - queryXxxxx -- queryForXxxxxx() determined by method signature as 
   above 
   - fetchXxxxx -- queryForXxxxxx() determined by method signature as 
   above 
   - getXxxxx -- queryForXxxxxx() determined by method signature as above 
   

 
*Parameters:*iface - The interface that contains methods representing the 
mapped statements contained. *Returns:*An instance of iface that can be used 
to call mapped statements directly in a typesafe manner.

Mime
View raw message