You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user-java@ibatis.apache.org by Carlos Pita <ca...@gmail.com> on 2009/08/30 10:37:29 UTC

Unconstrained signature interface mappers for ibatis 3

Hi all,

now that ibatis 3 supports type-safe mapper interfaces that make a
nice interface to the repository/dao tier, it would be desirable to
allow for multiple parameters to be passed, so that application
designers would not be constrained while designing their layer
interfaces. For example, I would prefer:

List<User> findCommonFriends(User user1, User user2)

instead of

List<User> findCommonFriends(Map<String,User> users)

or

List<User> findCommonFriends(UserPair users)

It just requires a trivial modification in MapperMethod and a simple
mechanism to access positional parameters to get it working. For
example, MapperMethod could create a Map and put the first argument
under the key "first", the second one under "second", etc. That is,
positional access "by name". Of course, in case the number of
arguments were only one, the usual mechanism would follow.

What do you think? Personally I belive that this very simple change
will add some degrees of freedom to interface designers.

Best regards
--
Carlos

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


Re: Unconstrained signature interface mappers for ibatis 3

Posted by ca...@gmail.com.
Hi Clinton,

thanks for your detailed answer.

I agree with you, although leaving aside the SQLUtils varargs proposal,
I tend to priorize the unconstrained java mapper interface issue over
the parameter naming issue, because

  (i) the interface defines a contract for the rest of the application
  and maps or a myriad of dtos don't feel like a good interface design
  at the application level (previously with ibatis 2 I simply implemented
  dao interfaces at my pleasure on top of SQLUtils, now I can avoid the
  boilerplate but at the price of modifying the signatures, this is
  intrusive from the part of ibatis).

  (ii) because most methods will in fact take just one argument, while a
  few will take two, or maybe three. The name-positional mapping is ugly,
  although there is no huge unmaintainable number of ? placeholders here but
  just a couple of ordinal arguments, so most of the references will still
  be done by name to the properties of the args and not to the args themselves:
    arg1.name,arg2.id,arg1.age,arg2.password,... vs ?,?,?,?,...
  That *makes* a difference.

With respect to  obtaining the parameters names at runtime, until java 8 
not even 7 afaik) the only way to go is to compile with debug info an access
the bytecode with asm (not sure if javassist can do this trick also).
It's not that hard, but you have to generate debug info for the class
and introduce a dependency on asm. I could implement this, if you're
interested.

Best regards
--
Carlos


 

On Sun, Aug 30, 2009 at 08:44:45AM -0600, Clinton Begin wrote:
> I love the idea, and I think we even have it on the wiki...
> 
> However, I attempted the implementation and could not land on a design that
> was nice.  The biggest problem is that Java lacks introspection on method
> parameter names.  What I would really love is:
> 
> @Select("select * from employee where first_name = #{firstName}" and
> last_name = #{lastName})
> Employee findEmployeeLike(String firstName, String lastName);
> 
> That would truly be awesome (of course complex types would work too).   This
> is perfectly possible in C#, where I can get the names of the parameters.
> However in Java, there is no such means.  So that leaves us with pretty much
> two options:
> 
> 1) Ordinal -- I don't like this, because it's akin to the ordinal ? params
> in standard JDBC prepared statements. By supporting multiple params, the
> value of the feature should increase with more params, but here, adding more
> params makes the SQL less readable and harder to change later (i.e.
> refactoring to add a new param in the middle of the method signature).
> Doesn't bode well for this feature.
> 
> @Select("select * from employee where first_name = #{1} and last_name =
> #{2})
> Employee findEmployeeLike(String firstName, String lastName);
> 
> 2) Annotations -- We could add annotations to the parameters... this just
> ended up looking silly.
> 
> @Select("select * from employee where first_name = #{firstName} and
> last_name = #{lastName})
> Employee findEmployeeLike(@Param("firstName") String firstName,
> @Param("lastName") String lastName);
> 
> An alternative was to use a single annotation...
> 
> @Select("select * from employee where first_name = #{firstName} and
> last_name = #{lastName})
> @Params("firstName","lastName")
> Employee findEmployeeLike(String firstName, String lastName);
> 
> But that kind of repetition makes me sad.  :-(
> 
> At the end of the day I gave up, because all of these were so repetitive,
> hard to maintain (due to the alignment and ordinal positioning) and don't
> read well.
> 
> I really wish Java made this easier.  One thought I had to submit to the JCP
> was to add introspection on parameter names by having the compiler
> automatically create annotations for the parameter names.
> 
> For example, given the method:
> 
> Employee findEmployeeLike(String firstName, String lastName);
> 
> The compiler would automatically create @MethodParameterName annotation (or
> something similar) for each parameter.  Then I could either use the regular
> annotation API to fetch them, or a cleaner API like String[]
> method.getParameterNames().
> 
> But I decided by the time that made it into the framework we'd be at JDK 9
> and who knows where iBATIS would be.  :-)
> 
> I'm open to more ideas... but the goals have to be:
> 
> 1) No repetition
> 2) No ordinal positioning
> 3) Descriptive SQL
> 4) Easy to maintain
> 
> Thoughts?
> 
> Cheers,
> Clinton
> 
> On Sun, Aug 30, 2009 at 3:30 AM, <ca...@gmail.com> wrote:
> 
> > > It just requires a trivial modification in MapperMethod and a simple
> > > mechanism to access positional parameters to get it working. For
> > > example, MapperMethod could create a Map and put the first argument
> > > under the key "first", the second one under "second", etc. That is,
> > > positional access "by name". Of course, in case the number of
> > > arguments were only one, the usual mechanism would follow.
> >
> >
> > Another possibility is to take advantage of java 5 varargs feature and
> > allow SqlSession methods to accept multiple parameters with Object...:
> >
> > Object selectOne(String statement, Object... parameters);
> >
> > (Of course, the currently overloaded selectOne:
> >
> >     Object selectOne(String statement);
> >     Object selectOne(String statement, Object parameter);
> >
> > would be merged into the single method above).
> >
> > As before, when length > 1 the varargs will be automatically stored into
> > a Map under "positional" keys like "arg1", "arg2", etc (I'm not sure if
> > the shorter "1", "2", etc are compatible with javabeans as in "bean.1",
> > "bean.2").
> >
> > This way MapperMethod will just forward its Object[] args to the SqlSession
> > method selectOne, selectList, etc.
> >
> > Notice that any change that I have proposed is absolutely backwards
> > compatible:
> >
> > 1) Object... still can take single arguments.
> > 2) If just one argument is given the { "arg1": arg1, "arg2": arg2, ...}
> > map will not be created at all.
> > 3) Sql expecting one argument won't need to be modified.
> >
> > However, SqlSession won't compile with java 1.4 or older due to the
> > introduction of varargs. I don't know if this is a concern for ibatis 3.
> > In that case, the proposal of my previous post doesn't suffer the same
> > inconvenience, althought it is more limited.
> >
> > I would like to hear your opinion about it.
> >
> > Best regards
> > --
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> > For additional commands, e-mail: user-java-help@ibatis.apache.org
> >
> >

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


Re: Unconstrained signature interface mappers for ibatis 3

Posted by Clinton Begin <cl...@gmail.com>.
I don't think it's an opinion limited to myself and iBATIS... Gavin King and
Christian Bauer of Hibernate fame have also spoken out against them in the
past.  I think a lot of people are coming to the conclusion that MVC +
Service + Persistence is enough layers. :-)

I couldn't find Gavin's original post (from many years ago) on the subject,
but I believe this thread references it and might offer some shared
insight:  http://forum.springsource.org/showthread.php?t=64147

That said, you did point out at least one case that is still certainly
relevant... if I were to build an app with JDBC today, I'd definitely put
that code in a nice little package.  However, I wouldn't call it a DAO
anymore, and would probably call it a Mapper.

Here's how I distinguish the two:

Mappers:  To me a Mapper says "Take this object and store it somewhere,
mapping the fields (i.e. state) of the object to some other structure, be it
a relational model, an XML file, a DOD, Amazon S3... whatever, and stop
there."

DAOs:  DAOs are more abstract that Mappers, and usually are broader in scope
as well.  They may take a complex object, save all of its parts and even
call out to other DAOs (although I always made a rule to avoid that).  DAO
frameworks always had a repository, factory or DI container that managed
them.  Furthermore, the DAO framework also often abstracted the transaction
control system as well (whereas a Mapper would be unaware of the
transaction).

So I see a DAO framework as a broader scoped an abstraction layer in the
software architecture, with interfaces, factories and transactions in all
their glory.  I see Mappers as more of a fine grained implementation layer
that is far simpler and narrower in scope.

Clinton

On Sun, Aug 30, 2009 at 9:02 PM, Carlos Pita <ca...@gmail.com>wrote:

> > DAOs have become the boilerplate in my opinion.
> >
> > ActionBean(Stripes) > Service(POJO) > Mapper(iBATIS)
>
> Interesting. I dare to say that your point of view is clearly influenced by
> your
> use of ibatis, isn't it? I can hardly imagine programming a services tier
> with
> verbose jdbc or obscure hql embedded. ibatis gets rid of most of the
> persistence concerns encapsulating them inside the mapper (I mean, the
> xml one). So it's logical to (learn to) stop worrying and love the mapper.
> And to conclude that DAOs are boilerplate.
>
> > I don't think you'd have to patch the code... You can implement your own
> > SqlSessionFactory and SqlSession instances, decorated with your
>
> On second thought a completely external proxy that has access to the
> configuration and sqlSession is more than enough for my needs.
> The api exposed by ibatis will suffice, there's no need for
> extension points. MapperMethod will be a valuable guideline for the
> implementation. I really don't care about session.getMapper() returning
> different proxies according to the enhance setting state or
> things like that. I'm grown enough to instantiate my own proxies :).
>
> Anyway I will let the idea of discarding daos mature for a while
> before putting hands to work.
>
> Thanks again.
>
> Best regards
> --
> Carlos
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

Re: Unconstrained signature interface mappers for ibatis 3

Posted by Carlos Pita <ca...@gmail.com>.
> DAOs have become the boilerplate in my opinion.
>
> ActionBean(Stripes) > Service(POJO) > Mapper(iBATIS)

Interesting. I dare to say that your point of view is clearly influenced by your
use of ibatis, isn't it? I can hardly imagine programming a services tier with
verbose jdbc or obscure hql embedded. ibatis gets rid of most of the
persistence concerns encapsulating them inside the mapper (I mean, the
xml one). So it's logical to (learn to) stop worrying and love the mapper.
And to conclude that DAOs are boilerplate.

> I don't think you'd have to patch the code... You can implement your own
> SqlSessionFactory and SqlSession instances, decorated with your

On second thought a completely external proxy that has access to the
configuration and sqlSession is more than enough for my needs.
The api exposed by ibatis will suffice, there's no need for
extension points. MapperMethod will be a valuable guideline for the
implementation. I really don't care about session.getMapper() returning
different proxies according to the enhance setting state or
things like that. I'm grown enough to instantiate my own proxies :).

Anyway I will let the idea of discarding daos mature for a while
before putting hands to work.

Thanks again.

Best regards
--
Carlos

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


Re: Unconstrained signature interface mappers for ibatis 3

Posted by Clinton Begin <cl...@gmail.com>.
>From a matter of personal opinion, I no longer use DAOs... I wrote them for
years, and to no benefit.  I've never swapped out a DAO implementation or
replaced the persistence framework, or at least not to the degree that the
mappers wouldn't allow for the same benefit.

DAOs have become the boilerplate in my opinion.  It think it's more
important to have a good services layer - with or without interfaces - that
defines your business logic.  So my current favourite layer structure would
be something like:

ActionBean(Stripes) > Service(POJO) > Mapper(iBATIS)

With all dependencies injected/managed by Guice.

>> so I would need to patch the code.

I don't think you'd have to patch the code... You can implement your own
SqlSessionFactory and SqlSession instances, decorated with your
implementations.  That's done by design for this reason.  You can also wrap
or extend the Configuration class.

Don't try to augment the existing mapper implementation, just replace it
entirely with yours.

Cheers,
Clinton


On Sun, Aug 30, 2009 at 8:06 PM, <ca...@gmail.com> wrote:

> > These mapper classes aren't meant to be DAOs... they're meant to be
> mappers.
> > If you like a DAO pattern, then you can still use it, with or without
> mapper
>
> Ok, I was thinking in dao terms and my perception was "mappers are
> almost daos... only if I had one more degree of freedom to define my
> interfaces... ". In fact, I'm porting an entire application persistence
> tier to ibatis, and the correspondence between mappers and daos is
> almost complete except for the minor differences between signatures. Now I
> will need some refactoring at the use-point (application/services tier)
> or, alternatively, to implement thin adaptors daos that delegate to
> mappers,
> preserving the original interfaces. That's a lot of boilerplate, or another
> level of bytecode manipulation wizardry. That was my motivation and
> rationale,
> but it's fine if it's out of the intended scope for mappers.
>
> > However, it's perfectly possible to build such a thing external to
> iBATIS...
> > the mapper framework in iBATIS is very small and simple.  If you're
> > interested in that approach, perhaps you could put something together for
> > yourself, and then post the implementation here.  The community can look
> at
>
> Sure. One simple way would be to implement a cglib enhanced variant
> of the current MapperProxy, but there is no extension point from where
> to instantiate different proxy implementations, so I would need to patch
> the code. Anyway, I guess you're suggesting something on top of mappers
> and not in place of mappers, according to your comments above. I'll
> think about it.
>
> Thank you!
>
> Best regards
> --
> Carlos
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

Re: Unconstrained signature interface mappers for ibatis 3

Posted by ca...@gmail.com.
> These mapper classes aren't meant to be DAOs... they're meant to be mappers.
> If you like a DAO pattern, then you can still use it, with or without mapper

Ok, I was thinking in dao terms and my perception was "mappers are
almost daos... only if I had one more degree of freedom to define my
interfaces... ". In fact, I'm porting an entire application persistence
tier to ibatis, and the correspondence between mappers and daos is
almost complete except for the minor differences between signatures. Now I
will need some refactoring at the use-point (application/services tier)
or, alternatively, to implement thin adaptors daos that delegate to mappers,
preserving the original interfaces. That's a lot of boilerplate, or another
level of bytecode manipulation wizardry. That was my motivation and rationale,
but it's fine if it's out of the intended scope for mappers.

> However, it's perfectly possible to build such a thing external to iBATIS...
> the mapper framework in iBATIS is very small and simple.  If you're
> interested in that approach, perhaps you could put something together for
> yourself, and then post the implementation here.  The community can look at

Sure. One simple way would be to implement a cglib enhanced variant
of the current MapperProxy, but there is no extension point from where
to instantiate different proxy implementations, so I would need to patch
the code. Anyway, I guess you're suggesting something on top of mappers
and not in place of mappers, according to your comments above. I'll
think about it.

Thank you!

Best regards
--
Carlos


---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


Re: Unconstrained signature interface mappers for ibatis 3

Posted by Clinton Begin <cl...@gmail.com>.
These mapper classes aren't meant to be DAOs... they're meant to be mappers.
If you like a DAO pattern, then you can still use it, with or without mapper
classes.  The mapper class's only goal is to eliminate the string literals
and casting that comes with the "old way".

We deprecated the DAO framework and don't intend to replace it, as there are
better alternatives like Guice and Spring.

iBATIS does optionally use CGLIB for certain things (lazy loading on
concrete types), but it's not a requirement. If it's on the classpath,
iBATIS will use it, if it's not, iBATIS won't.  For the case of the mappers,
it's simply not needed.

I see what you're saying about the concrete methods, but I don't think I'd
take iBATIS in that direction.

However, it's perfectly possible to build such a thing external to iBATIS...
the mapper framework in iBATIS is very small and simple.  If you're
interested in that approach, perhaps you could put something together for
yourself, and then post the implementation here.  The community can look at
it. It might become a popular extension, or maybe a core addition.  In the
worst case scenario, you'd get to use it. :-)

Clinton

On Sun, Aug 30, 2009 at 2:16 PM, <ca...@gmail.com> wrote:

> > thoughts on the following two options:
> >
> > @Select("select * from employee where first_name = #{firstName} and
> > last_name = #{lastName})
> > List<Employee> findEmployeesLike(@Param("firstName") String firstName,
> > @Param("lastName") String lastName, @Offset int offset, @Limit, int
> limit);
> >
> > @Select("select * from employee where first_name = #{firstName} and
> > last_name = #{lastName})
> > List<Employee> findEmployeesLike(@Param("firstName") String firstName,
> > @Param("lastName") String lastName, Constraint offsetLimit);
> >
> Prima facie I would prefer the first option, because the current
> implementation,
> (ie. with no parameter annotations) could be considered the default case.
> It
> makes a very good default indeed. Most of the methods that return or update
> one entity will match the one parameter signature, and those queries that
> return collections will match the one or three parameters signature,
> the last two ones for the offset/limit constraint. Following Pareto,
> no annotations or special classes should be required for these common
> cases.
> Also, I don't like the idea of introducing an IBatis specific class at the
> dao
> layer (which is supposed to isolate the application from the specific
> persistence technology employed, at least to a reasonable degree),
> but then you're right that we already have ResultHandler anyway.
>
> Besides the annotations question, I think the above is pointing out a
> deeper issue. As far as IBatis is being all that smart creating the
> entire mapper on the fly from an interface, it leaves no fine tunning
> options to the application designer/programmer, except by means of
> an in-place metadata mechanism that soon becomes awkward, limited and
> verbose (we are pushing it to the limit here, in fact). That was my point
> before
> about being relieved of the old boilerplate, but then: maybe excessively
> relieved.
>
> Why is it that you're using java dynamic proxies here instead of cglib
> or javassist proxies? To avoid external dependencies at all costs?
> Would you provide a cglib variant if enhance is enabled? This way one
> could think (just brainstorming) of a combination of automagically
> generated methods and other hand written ones that allow for complete
> customisation of the 20% cases that don't follow the rule, by delegating
> to internal protected autogenerated methods or just by directly calling
> the SqlSession as in the old times. It would be a "best of both worlds"
> approach. A combination of abstract and concrete methods will do the trick,
> interfaces being the "degenerate" case for which all methods are abstract.
> This could even solve the multiple parameter naming issue: you want it,
> write it, IBatis won't do it for you but won't forbid you to do it either.
> Also, if you don't care about exposing IBatis specific interfaces to the
> rest of the application, go ahead with ResultHandler, for example. But
> if you DO care, write your own MyAppResultHandler and your dao method
> that accepts it (again, as a "full-fledged" implementation on top of
> SqlSession or as an adaptor stub to an autogenerated method).
>
> Best regards
> --
> Carlos
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

Re: Unconstrained signature interface mappers for ibatis 3

Posted by ca...@gmail.com.
> thoughts on the following two options:
> 
> @Select("select * from employee where first_name = #{firstName} and
> last_name = #{lastName})
> List<Employee> findEmployeesLike(@Param("firstName") String firstName,
> @Param("lastName") String lastName, @Offset int offset, @Limit, int limit);
> 
> @Select("select * from employee where first_name = #{firstName} and
> last_name = #{lastName})
> List<Employee> findEmployeesLike(@Param("firstName") String firstName,
> @Param("lastName") String lastName, Constraint offsetLimit);
> 
Prima facie I would prefer the first option, because the current implementation,
(ie. with no parameter annotations) could be considered the default case. It
makes a very good default indeed. Most of the methods that return or update
one entity will match the one parameter signature, and those queries that
return collections will match the one or three parameters signature,
the last two ones for the offset/limit constraint. Following Pareto,
no annotations or special classes should be required for these common cases.
Also, I don't like the idea of introducing an IBatis specific class at the dao
layer (which is supposed to isolate the application from the specific
persistence technology employed, at least to a reasonable degree),
but then you're right that we already have ResultHandler anyway.

Besides the annotations question, I think the above is pointing out a
deeper issue. As far as IBatis is being all that smart creating the
entire mapper on the fly from an interface, it leaves no fine tunning
options to the application designer/programmer, except by means of
an in-place metadata mechanism that soon becomes awkward, limited and
verbose (we are pushing it to the limit here, in fact). That was my point before
about being relieved of the old boilerplate, but then: maybe excessively
relieved.

Why is it that you're using java dynamic proxies here instead of cglib
or javassist proxies? To avoid external dependencies at all costs?
Would you provide a cglib variant if enhance is enabled? This way one
could think (just brainstorming) of a combination of automagically
generated methods and other hand written ones that allow for complete
customisation of the 20% cases that don't follow the rule, by delegating
to internal protected autogenerated methods or just by directly calling
the SqlSession as in the old times. It would be a "best of both worlds"
approach. A combination of abstract and concrete methods will do the trick,
interfaces being the "degenerate" case for which all methods are abstract.
This could even solve the multiple parameter naming issue: you want it,
write it, IBatis won't do it for you but won't forbid you to do it either.
Also, if you don't care about exposing IBatis specific interfaces to the
rest of the application, go ahead with ResultHandler, for example. But
if you DO care, write your own MyAppResultHandler and your dao method
that accepts it (again, as a "full-fledged" implementation on top of
SqlSession or as an adaptor stub to an autogenerated method).

Best regards
--
Carlos

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


Re: Unconstrained signature interface mappers for ibatis 3

Posted by Clinton Begin <cl...@gmail.com>.
I'll play with it and see how it looks.

I'm wondering if this new API should filter down to the SqlSession API as
well.. that is, introduce the RowLimit class to replace the offset and limit
integer parameters....  It kind of makes sense.

I bet people will be ticked that we're changing an interface signature in a
Beta...  but hey, it's that or suck just because of a version label... LOL.

I'll create a JIRA ticket with a copy of this thread.

Clinton



On Sun, Aug 30, 2009 at 11:14 PM, Carlos Pita <ca...@gmail.com>wrote:

> > @Select("select * from employee where first_name = #{firstName} and
> > last_name = #{lastName})
> > List<Employee> findEmployeesLike(@Param("firstName") String firstName,
> > @Param("lastName") String lastName, Constraint offsetLimit);
>
> Clinton, after considering all of your insightful remarks altogether
> I've come to the conclusion that the above option is ok, because:
>
> 1) I don't care about exposing Constraint (or ResultHandler) to upper
> layers anymore. It's fine for me.
>
> 2) Now I'm not thinking in terms of full-fledged daos (although I must
> say after your last post that my concept of dao was far simpler than
> yours from the very beginning, not so distant from your beloved
> mappers at all), so I don't expect full interface flexibility, no
> matter what this thread's subject still asks for :).
>
> 3) Although redundant and repetitive, @Param anotations will be a very
> convenient shortcut for the alternative procedures of
>
> i. building a map: cumbersome, not type-safe thus goes against the
> purpose of mapper interfaces.
>
> ii. creating simple dtos for the mere purpose of passing parameters:
> type-safe but yet more cumbersome.
>
> Of course, for the usual single parameter signature, annotation will
> be optional (or even forbidden).
>
> Consider the difference:
>
> i) using a map:
>
> List<User> findCommonFriends(Map<String, User> userPair);
>
> Map<String,User> userPair = new HashMap<String,User>();
> userPair.put("user1", user1);
> userPair.put("user2", user2);
>
> ii)  using a dto:
>
> class UserPair {
>
>   private final User user1;
>   private final User user2;
>
>   public UserPair(User user1, User user2) {
>      this.user1 = user1;
>      this.user2 = user2;
>   }
>
>   public User getUser1() {
>     return user1;
>   }
>
>   public User getUser2() {
>     return user2;
>   }
> }
> List<User> findCommonFriends(UserPair userPair);
>
> iii) using annotations
>
> List<User> findCommonFriends(@Param("user1") User user1,
> @Param("user2") User user2);
>
>
> Of course there are a number of tricks than can be done to alleviate
> the exuberance of (i) and (ii)
> to a certain extent, but not even remotely close to (iii) briefness.
>
>
> Have we a deal ;) ?
>
> Best regards
> --
> Carlos
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

Re: Unconstrained signature interface mappers for ibatis 3

Posted by Carlos Pita <ca...@gmail.com>.
> @Select("select * from employee where first_name = #{firstName} and
> last_name = #{lastName})
> List<Employee> findEmployeesLike(@Param("firstName") String firstName,
> @Param("lastName") String lastName, Constraint offsetLimit);

Clinton, after considering all of your insightful remarks altogether
I've come to the conclusion that the above option is ok, because:

1) I don't care about exposing Constraint (or ResultHandler) to upper
layers anymore. It's fine for me.

2) Now I'm not thinking in terms of full-fledged daos (although I must
say after your last post that my concept of dao was far simpler than
yours from the very beginning, not so distant from your beloved
mappers at all), so I don't expect full interface flexibility, no
matter what this thread's subject still asks for :).

3) Although redundant and repetitive, @Param anotations will be a very
convenient shortcut for the alternative procedures of

i. building a map: cumbersome, not type-safe thus goes against the
purpose of mapper interfaces.

ii. creating simple dtos for the mere purpose of passing parameters:
type-safe but yet more cumbersome.

Of course, for the usual single parameter signature, annotation will
be optional (or even forbidden).

Consider the difference:

i) using a map:

List<User> findCommonFriends(Map<String, User> userPair);

Map<String,User> userPair = new HashMap<String,User>();
userPair.put("user1", user1);
userPair.put("user2", user2);

ii)  using a dto:

class UserPair {

   private final User user1;
   private final User user2;

   public UserPair(User user1, User user2) {
      this.user1 = user1;
      this.user2 = user2;
   }

   public User getUser1() {
     return user1;
   }

   public User getUser2() {
     return user2;
   }
}
List<User> findCommonFriends(UserPair userPair);

iii) using annotations

List<User> findCommonFriends(@Param("user1") User user1,
@Param("user2") User user2);


Of course there are a number of tricks than can be done to alleviate
the exuberance of (i) and (ii)
to a certain extent, but not even remotely close to (iii) briefness.


Have we a deal ;) ?

Best regards
--
Carlos

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


Re: Unconstrained signature interface mappers for ibatis 3

Posted by Clinton Begin <cl...@gmail.com>.
I think your point about the "prioritizing" the rest of the application
code, even at the expense of a bit of duplication in the interface, is a
good one.  And if that's the case, I think my preference would be for this
syntax:

@Select("select * from employee where first_name = #{firstName} and
last_name = #{lastName})
List<Employee> findEmployeesLike(@Param("firstName") String firstName,
@Param("lastName") String lastName);

The reason being, we'd need to mark the "special" parameters for
pagination.  Unless I introduce a class for that..... hmmm... what are your
thoughts on the following two options:

@Select("select * from employee where first_name = #{firstName} and
last_name = #{lastName})
List<Employee> findEmployeesLike(@Param("firstName") String firstName,
@Param("lastName") String lastName, @Offset int offset, @Limit, int limit);

@Select("select * from employee where first_name = #{firstName} and
last_name = #{lastName})
List<Employee> findEmployeesLike(@Param("firstName") String firstName,
@Param("lastName") String lastName, Constraint offsetLimit);

Where the latter would be used like:

findEmployeesLike("C%", "B%", new Constraint(offset,limit));

I could detect the constraint type and treat all other parameters like SQL
parameters.  I could do the same with the ResultHandler...

findEmployeesLike("C%", "B%", new Constraint(offset,limit), new
ResultHandler(){...});

I think I answered my own question, I definitely like that better than the
annotations (other than for the actual parameters themselves.  Hmmm... I
almost like that better than how I have it now.  It does introduce an iBATIS
type into your Mapper signature though... But then again ResultHandler is a
dependency already.  I suppose if I wanted to go crazy I could accept any
class named Constraint that had two integer properties ... LOL :-)

Thoughts?

Cheers,
Clinton

On Sun, Aug 30, 2009 at 12:03 PM, <ca...@gmail.com> wrote:

> > I really wish Java made this easier.  One thought I had to submit to the
> JCP
> > was to add introspection on parameter names by having the compiler
> > automatically create annotations for the parameter names.
>
> This was scheduled for java 6 but it was postponed, now it seems unlikely
> that java 7 will introduce it either, so we have to wait for java 8 at
> least.
>
> There is the paranamer library that follows an approach similar to the
> one I described in my previous mail: it obtains the info parsing the
> debug enabled bytecode with asm.
>
> Regards
> --
> Carlos
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

Re: Unconstrained signature interface mappers for ibatis 3

Posted by ca...@gmail.com.
> I really wish Java made this easier.  One thought I had to submit to the JCP
> was to add introspection on parameter names by having the compiler
> automatically create annotations for the parameter names.

This was scheduled for java 6 but it was postponed, now it seems unlikely
that java 7 will introduce it either, so we have to wait for java 8 at
least.

There is the paranamer library that follows an approach similar to the
one I described in my previous mail: it obtains the info parsing the
debug enabled bytecode with asm.

Regards
--
Carlos

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


Re: Unconstrained signature interface mappers for ibatis 3

Posted by Clinton Begin <cl...@gmail.com>.
I love the idea, and I think we even have it on the wiki...

However, I attempted the implementation and could not land on a design that
was nice.  The biggest problem is that Java lacks introspection on method
parameter names.  What I would really love is:

@Select("select * from employee where first_name = #{firstName}" and
last_name = #{lastName})
Employee findEmployeeLike(String firstName, String lastName);

That would truly be awesome (of course complex types would work too).   This
is perfectly possible in C#, where I can get the names of the parameters.
However in Java, there is no such means.  So that leaves us with pretty much
two options:

1) Ordinal -- I don't like this, because it's akin to the ordinal ? params
in standard JDBC prepared statements. By supporting multiple params, the
value of the feature should increase with more params, but here, adding more
params makes the SQL less readable and harder to change later (i.e.
refactoring to add a new param in the middle of the method signature).
Doesn't bode well for this feature.

@Select("select * from employee where first_name = #{1} and last_name =
#{2})
Employee findEmployeeLike(String firstName, String lastName);

2) Annotations -- We could add annotations to the parameters... this just
ended up looking silly.

@Select("select * from employee where first_name = #{firstName} and
last_name = #{lastName})
Employee findEmployeeLike(@Param("firstName") String firstName,
@Param("lastName") String lastName);

An alternative was to use a single annotation...

@Select("select * from employee where first_name = #{firstName} and
last_name = #{lastName})
@Params("firstName","lastName")
Employee findEmployeeLike(String firstName, String lastName);

But that kind of repetition makes me sad.  :-(

At the end of the day I gave up, because all of these were so repetitive,
hard to maintain (due to the alignment and ordinal positioning) and don't
read well.

I really wish Java made this easier.  One thought I had to submit to the JCP
was to add introspection on parameter names by having the compiler
automatically create annotations for the parameter names.

For example, given the method:

Employee findEmployeeLike(String firstName, String lastName);

The compiler would automatically create @MethodParameterName annotation (or
something similar) for each parameter.  Then I could either use the regular
annotation API to fetch them, or a cleaner API like String[]
method.getParameterNames().

But I decided by the time that made it into the framework we'd be at JDK 9
and who knows where iBATIS would be.  :-)

I'm open to more ideas... but the goals have to be:

1) No repetition
2) No ordinal positioning
3) Descriptive SQL
4) Easy to maintain

Thoughts?

Cheers,
Clinton

On Sun, Aug 30, 2009 at 3:30 AM, <ca...@gmail.com> wrote:

> > It just requires a trivial modification in MapperMethod and a simple
> > mechanism to access positional parameters to get it working. For
> > example, MapperMethod could create a Map and put the first argument
> > under the key "first", the second one under "second", etc. That is,
> > positional access "by name". Of course, in case the number of
> > arguments were only one, the usual mechanism would follow.
>
>
> Another possibility is to take advantage of java 5 varargs feature and
> allow SqlSession methods to accept multiple parameters with Object...:
>
> Object selectOne(String statement, Object... parameters);
>
> (Of course, the currently overloaded selectOne:
>
>     Object selectOne(String statement);
>     Object selectOne(String statement, Object parameter);
>
> would be merged into the single method above).
>
> As before, when length > 1 the varargs will be automatically stored into
> a Map under "positional" keys like "arg1", "arg2", etc (I'm not sure if
> the shorter "1", "2", etc are compatible with javabeans as in "bean.1",
> "bean.2").
>
> This way MapperMethod will just forward its Object[] args to the SqlSession
> method selectOne, selectList, etc.
>
> Notice that any change that I have proposed is absolutely backwards
> compatible:
>
> 1) Object... still can take single arguments.
> 2) If just one argument is given the { "arg1": arg1, "arg2": arg2, ...}
> map will not be created at all.
> 3) Sql expecting one argument won't need to be modified.
>
> However, SqlSession won't compile with java 1.4 or older due to the
> introduction of varargs. I don't know if this is a concern for ibatis 3.
> In that case, the proposal of my previous post doesn't suffer the same
> inconvenience, althought it is more limited.
>
> I would like to hear your opinion about it.
>
> Best regards
> --
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

Re: Unconstrained signature interface mappers for ibatis 3

Posted by ca...@gmail.com.
> It just requires a trivial modification in MapperMethod and a simple
> mechanism to access positional parameters to get it working. For
> example, MapperMethod could create a Map and put the first argument
> under the key "first", the second one under "second", etc. That is,
> positional access "by name". Of course, in case the number of
> arguments were only one, the usual mechanism would follow.


Another possibility is to take advantage of java 5 varargs feature and
allow SqlSession methods to accept multiple parameters with Object...:

Object selectOne(String statement, Object... parameters);

(Of course, the currently overloaded selectOne:

     Object selectOne(String statement);
     Object selectOne(String statement, Object parameter);

would be merged into the single method above).

As before, when length > 1 the varargs will be automatically stored into
a Map under "positional" keys like "arg1", "arg2", etc (I'm not sure if
the shorter "1", "2", etc are compatible with javabeans as in "bean.1",
"bean.2").

This way MapperMethod will just forward its Object[] args to the SqlSession
method selectOne, selectList, etc.

Notice that any change that I have proposed is absolutely backwards
compatible:

1) Object... still can take single arguments.
2) If just one argument is given the { "arg1": arg1, "arg2": arg2, ...}
map will not be created at all.
3) Sql expecting one argument won't need to be modified.

However, SqlSession won't compile with java 1.4 or older due to the
introduction of varargs. I don't know if this is a concern for ibatis 3.
In that case, the proposal of my previous post doesn't suffer the same
inconvenience, althought it is more limited.

I would like to hear your opinion about it.

Best regards
--

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org