ibatis-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Paul Benedict" <pbened...@apache.org>
Subject Re: Working with nested interfaces: a problem to solve
Date Mon, 15 Jan 2007 15:54:20 GMT
Jeff and Clinton,

Thanks for the responses! However, I am going to push this question a bit
more because I think it's not limited to immutability. Granted, your points
on the Immutable Pattern are good ones, but the topic is ancillary. If I did
make the interface mutable, the problem will still exist because of
polymorphism. The immutability pattern was just a distraction to the topic;
polymorphism is the actual culprit here.

The reason BImpl is taking an A interface is because I have many A
implementations. Outside the DAO layer, I am performing additional logic to
proxy or delegate the A instance constructed from iBATIS, so my BImpl class
cannot be tied to a specific implementation of A. As I was trying to state
(but not so clearly), was that iBATIS is constructing objects in a fashion
which makes this polymorphism impossible.

Let me detail how iBATIS seems to be working in an example, and I think you
may agree a change is needed:

<resultMap id="BResult" class="BImpl">
  <result property="a" resultMap="AResult"/>
</resultMap>

<resultMap id="AResult" class="AImpl">
  <result property="name" column="name" />
</resultMap>

These are the steps of the mapper:
1) Construct a BImpl instance
2) Construct a AImpl instance
3) Set the AImpl instance into BImpl.setA
4) Call BImpl.getA.setName

iBATIS errrs out on #4 because it invokes BImpl.setA(), but gets back only
the interface from BImpl.getA(). The problem is about polymorphism (this
would be the same thing with subclasses), and I would not expect the mapper
to work this way. Why is the mapper setting a blank object, trying to get it
back, and then setting the properties? This is reverse of my expectations.
It should hold onto the reference it just constructed, set the properties,
and then at the very end store the object in the parent.

I would change it to be a stack-based solution:
1) Construct a BImpl instance
2) Construct a AImpl instance
3) Call AImpl.setName
4) Set the AImpl instance into BImpl.setA

The short summary:

For nested properties, the mapper should not always throw away the instance
it just created. For the general use case, it should not have to call the
parent object's getter again to retrieve the child instance (the exception
would be cglib lazy loading when the instance is no longer held). Instead
set the properties with the instance it just made.

PS: +1 on 2.3.

Paul

On 1/15/07, Jeff Butler <jeffgbutler@gmail.com> wrote:
>
> Hmmm - on second thought, maybe a ResultObjectFactory can't solve this
> issue.  But I really dislike the idea of changing iBATIS so that it, in
> effect, ignores the interfaces you declare by remembering their
> implementations.  If there's an interface, there's always a possibility of
> more than one implementation.  I think it would be wrong to have iBATIS try
> to deduce what you mean here.
>
> I think the best way to handle this would be to skip the immutable
> interface and write private setters.  iBATIS can use the private setters as
> of V2.2.
>
> BTW - it's not that I don't like immutability, I just think that this
> pattern doesn't really achieve it.  If someone is bent on changing
> your so-called immutable object, it's so easy to do.  The real problem here
> is that you have to trust programmers to do the right thing.  If you don't
> trust them not to call the setters, how can you trust them not to cast the
> interface to the concrete class?  I think the ultimate solution is to have
> iBATIS work with parameterized constructors but that is a V3 thing.
>
> Jeff Butler
>
>
> On 1/14/07, Paul Benedict <pbenedict@apache.org> wrote:
> >
> > Jeff,
> >
> > Thanks for the reply. I know not everyone likes the immutable pattern,
> > but I have found it tremendously useful and cuts down on a lot of
> > synchronized behavior because it creates thread-safe access. I am not
> > promoting its use for everything, but because I have quite a few classes
> > which do this, I have constantly found this a problem when using iBATIS.
> >
> >
> > How would a ResultObjectFactory solve this problem? I read up on it, but
> > can you give me exactly what you're thinking?
> >
> > Thanks,
> > Paul
> >
> > Jeff Butler wrote:
> > > First thought - ugh.  I really don't care for domain classes being
> > > built this way.  We did it once and it really didn't solve anything.
> > > If a programmer wants to break the immutability, it is a simple matter
> > > to cast the interface to the mutable implementation.  So it's just a
> > > lot of hassle for no benefit.  (BTW - I know this is promoted in the
> > > Sun blueprints catalog, but I still think it's awful.  But that's just
> > > my 2 cents - YMMV)
> > >
> > > Second thought - if you really want to do this, you can code a
> > > ResultObjectFactory and supply the concrete implementations yourself.
> > >
> > > Jeff Butler
> > >
> > >
> > >
> > > On 1/14/07, *Paul Benedict* <pbenedict@apache.org
> > > <mailto:pbenedict@apache.org>> wrote:
> > >
> > >     I have this problem currently in iBATIS 2. I would prefer it be
> > solved
> > >     in 2.4, but if it is more extensive in scope, then I wouldn't mind
> >
> > >     seeing it pushed off to version 3.
> > >
> > >     Here are two classes which have two immutable interfaces:
> > >     interface A {          class AImpl implements A {
> > >       String getName();      String getName();
> > >     }                        void setName(String name);
> > >                            }
> > >
> > >     interface B {          class BImpl implements B {
> > >       A getA();              A getA();
> > >     }                        void setA(A a);
> > >                            }
> > >
> > >     At the moment iBATIS cannot create a BImpl because the get/setA
> > >     methods
> > >     are returning the interface signature (not the concrete mutable
> > >     class).
> > >     Even though iBATIS will call setA with an AImpl, it forgets the
> > >     implementation and cannot find setName on the returned object.
> > >
> > >     However, I think iBATIS CAN solve this problem!!! It's very easy:
> > the
> > >     mapper needs to remember the concrete implementation injected, and
> > >     cast
> > >     that when calling the setter.
> > >
> > >     The only way to currently solve this problem is by altering the
> > >     class to
> > >     do this below. Here I have provided a separate set of properties
> > just
> > >     for iBATIS object construction. It's not pretty but it's the only
> > way
> > >     for iBATIS to "remember" the concrete type injected:
> > >
> > >     class BImpl implements B {
> > >       A getA();
> > >       void setA(A a);
> > >       AImpl getAImpl();
> > >       void setAImpl(AImpl);
> > >     }
> > >
> > >     Thoughts?
> > >
> > >     Paul
> > >
> > >
> >
> >
>

Mime
View raw message