Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF "Technology" (Ecore Tools, EMFatic, etc)  » [Teneo/EMF] Question
[Teneo/EMF] Question [message #114465] Tue, 11 March 2008 22:04 Go to next message
Jason Henriksen is currently offline Jason HenriksenFriend
Messages: 231
Registered: July 2009
Senior Member
Here's a really fun one for you guys. Sorry to post in both groups, but
I wanted to make sure both Ed and Martin see this.

I have an object that I've loaded from the database that has lists of
child object. These lists are lazily loaded.

So for example:

class Parent{
List<ChildA> aList;
List<ChildB> bList;
}

For efficiency, I've loaded aList but left bList uninitialized. I now
want to serialize this object to XML so I can send it in a SOAP message.
I ONLY want to send aList but not send bList. I didn't load that from
the DB so it shouldn't be a problem.

Except that eIsSet() on the list looks like this:

case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
return (labNetworkMemberList != null &&
!labNetworkMemberList.isEmpty();

and calling labNetworkMemberList.isEmpty() causes the list to be loaded
from the database!!!
(And if I disconnect the session I get ObjectNotInitialized exceptions)

Once it's loaded the whole object gets serialized into the XML and the
benefit of lazy loading is lost.

It turns out that this is a really common problem using hibernate and
lazy loading with serialization. In fact, by using EMF we're ahead of
the game because we have the eIsSet() methods which we can hack. If we
apply this hack we can get the lazy loading behavior we want:

//... from inside of eIsSet ...
case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
//--- this list may be initialized by Teneo/Hibernate or maybe not
// Note that we use reflection because only the server side has
// Teneo installed. Since these objects are used by the client
// and by the server we don't know if isInitialized() is present.
// On the client we ignore the exception and
// defer to the value set in isEmpty()
// On the server this fails out of the if check BEFORE isEmpty()
// gets called to prevent the list from being loaded.
boolean isInitialized=true;
try {
Class c = contactList.getClass();
Method m = c.getMethod("isInitialized", new Class[] {})
isInitialized = m.invoke(contactList, new Object[] {})
} catch (Exception e) {/* ignored exception */ }
return (labNetworkMemberList != null &&
isInitialized &&
!labNetworkMemberList.isEmpty();


I could write all the refection into a utility and then build a
refactoring tool that inserts a call to that utility into the middle of
the if statement for each list on the object, but I'm hoping you guys
have a better idea.

What we really have is a problem with the meaning of isEmpty(). EMF
assumes we mean to ask if the real list has no children. But in the
context of a serialization I wan to know if the current copy of the
object's list is empty.

So what do you guys think of all that? Am I better to refactor all the
generated code or should I be trying to augment isEmpty somehow? Or is
there some better way to handle this that I haven't found yet? Any
suggestions are much appreciated.

Thanks,

Jason Henriksen
Re: [Teneo/EMF] Question [message #114478 is a reply to message #114465] Tue, 11 March 2008 22:31 Go to previous messageGo to next message
Martin Taal is currently offline Martin TaalFriend
Messages: 5468
Registered: July 2009
Senior Member
Hi Jason,
One can debate ofcourse if eIsSet should return false on an uninitialized but non-empty list. I
think the eIsSet should return true in this case and therefore should do isEmpty. The reason is that
a non-loaded lists is maybe technically empty but conceptually it is not empty (as the database has
the list content).
The isEmpty call can be made more efficient for non-initialized collections. But that's a separate
discussion.

Instead of changing eIsSet I would change the serialization code should so that it does not load
uninitialized lists. I am no expert on this area of EMF but maybe EMF's behavior can be customized
in this area.

As an example the HibernateResource has a nonresolving iterator which walks passed all objects in a
resource without loading non-loaded lists (so the content of non-loaded lists is not visited).

gr. Martin

jason henriksen wrote:
>
> Here's a really fun one for you guys. Sorry to post in both groups, but
> I wanted to make sure both Ed and Martin see this.
>
> I have an object that I've loaded from the database that has lists of
> child object. These lists are lazily loaded.
>
> So for example:
>
> class Parent{
> List<ChildA> aList;
> List<ChildB> bList;
> }
>
> For efficiency, I've loaded aList but left bList uninitialized. I now
> want to serialize this object to XML so I can send it in a SOAP message.
> I ONLY want to send aList but not send bList. I didn't load that from
> the DB so it shouldn't be a problem.
>
> Except that eIsSet() on the list looks like this:
>
> case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
> return (labNetworkMemberList != null &&
> !labNetworkMemberList.isEmpty();
>
> and calling labNetworkMemberList.isEmpty() causes the list to be loaded
> from the database!!!
> (And if I disconnect the session I get ObjectNotInitialized exceptions)
>
> Once it's loaded the whole object gets serialized into the XML and the
> benefit of lazy loading is lost.
>
> It turns out that this is a really common problem using hibernate and
> lazy loading with serialization. In fact, by using EMF we're ahead of
> the game because we have the eIsSet() methods which we can hack. If we
> apply this hack we can get the lazy loading behavior we want:
>
> //... from inside of eIsSet ...
> case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
> //--- this list may be initialized by Teneo/Hibernate or maybe not
> // Note that we use reflection because only the server side has
> // Teneo installed. Since these objects are used by the client
> // and by the server we don't know if isInitialized() is present.
> // On the client we ignore the exception and
> // defer to the value set in isEmpty()
> // On the server this fails out of the if check BEFORE isEmpty()
> // gets called to prevent the list from being loaded.
> boolean isInitialized=true;
> try {
> Class c = contactList.getClass();
> Method m = c.getMethod("isInitialized", new Class[] {})
> isInitialized = m.invoke(contactList, new Object[] {})
> } catch (Exception e) {/* ignored exception */ }
> return (labNetworkMemberList != null &&
> isInitialized &&
> !labNetworkMemberList.isEmpty();
>
>
> I could write all the refection into a utility and then build a
> refactoring tool that inserts a call to that utility into the middle of
> the if statement for each list on the object, but I'm hoping you guys
> have a better idea.
>
> What we really have is a problem with the meaning of isEmpty(). EMF
> assumes we mean to ask if the real list has no children. But in the
> context of a serialization I wan to know if the current copy of the
> object's list is empty.
>
> So what do you guys think of all that? Am I better to refactor all the
> generated code or should I be trying to augment isEmpty somehow? Or is
> there some better way to handle this that I haven't found yet? Any
> suggestions are much appreciated.
>
> Thanks,
>
> Jason Henriksen
>
>
>
>
>
>


--

With Regards, Martin Taal

Springsite/Elver.org
Office: Hardwareweg 4, 3821 BV Amersfoort
Postal: Nassaulaan 7, 3941 EC Doorn
The Netherlands
Tel: +31 (0)84 420 2397
Fax: +31 (0)84 225 9307
Mail: mtaal@springsite.com - mtaal@elver.org
Web: www.springsite.com - www.elver.org
Re: [Teneo/EMF] Question [message #114515 is a reply to message #114478] Wed, 12 March 2008 12:22 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: merks.ca.ibm.com

This is a multi-part message in MIME format.
--------------030303040403010200030900
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Guys,

Comments below.

Martin Taal wrote:
> Hi Jason,
> One can debate ofcourse if eIsSet should return false on an
> uninitialized but non-empty list.
Sounds odd. EMF doesn't directly support non-empty lists that are not
considered set and hence doesn't support a default value for a
multi-valued feature. It's a little tricky to support something like
this. Consider when you are deserializing and the normal behavior is
just to append to the list as you see elements with values. To support
a list that's pre-populated, you'd have to clear the list first before
adding to it, and you'd have to do that only the first time. You can
imagine that's a bit tricky and somewhat costly to manage doing it only
once. A copier would have similar issues...
> I think the eIsSet should return true in this case and therefore
> should do isEmpty. The reason is that a non-loaded lists is maybe
> technically empty but conceptually it is not empty (as the database
> has the list content).
That makes sense. If it will be non-empty but in a lazy way, it's still
non-empty.
> The isEmpty call can be made more efficient for non-initialized
> collections. But that's a separate discussion.
I think that's why lists have isEmpty as well as size even though size()
!= 0 implies isEmpty() == false. I.e., you can compute non-emptiness
more efficiently than the size.
>
> Instead of changing eIsSet I would change the serialization code
> should so that it does not load uninitialized lists. I am no expert on
> this area of EMF but maybe EMF's behavior can be customized in this area.
When getting a value in XMLHelperImpl we do indicate that we don't want
proxies to be resolved.

public Object getValue(EObject obj, EStructuralFeature f)
{
return obj.eGet(f, false);
}

It seems to me when serializing though, you will need the contents for
the list to serialize the items... I'll read more below...
>
> As an example the HibernateResource has a nonresolving iterator which
> walks passed all objects in a resource without loading non-loaded
> lists (so the content of non-loaded lists is not visited).
Kind of like InternalEList supports visiting the list without resolving
proxies...
>
> gr. Martin
>
> jason henriksen wrote:
>>
>> Here's a really fun one for you guys. Sorry to post in both groups,
>> but I wanted to make sure both Ed and Martin see this.
You miss addressed on the group. :-P Don't worry, I watch many of the
newsgroups and will always see EMFT posts.
>>
>> I have an object that I've loaded from the database that has lists of
>> child object. These lists are lazily loaded.
>>
>> So for example:
>>
>> class Parent{
>> List<ChildA> aList;
>> List<ChildB> bList;
>> }
>>
>> For efficiency, I've loaded aList but left bList uninitialized. I
>> now want to serialize this object to XML so I can send it in a SOAP
>> message. I ONLY want to send aList but not send bList. I didn't
>> load that from the DB so it shouldn't be a problem.
If the bList's feature was transient, then it wouldn't be serialized.
>>
>> Except that eIsSet() on the list looks like this:
>>
>> case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
>> return (labNetworkMemberList != null &&
>> !labNetworkMemberList.isEmpty();
>>
>> and calling labNetworkMemberList.isEmpty() causes the list to be
>> loaded from the database!!!
>> (And if I disconnect the session I get ObjectNotInitialized exceptions)
It really should return true as Martin says if there there are contents
in the actual list.
>>
>> Once it's loaded the whole object gets serialized into the XML and
>> the benefit of lazy loading is lost.
>>
>> It turns out that this is a really common problem using hibernate and
>> lazy loading with serialization. In fact, by using EMF we're ahead
>> of the game because we have the eIsSet() methods which we can hack.
>> If we apply this hack we can get the lazy loading behavior we want:
>>
>> //... from inside of eIsSet ...
>> case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
>> //--- this list may be initialized by Teneo/Hibernate or maybe not
>> // Note that we use reflection because only the server side has
>> // Teneo installed. Since these objects are used by the client
>> // and by the server we don't know if isInitialized() is present.
>> // On the client we ignore the exception and
>> // defer to the value set in isEmpty()
>> // On the server this fails out of the if check BEFORE isEmpty()
>> // gets called to prevent the list from being loaded.
>> boolean isInitialized=true;
>> try {
>> Class c = contactList.getClass();
>> Method m = c.getMethod("isInitialized", new Class[] {})
>> isInitialized = m.invoke(contactList, new Object[] {})
>> } catch (Exception e) {/* ignored exception */ }
>> return (labNetworkMemberList != null &&
>> isInitialized &&
>> !labNetworkMemberList.isEmpty();
>>
>>
>> I could write all the refection into a utility and then build a
>> refactoring tool that inserts a call to that utility into the middle
>> of the if statement for each list on the object, but I'm hoping you
>> guys have a better idea.
I think this is solving the problem in the wrong place. If the list has
contents that are only lazily present, it still has contents and those
contents should be copied or serialized normally. If you don't want
that for some reason, it's best to specialize that locally, not in the
model itself.
>>
>> What we really have is a problem with the meaning of isEmpty(). EMF
>> assumes we mean to ask if the real list has no children. But in the
>> context of a serialization I wan to know if the current copy of the
>> object's list is empty.
Yes, that's what I mean by you having specific needs because generally
is someone is transmitting an object via XML, they'll want all the real
contents, not just what happens to be loaded so far.
>>
>> So what do you guys think of all that? Am I better to refactor all
>> the generated code or should I be trying to augment isEmpty somehow?
>> Or is there some better way to handle this that I haven't found yet?
>> Any suggestions are much appreciated.
Perhaps the simplest way to specialize the code would be to specialize
this method in XMLSaveImpl to ignore certain features you don't want
saved (if it doesn't make sense to mark them as transient, since they
aren't really transient when you save to hibernate):

protected boolean shouldSaveFeature(EObject o, EStructuralFeature f)
{
return o.eIsSet(f) || keepDefaults && f.getDefaultValueLiteral()
!= null;
}

>>
>> Thanks,
>>
>> Jason Henriksen
>>
>>
>>
>>
>>
>>
>
>


--------------030303040403010200030900
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Guys,<br>
<br>
Comments below.<br>
<br>
Martin Taal wrote:
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">Hi
Jason,
<br>
One can debate ofcourse if eIsSet should return false on an
uninitialized but non-empty list.</blockquote>
Sounds odd.&nbsp; EMF doesn't directly support non-empty lists that are not
considered set and hence doesn't support a default value for a
multi-valued feature.&nbsp; It's a little tricky to support something like
this.&nbsp; Consider when you are deserializing and the normal behavior is
just to append to the list as you see elements with values.&nbsp; To support
a list that's pre-populated, you'd have to clear the list first before
adding to it, and you'd have to do that only the first time.&nbsp; You can
imagine that's a bit tricky and somewhat costly to manage doing it only
once.&nbsp; A copier would have similar issues...<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite"> I
think the eIsSet should return true in this case and therefore should
do isEmpty. The reason is that a non-loaded lists is maybe technically
empty but conceptually it is not empty (as the database has the list
content).
<br>
</blockquote>
That makes sense.&nbsp; If it will be non-empty but in a lazy way, it's
still non-empty.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">The
isEmpty call can be made more efficient for non-initialized
collections. But that's a separate discussion.
<br>
</blockquote>
I think that's why lists have isEmpty as well as size even though
size() != 0 implies isEmpty() == false.&nbsp; I.e., you can compute
non-emptiness more efficiently than the size.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite"><br>
Instead of changing eIsSet I would change the serialization code should
so that it does not load uninitialized lists. I am no expert on this
area of EMF but maybe EMF's behavior can be customized in this area.
<br>
</blockquote>
When getting a value in XMLHelperImpl we do indicate that we don't want
proxies to be resolved.&nbsp; <br>
<br>
&nbsp; public Object getValue(EObject obj, EStructuralFeature f)<br>
&nbsp; {<br>
&nbsp;&nbsp;&nbsp; return obj.eGet(f, false);<br>
&nbsp; }<br>
<br>
It seems to me when serializing though, you will need the contents for
the list to serialize the items...&nbsp; I'll read more below...<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite"><br>
As an example the HibernateResource has a nonresolving iterator which
walks passed all objects in a resource without loading non-loaded lists
(so the content of non-loaded lists is not visited).
<br>
</blockquote>
Kind of like InternalEList supports visiting the list without resolving
proxies...<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite"><br>
gr. Martin
<br>
<br>
jason henriksen wrote:
<br>
<blockquote type="cite"><br>
Here's a really fun one for you guys.&nbsp; Sorry to post in both groups,
but I wanted to make sure both Ed and Martin see this.
<br>
</blockquote>
</blockquote>
You miss addressed on the group.&nbsp;&nbsp; :-P&nbsp; Don't worry, I watch many of
the newsgroups and will always see EMFT posts.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
I have an object that I've loaded from the database that has lists of
child object.&nbsp; These lists are lazily loaded.
<br>
<br>
So for example:
<br>
<br>
class Parent{
<br>
&nbsp;&nbsp;&nbsp; List&lt;ChildA&gt; aList;
<br>
&nbsp;&nbsp;&nbsp; List&lt;ChildB&gt; bList;
<br>
}
<br>
<br>
For efficiency, I've loaded aList but left bList uninitialized.&nbsp; I now
want to serialize this object to XML so I can send it in a SOAP
message. &nbsp;I ONLY want to send aList but not send bList.&nbsp; I didn't load
that from the DB so it shouldn't be a problem.
<br>
</blockquote>
</blockquote>
If the bList's feature was transient, then it wouldn't be serialized. <br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
Except that eIsSet() on the list looks like this:
<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; return&nbsp; (labNetworkMemberList != null &amp;&amp;
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; !labNetworkMemberList.isEmpty();
<br>
<br>
and calling labNetworkMemberList.isEmpty() causes the list to be loaded
from the database!!!
<br>
(And if I disconnect the session I get ObjectNotInitialized exceptions)
<br>
</blockquote>
</blockquote>
It really should return true as Martin says if there there are contents
in the actual list.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
Once it's loaded the whole object gets serialized into the XML and the
benefit of lazy loading is lost.
<br>
<br>
It turns out that this is a really common problem using hibernate and
lazy loading with serialization.&nbsp; In fact, by using EMF we're ahead of
the game because we have the eIsSet() methods which we can hack.&nbsp; If we
apply this hack we can get the lazy loading behavior we want:
<br>
<br>
//... from inside of eIsSet ...
<br>
case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
<br>
&nbsp; //--- this list may be initialized by Teneo/Hibernate or maybe not
<br>
&nbsp; //&nbsp;&nbsp;&nbsp; Note that we use reflection because only the server side has
<br>
&nbsp; //&nbsp;&nbsp;&nbsp; Teneo installed.&nbsp; Since these objects are used by the client
<br>
&nbsp; //&nbsp;&nbsp;&nbsp; and by the server we don't know if isInitialized() is present.
<br>
&nbsp; //&nbsp;&nbsp;&nbsp; On the client we ignore the exception and
<br>
&nbsp; //&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs p; defer to the value set in isEmpty()
<br>
&nbsp; //&nbsp;&nbsp;&nbsp; On the server this fails out of the if check BEFORE isEmpty()
<br>
&nbsp; //&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs p; gets called to prevent the list from being loaded.
<br>
&nbsp; boolean isInitialized=true;
<br>
&nbsp; try {
<br>
&nbsp;&nbsp;&nbsp; Class c = contactList.getClass();
<br>
&nbsp;&nbsp;&nbsp; Method m = c.getMethod("isInitialized", new Class[] {})
<br>
&nbsp;&nbsp;&nbsp; isInitialized = m.invoke(contactList, new Object[] {})
<br>
&nbsp; } catch (Exception e) {/* ignored exception */ }
<br>
&nbsp; return&nbsp; (labNetworkMemberList != null &amp;&amp;
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; isInitialized &amp;&amp;
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; !labNetworkMemberList.isEmpty();
<br>
<br>
<br>
I could write all the refection into a utility and then build a
refactoring tool that inserts a call to that utility into the middle of
the if statement for each list on the object, but I'm hoping you guys
have a better idea.
<br>
</blockquote>
</blockquote>
I think this is solving the problem in the wrong place.&nbsp; If the list
has contents that are only lazily present, it still has contents and
those contents should be copied or serialized normally.&nbsp; If you don't
want that for some reason, it's best to specialize that locally, not in
the model itself.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
What we really have is a problem with the meaning of isEmpty().&nbsp; EMF
assumes we mean to ask if the real list has no children.&nbsp; But in the
context of a serialization I wan to know if the current copy of the
object's list is empty.
<br>
</blockquote>
</blockquote>
Yes, that's what I mean by you having specific needs because generally
is someone is transmitting an object via XML, they'll want all the real
contents, not just what happens to be loaded so far.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
So what do you guys think of all that?&nbsp; Am I better to refactor all the
generated code or should I be trying to augment isEmpty somehow?&nbsp; Or is
there some better way to handle this that I haven't found yet?&nbsp; Any
suggestions are much appreciated.
<br>
</blockquote>
</blockquote>
Perhaps the simplest way to specialize the code would be to specialize
this method in XMLSaveImpl to ignore certain features you don't want
saved (if it doesn't make sense to mark them as transient, since they
aren't really transient when you save to hibernate):<br>
<blockquote>&nbsp; protected boolean shouldSaveFeature(EObject o,
EStructuralFeature f)<br>
&nbsp; {<br>
&nbsp;&nbsp;&nbsp; return o.eIsSet(f) || keepDefaults &amp;&amp;
f.getDefaultValueLiteral() != null;<br>
&nbsp; }<br>
</blockquote>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
Thanks,
<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Jason Henriksen
<br>
<br>
<br>
<br>
<br>
<br>
<br>
</blockquote>
<br>
<br>
</blockquote>
<br>
</body>
</html>

--------------030303040403010200030900--
Re: [Teneo/EMF] Question [message #114591 is a reply to message #114515] Wed, 12 March 2008 20:14 Go to previous message
Jason Henriksen is currently offline Jason HenriksenFriend
Messages: 231
Registered: July 2009
Senior Member
Thanks for the input guys! I agree with your comments that this is
really a serialization problem and should be handled at that point
instead of the eIsSet() method.

In fact, it bring to mind the idea of a view. We have object graphs
that go five and size levels deep and when fully specified the XML can
run into multiple mega-bytes. It might be interesting to annotate
certain xml to appear in one view but not in another view.

Good stuff! Thanks again,

Jason

P.S.: I spoke to my client about potentially making the DDL2XSD
converter open source and he's open to the idea. We'd have to clear it
with the client's legal department and so on but the general sentiment
is that it will eventually happen. I'll let you know as that effort
progresses.
Re: [Teneo/EMF] Question [message #615678 is a reply to message #114465] Tue, 11 March 2008 22:31 Go to previous message
Martin Taal is currently offline Martin TaalFriend
Messages: 5468
Registered: July 2009
Senior Member
Hi Jason,
One can debate ofcourse if eIsSet should return false on an uninitialized but non-empty list. I
think the eIsSet should return true in this case and therefore should do isEmpty. The reason is that
a non-loaded lists is maybe technically empty but conceptually it is not empty (as the database has
the list content).
The isEmpty call can be made more efficient for non-initialized collections. But that's a separate
discussion.

Instead of changing eIsSet I would change the serialization code should so that it does not load
uninitialized lists. I am no expert on this area of EMF but maybe EMF's behavior can be customized
in this area.

As an example the HibernateResource has a nonresolving iterator which walks passed all objects in a
resource without loading non-loaded lists (so the content of non-loaded lists is not visited).

gr. Martin

jason henriksen wrote:
>
> Here's a really fun one for you guys. Sorry to post in both groups, but
> I wanted to make sure both Ed and Martin see this.
>
> I have an object that I've loaded from the database that has lists of
> child object. These lists are lazily loaded.
>
> So for example:
>
> class Parent{
> List<ChildA> aList;
> List<ChildB> bList;
> }
>
> For efficiency, I've loaded aList but left bList uninitialized. I now
> want to serialize this object to XML so I can send it in a SOAP message.
> I ONLY want to send aList but not send bList. I didn't load that from
> the DB so it shouldn't be a problem.
>
> Except that eIsSet() on the list looks like this:
>
> case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
> return (labNetworkMemberList != null &&
> !labNetworkMemberList.isEmpty();
>
> and calling labNetworkMemberList.isEmpty() causes the list to be loaded
> from the database!!!
> (And if I disconnect the session I get ObjectNotInitialized exceptions)
>
> Once it's loaded the whole object gets serialized into the XML and the
> benefit of lazy loading is lost.
>
> It turns out that this is a really common problem using hibernate and
> lazy loading with serialization. In fact, by using EMF we're ahead of
> the game because we have the eIsSet() methods which we can hack. If we
> apply this hack we can get the lazy loading behavior we want:
>
> //... from inside of eIsSet ...
> case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
> //--- this list may be initialized by Teneo/Hibernate or maybe not
> // Note that we use reflection because only the server side has
> // Teneo installed. Since these objects are used by the client
> // and by the server we don't know if isInitialized() is present.
> // On the client we ignore the exception and
> // defer to the value set in isEmpty()
> // On the server this fails out of the if check BEFORE isEmpty()
> // gets called to prevent the list from being loaded.
> boolean isInitialized=true;
> try {
> Class c = contactList.getClass();
> Method m = c.getMethod("isInitialized", new Class[] {})
> isInitialized = m.invoke(contactList, new Object[] {})
> } catch (Exception e) {/* ignored exception */ }
> return (labNetworkMemberList != null &&
> isInitialized &&
> !labNetworkMemberList.isEmpty();
>
>
> I could write all the refection into a utility and then build a
> refactoring tool that inserts a call to that utility into the middle of
> the if statement for each list on the object, but I'm hoping you guys
> have a better idea.
>
> What we really have is a problem with the meaning of isEmpty(). EMF
> assumes we mean to ask if the real list has no children. But in the
> context of a serialization I wan to know if the current copy of the
> object's list is empty.
>
> So what do you guys think of all that? Am I better to refactor all the
> generated code or should I be trying to augment isEmpty somehow? Or is
> there some better way to handle this that I haven't found yet? Any
> suggestions are much appreciated.
>
> Thanks,
>
> Jason Henriksen
>
>
>
>
>
>


--

With Regards, Martin Taal

Springsite/Elver.org
Office: Hardwareweg 4, 3821 BV Amersfoort
Postal: Nassaulaan 7, 3941 EC Doorn
The Netherlands
Tel: +31 (0)84 420 2397
Fax: +31 (0)84 225 9307
Mail: mtaal@springsite.com - mtaal@elver.org
Web: www.springsite.com - www.elver.org
Re: [Teneo/EMF] Question [message #615847 is a reply to message #114478] Wed, 12 March 2008 12:22 Go to previous message
Ed Merks is currently offline Ed MerksFriend
Messages: 33140
Registered: July 2009
Senior Member
This is a multi-part message in MIME format.
--------------030303040403010200030900
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Guys,

Comments below.

Martin Taal wrote:
> Hi Jason,
> One can debate ofcourse if eIsSet should return false on an
> uninitialized but non-empty list.
Sounds odd. EMF doesn't directly support non-empty lists that are not
considered set and hence doesn't support a default value for a
multi-valued feature. It's a little tricky to support something like
this. Consider when you are deserializing and the normal behavior is
just to append to the list as you see elements with values. To support
a list that's pre-populated, you'd have to clear the list first before
adding to it, and you'd have to do that only the first time. You can
imagine that's a bit tricky and somewhat costly to manage doing it only
once. A copier would have similar issues...
> I think the eIsSet should return true in this case and therefore
> should do isEmpty. The reason is that a non-loaded lists is maybe
> technically empty but conceptually it is not empty (as the database
> has the list content).
That makes sense. If it will be non-empty but in a lazy way, it's still
non-empty.
> The isEmpty call can be made more efficient for non-initialized
> collections. But that's a separate discussion.
I think that's why lists have isEmpty as well as size even though size()
!= 0 implies isEmpty() == false. I.e., you can compute non-emptiness
more efficiently than the size.
>
> Instead of changing eIsSet I would change the serialization code
> should so that it does not load uninitialized lists. I am no expert on
> this area of EMF but maybe EMF's behavior can be customized in this area.
When getting a value in XMLHelperImpl we do indicate that we don't want
proxies to be resolved.

public Object getValue(EObject obj, EStructuralFeature f)
{
return obj.eGet(f, false);
}

It seems to me when serializing though, you will need the contents for
the list to serialize the items... I'll read more below...
>
> As an example the HibernateResource has a nonresolving iterator which
> walks passed all objects in a resource without loading non-loaded
> lists (so the content of non-loaded lists is not visited).
Kind of like InternalEList supports visiting the list without resolving
proxies...
>
> gr. Martin
>
> jason henriksen wrote:
>>
>> Here's a really fun one for you guys. Sorry to post in both groups,
>> but I wanted to make sure both Ed and Martin see this.
You miss addressed on the group. :-P Don't worry, I watch many of the
newsgroups and will always see EMFT posts.
>>
>> I have an object that I've loaded from the database that has lists of
>> child object. These lists are lazily loaded.
>>
>> So for example:
>>
>> class Parent{
>> List<ChildA> aList;
>> List<ChildB> bList;
>> }
>>
>> For efficiency, I've loaded aList but left bList uninitialized. I
>> now want to serialize this object to XML so I can send it in a SOAP
>> message. I ONLY want to send aList but not send bList. I didn't
>> load that from the DB so it shouldn't be a problem.
If the bList's feature was transient, then it wouldn't be serialized.
>>
>> Except that eIsSet() on the list looks like this:
>>
>> case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
>> return (labNetworkMemberList != null &&
>> !labNetworkMemberList.isEmpty();
>>
>> and calling labNetworkMemberList.isEmpty() causes the list to be
>> loaded from the database!!!
>> (And if I disconnect the session I get ObjectNotInitialized exceptions)
It really should return true as Martin says if there there are contents
in the actual list.
>>
>> Once it's loaded the whole object gets serialized into the XML and
>> the benefit of lazy loading is lost.
>>
>> It turns out that this is a really common problem using hibernate and
>> lazy loading with serialization. In fact, by using EMF we're ahead
>> of the game because we have the eIsSet() methods which we can hack.
>> If we apply this hack we can get the lazy loading behavior we want:
>>
>> //... from inside of eIsSet ...
>> case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
>> //--- this list may be initialized by Teneo/Hibernate or maybe not
>> // Note that we use reflection because only the server side has
>> // Teneo installed. Since these objects are used by the client
>> // and by the server we don't know if isInitialized() is present.
>> // On the client we ignore the exception and
>> // defer to the value set in isEmpty()
>> // On the server this fails out of the if check BEFORE isEmpty()
>> // gets called to prevent the list from being loaded.
>> boolean isInitialized=true;
>> try {
>> Class c = contactList.getClass();
>> Method m = c.getMethod("isInitialized", new Class[] {})
>> isInitialized = m.invoke(contactList, new Object[] {})
>> } catch (Exception e) {/* ignored exception */ }
>> return (labNetworkMemberList != null &&
>> isInitialized &&
>> !labNetworkMemberList.isEmpty();
>>
>>
>> I could write all the refection into a utility and then build a
>> refactoring tool that inserts a call to that utility into the middle
>> of the if statement for each list on the object, but I'm hoping you
>> guys have a better idea.
I think this is solving the problem in the wrong place. If the list has
contents that are only lazily present, it still has contents and those
contents should be copied or serialized normally. If you don't want
that for some reason, it's best to specialize that locally, not in the
model itself.
>>
>> What we really have is a problem with the meaning of isEmpty(). EMF
>> assumes we mean to ask if the real list has no children. But in the
>> context of a serialization I wan to know if the current copy of the
>> object's list is empty.
Yes, that's what I mean by you having specific needs because generally
is someone is transmitting an object via XML, they'll want all the real
contents, not just what happens to be loaded so far.
>>
>> So what do you guys think of all that? Am I better to refactor all
>> the generated code or should I be trying to augment isEmpty somehow?
>> Or is there some better way to handle this that I haven't found yet?
>> Any suggestions are much appreciated.
Perhaps the simplest way to specialize the code would be to specialize
this method in XMLSaveImpl to ignore certain features you don't want
saved (if it doesn't make sense to mark them as transient, since they
aren't really transient when you save to hibernate):

protected boolean shouldSaveFeature(EObject o, EStructuralFeature f)
{
return o.eIsSet(f) || keepDefaults && f.getDefaultValueLiteral()
!= null;
}

>>
>> Thanks,
>>
>> Jason Henriksen
>>
>>
>>
>>
>>
>>
>
>


--------------030303040403010200030900
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Guys,<br>
<br>
Comments below.<br>
<br>
Martin Taal wrote:
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">Hi
Jason,
<br>
One can debate ofcourse if eIsSet should return false on an
uninitialized but non-empty list.</blockquote>
Sounds odd.&nbsp; EMF doesn't directly support non-empty lists that are not
considered set and hence doesn't support a default value for a
multi-valued feature.&nbsp; It's a little tricky to support something like
this.&nbsp; Consider when you are deserializing and the normal behavior is
just to append to the list as you see elements with values.&nbsp; To support
a list that's pre-populated, you'd have to clear the list first before
adding to it, and you'd have to do that only the first time.&nbsp; You can
imagine that's a bit tricky and somewhat costly to manage doing it only
once.&nbsp; A copier would have similar issues...<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite"> I
think the eIsSet should return true in this case and therefore should
do isEmpty. The reason is that a non-loaded lists is maybe technically
empty but conceptually it is not empty (as the database has the list
content).
<br>
</blockquote>
That makes sense.&nbsp; If it will be non-empty but in a lazy way, it's
still non-empty.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">The
isEmpty call can be made more efficient for non-initialized
collections. But that's a separate discussion.
<br>
</blockquote>
I think that's why lists have isEmpty as well as size even though
size() != 0 implies isEmpty() == false.&nbsp; I.e., you can compute
non-emptiness more efficiently than the size.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite"><br>
Instead of changing eIsSet I would change the serialization code should
so that it does not load uninitialized lists. I am no expert on this
area of EMF but maybe EMF's behavior can be customized in this area.
<br>
</blockquote>
When getting a value in XMLHelperImpl we do indicate that we don't want
proxies to be resolved.&nbsp; <br>
<br>
&nbsp; public Object getValue(EObject obj, EStructuralFeature f)<br>
&nbsp; {<br>
&nbsp;&nbsp;&nbsp; return obj.eGet(f, false);<br>
&nbsp; }<br>
<br>
It seems to me when serializing though, you will need the contents for
the list to serialize the items...&nbsp; I'll read more below...<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite"><br>
As an example the HibernateResource has a nonresolving iterator which
walks passed all objects in a resource without loading non-loaded lists
(so the content of non-loaded lists is not visited).
<br>
</blockquote>
Kind of like InternalEList supports visiting the list without resolving
proxies...<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite"><br>
gr. Martin
<br>
<br>
jason henriksen wrote:
<br>
<blockquote type="cite"><br>
Here's a really fun one for you guys.&nbsp; Sorry to post in both groups,
but I wanted to make sure both Ed and Martin see this.
<br>
</blockquote>
</blockquote>
You miss addressed on the group.&nbsp;&nbsp; :-P&nbsp; Don't worry, I watch many of
the newsgroups and will always see EMFT posts.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
I have an object that I've loaded from the database that has lists of
child object.&nbsp; These lists are lazily loaded.
<br>
<br>
So for example:
<br>
<br>
class Parent{
<br>
&nbsp;&nbsp;&nbsp; List&lt;ChildA&gt; aList;
<br>
&nbsp;&nbsp;&nbsp; List&lt;ChildB&gt; bList;
<br>
}
<br>
<br>
For efficiency, I've loaded aList but left bList uninitialized.&nbsp; I now
want to serialize this object to XML so I can send it in a SOAP
message. &nbsp;I ONLY want to send aList but not send bList.&nbsp; I didn't load
that from the DB so it shouldn't be a problem.
<br>
</blockquote>
</blockquote>
If the bList's feature was transient, then it wouldn't be serialized. <br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
Except that eIsSet() on the list looks like this:
<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; return&nbsp; (labNetworkMemberList != null &amp;&amp;
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; !labNetworkMemberList.isEmpty();
<br>
<br>
and calling labNetworkMemberList.isEmpty() causes the list to be loaded
from the database!!!
<br>
(And if I disconnect the session I get ObjectNotInitialized exceptions)
<br>
</blockquote>
</blockquote>
It really should return true as Martin says if there there are contents
in the actual list.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
Once it's loaded the whole object gets serialized into the XML and the
benefit of lazy loading is lost.
<br>
<br>
It turns out that this is a really common problem using hibernate and
lazy loading with serialization.&nbsp; In fact, by using EMF we're ahead of
the game because we have the eIsSet() methods which we can hack.&nbsp; If we
apply this hack we can get the lazy loading behavior we want:
<br>
<br>
//... from inside of eIsSet ...
<br>
case ModelPackageImpl.LAB__LAB_NETWORK_MEMBER_LIST:
<br>
&nbsp; //--- this list may be initialized by Teneo/Hibernate or maybe not
<br>
&nbsp; //&nbsp;&nbsp;&nbsp; Note that we use reflection because only the server side has
<br>
&nbsp; //&nbsp;&nbsp;&nbsp; Teneo installed.&nbsp; Since these objects are used by the client
<br>
&nbsp; //&nbsp;&nbsp;&nbsp; and by the server we don't know if isInitialized() is present.
<br>
&nbsp; //&nbsp;&nbsp;&nbsp; On the client we ignore the exception and
<br>
&nbsp; //&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs p; defer to the value set in isEmpty()
<br>
&nbsp; //&nbsp;&nbsp;&nbsp; On the server this fails out of the if check BEFORE isEmpty()
<br>
&nbsp; //&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs p; gets called to prevent the list from being loaded.
<br>
&nbsp; boolean isInitialized=true;
<br>
&nbsp; try {
<br>
&nbsp;&nbsp;&nbsp; Class c = contactList.getClass();
<br>
&nbsp;&nbsp;&nbsp; Method m = c.getMethod("isInitialized", new Class[] {})
<br>
&nbsp;&nbsp;&nbsp; isInitialized = m.invoke(contactList, new Object[] {})
<br>
&nbsp; } catch (Exception e) {/* ignored exception */ }
<br>
&nbsp; return&nbsp; (labNetworkMemberList != null &amp;&amp;
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; isInitialized &amp;&amp;
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; !labNetworkMemberList.isEmpty();
<br>
<br>
<br>
I could write all the refection into a utility and then build a
refactoring tool that inserts a call to that utility into the middle of
the if statement for each list on the object, but I'm hoping you guys
have a better idea.
<br>
</blockquote>
</blockquote>
I think this is solving the problem in the wrong place.&nbsp; If the list
has contents that are only lazily present, it still has contents and
those contents should be copied or serialized normally.&nbsp; If you don't
want that for some reason, it's best to specialize that locally, not in
the model itself.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
What we really have is a problem with the meaning of isEmpty().&nbsp; EMF
assumes we mean to ask if the real list has no children.&nbsp; But in the
context of a serialization I wan to know if the current copy of the
object's list is empty.
<br>
</blockquote>
</blockquote>
Yes, that's what I mean by you having specific needs because generally
is someone is transmitting an object via XML, they'll want all the real
contents, not just what happens to be loaded so far.<br>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
So what do you guys think of all that?&nbsp; Am I better to refactor all the
generated code or should I be trying to augment isEmpty somehow?&nbsp; Or is
there some better way to handle this that I haven't found yet?&nbsp; Any
suggestions are much appreciated.
<br>
</blockquote>
</blockquote>
Perhaps the simplest way to specialize the code would be to specialize
this method in XMLSaveImpl to ignore certain features you don't want
saved (if it doesn't make sense to mark them as transient, since they
aren't really transient when you save to hibernate):<br>
<blockquote>&nbsp; protected boolean shouldSaveFeature(EObject o,
EStructuralFeature f)<br>
&nbsp; {<br>
&nbsp;&nbsp;&nbsp; return o.eIsSet(f) || keepDefaults &amp;&amp;
f.getDefaultValueLiteral() != null;<br>
&nbsp; }<br>
</blockquote>
<blockquote cite="mid:fr719a$hl7$1@build.eclipse.org" type="cite">
<blockquote type="cite"><br>
Thanks,
<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Jason Henriksen
<br>
<br>
<br>
<br>
<br>
<br>
<br>
</blockquote>
<br>
<br>
</blockquote>
<br>
</body>
</html>

--------------030303040403010200030900--


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: [Teneo/EMF] Question [message #615857 is a reply to message #114515] Wed, 12 March 2008 20:14 Go to previous message
Jason Henriksen is currently offline Jason HenriksenFriend
Messages: 231
Registered: July 2009
Senior Member
Thanks for the input guys! I agree with your comments that this is
really a serialization problem and should be handled at that point
instead of the eIsSet() method.

In fact, it bring to mind the idea of a view. We have object graphs
that go five and size levels deep and when fully specified the XML can
run into multiple mega-bytes. It might be interesting to annotate
certain xml to appear in one view but not in another view.

Good stuff! Thanks again,

Jason

P.S.: I spoke to my client about potentially making the DDL2XSD
converter open source and he's open to the idea. We'd have to clear it
with the client's legal department and so on but the general sentiment
is that it will eventually happen. I'll let you know as that effort
progresses.
Previous Topic:Disable the schemaExport on the hibernate
Next Topic:Teneo: support for Informix
Goto Forum:
  


Current Time: Wed Apr 24 16:23:53 GMT 2024

Powered by FUDForum. Page generated in 0.03554 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top