To clarify, yes, this is all completely optional functionality.
Cheers,
Clinton
On 5/23/05, Fabrizio Gianneschi <[EMAIL PROTECTED]> wrote:
I think this is a very **cool** new feature, but I would vote for it only if it's use is optional, or completely automated.One of the reasons I like iBATIS is its simplicity; this solution complicates a bit the overall design, and it's a bit more hard to understand for a newbie. As Aitor already notes, there is the issue of the proliferation of interfaces. In addition, using the Object class as a parameter (and return type) makes the coding extremely fast, when you want to do so.What about generating the interfaces from the sql map files? At least, generating part of them, when the I/O types are well known.F
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...
Da: Clinton Begin [mailto:[EMAIL PROTECTED]]
Inviato: domenica 22 maggio 2005 18.35
A: ibatis-user-java@incubator.apache.org
Oggetto: [New Feature] SQL Map Interface Binding -for your review
---------------------------------
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:
How select statements are run is determined by the method signature, 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 stored procedures are run is determined by the method name, 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
- 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.