>>>1- Does the class (interface) passed to the getMapper() method need to
>>>extend a special iBatis interface (as with the Dao interface)?
>
>
> Nope.
Good.
Completely off topic: any plans to eliminate the Dao interface
reuirement on iBatis DAOs?
>>>2- Can this handle extended interfaces? For example, interface B extends
>>>interface A. Are both interfaces "mapped" like you described?
>
>
> The way it's implemented right now, the answer is: yes. I was
thinking of
> binding it more tightly, but this is definitely an option.
I'm not sure if a "tight" binding would be beneficial. Considering
extended interfaces, it would seem non-intuitive to have the extended
interface partialy mapped to statements.
>>>3- What about namespaces? Can they or are they being used?
>
>
> That's going to be the challenge with the current implementation, and
may
> require the tight binding that I mentioned in the previous question.
How would a tight binding look like? How would the namespace be derived?
>>>4- Can we still use startBatch/executeBatch?
>
> But I don't see any reason why we couldn't just allow you to define
methods
> with the same signature to any interface that you can then call. Of
course,
> you could always just use SqlMapClient for this, but if you truly
wanted to
> isolate yourself, then you could define your own TransactionManager
> interface that has all of these methods declared.
Does the TransactionManager expose the startBatch and executeBatch
methods? I didn't think it did.
I guess keeping the SQLMapClient around isn't such a bad thing... Unless
someone would like to get rid of their DAOs completely...
>>>5- Can you explain how insert() and insertXXXX() differs (besides the
>>>executed statement's name)?
>
>
> No, because I don't know what you mean. :-) The method name is only
> significant when you're calling a stored procedure (because procs can do
> anything...insert, update, delete, query or a combination).
I have to admit, my question was not very clear! I realize now that it
was due to a misunderstanding of the javadoc you posted...
If my interface looks like this:
public List searchFoos(Foo value);
public Foo insertFoo(Foo value);
public Foo saveFoo(Foo value);
public Foo createASpecialFoo(Foo value);
And my SqlMap looks like this:
searchFoos=<select>
insertFoo=<insert>
saveFoo=<update>
createASpecialFoo=<procedure>
iBatis will execute these methods:
searchFoos=queryForList()
insertFoo=insert()
saveFoo=update()
createASpecialFoo=insert()
In other words, iBatis looks at both the method's signature AND the
SqlMap's tag to determine what SqlMapClient method to call.
Is that how the mapping occurs?
Clinton Begin wrote:
Great questions!
1- Does the class (interface) passed to the getMapper() method need to
extend a special iBatis interface (as with the Dao interface)?
Nope.
2- Can this handle extended interfaces? For example, interface B extends
interface A. Are both interfaces "mapped" like you described?
The way it's implemented right now, the answer is: yes. I was thinking of
binding it more tightly, but this is definitely an option.
3- What about namespaces? Can they or are they being used?
That's going to be the challenge with the current implementation, and may
require the tight binding that I mentioned in the previous question.
4- Can we still use startBatch/executeBatch?
I haven't decided how best to deal with all of the non-execute methods like
startTransaction(), commitTransaction(), endTransaction(), startBatch(),
endBatch() etc.
But I don't see any reason why we couldn't just allow you to define methods
with the same signature to any interface that you can then call. Of course,
you could always just use SqlMapClient for this, but if you truly wanted to
isolate yourself, then you could define your own TransactionManager
interface that has all of these methods declared.
5- Can you explain how insert() and insertXXXX() differs (besides the
executed statement's name)?
No, because I don't know what you mean. :-) The method name is only
significant when you're calling a stored procedure (because procs can do
anything...insert, update, delete, query or a combination).
Cheers,
Clinton
On 5/24/05, Philippe Laflamme <[EMAIL PROTECTED]> wrote:
Great idea. I think this will help make SQLMaps even more usable. I do
have a few questions:
1- Does the class (interface) passed to the getMapper() method need to
extend a special iBatis interface (as with the Dao interface)?
2- Can this handle extended interfaces? For example, interface B extends
interface A. Are both interfaces "mapped" like you described? This can
be very interesting for common persistence methods for example. One
would simply need to extend a CustomPersistenceMapper interface instead
of redefining every method.
3- What about namespaces? Can they or are they being used?
4- Can we still use startBatch/executeBatch?
5- Can you explain how insert() and insertXXXX() differs (besides the
executed statement's name)?
Cheers,
Philippe
Clinton Begin wrote:
Although quite simple, there are some tradeoffs with the typical
SqlMapClient methods like:
Document doc = (Document) sqlMap.queryForList("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
<
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.