Export to GitHub

google-web-toolkit - issue #5952

RequestContext.isChanged implementation


Posted on Jan 28, 2011 by Quick Dog

Found in GWT Release (e.g. 1.5.3, 1.6 RC):

GWT 2.1.1

Encountered on OS / Browser (e.g. WinXP, IE6-7, FF3):

All

Detailed description (please be as specific as possible):

RequestContext.isChanged implementation done in the AbstractRequestContext relies on AutobeanUtils.diff(x,y) to detect if the edited proxies were modified or not.

But this is incorrect in the following example :

1/ Entity A has a collection of entities B (many-to-many relationship). 2/ A view/editor focuses on editing an entity A with a custom widget (derived from ValueListBox) to handle the collection of entities B 2/ An entitiy A is edited with the collection of entities B in the requestContext 3/ If no modifications are done, requestContext.isChanged returns TRUE

=> This is due to AutobeanUtils.diff(x,y) that performs the equality of the 2 collections of entities B on the 'equals' method of the Collection objects.

Proposal : Why dont use something like AutobeanUtils.deepEquals that performs equality of collections based on equality of the elements of the collection ?

Shortest code snippet which demonstrates issue (please indicate where actual result differs from expected result):

Workaround if you have one: I'm looking for it

Links to relevant GWT Developer Forum posts:

Comment #1

Posted on Jan 31, 2011 by Swift Rhino

Im not sure if exactly the same problem.

final DICT_TERMRequest rc = requestFactory.dICT_TERMRequest(); rc.findDICT_TERM("1234")/.with("lAST_MODIFIED_BY_OID")/.to(new Receiver() {

        @Override
        public void onSuccess(DICT_TERMProxy response) {
            rftest.proxy = response;
            System.out.println(rftest.proxy);
        }

}).fire();

final DICT_TERMRequest rc2 = requestFactory.dICT_TERMRequest(); System.out.println("changed before edit start: " + rc2.isChanged()); DICT_TERMProxy edited = rc2.edit(rftest.proxy); System.out.println("changed after edit start: " + rc2.isChanged());

results in:

{CREATED_AT=Mon Sep 20 17:15:19 CEST 2010, TERM_KEY=key1, LAST_MODIFIED_AT=Tue Oct 19 10:26:12 CEST 2010, DICT_DESCRIPTION=v1, Id=1234, Version=11} changed before edit start: false changed after edit start: false

when '.with("lAST_MODIFIED_BY_OID")' uncomented:

{LAST_MODIFIED_BY_OID={USER_ID=root, Id=0, Version=1}, CREATED_AT=Mon Sep 20 17:15:19 CEST 2010, TERM_KEY=key1, LAST_MODIFIED_AT=Tue Oct 19 10:26:12 CEST 2010, DICT_DESCRIPTION=v1, Id=1234, Version=11} changed before edit start: false changed after edit start: true

Comment #2

Posted on Feb 13, 2011 by Swift Rhino

http://gwt-code-reviews.appspot.com/1357805

Comment #3

Posted on Aug 28, 2011 by Helpful Wombat

This issue (i.e. not deep checking) causes a performance problem ...

Consider the case when the client obtains a bunch of data and caches it somewhere. For example, at the start of the application, we obtain an object graph for the currently logged in user. Note that the objects we receive have their request context tag in their bean set to null by request factory.

After some time, in response to user actions, the cached data has to be modified, so we'd call request.edit(cachedData). Now, when we actually fire the request, it will think the entire object graph has changed, and ends up sending everything that we cached.

So, when does request factory actually send diff'd data?

The only workaround we have right now is to fetch a single object using find(..) without its object graph, edit the single object, and send back. However, this means two round trips. If we have multiple requests, we can queue multiple find's in the first request and do a bulk update in the second request, which is still two round trips.

Any suggestions?

Comment #4

Posted on Aug 29, 2011 by Helpful Wombat

Looking for workarounds...

  1. My first workaround was to write a customized RequestContext impl class. This was a little unsuccessful, given I couldn't delegate addInvocation(..) method to a dynamically generated RequestContext class from RF.

  2. Second workaround was to do a little hack before I edit the object: AutoBean bean = AutoBeanUtils.getAutoBean(parentObject); bean.setTag(Constants.REQUEST_CONTEXT, request); request.edit(bean.as());

That tries to take advantage of the weak mapping cache but that doesn't work too, because the parent object's request context is somehow set back to null just before the equals is called on the bean.

Are there any workarounds?

For reference:

http://groups.google.com/group/google-web-toolkit/browse_thread/thread/e752268c76c300fc

http://groups.google.com/group/google-web-toolkit/browse_thread/thread/d34d48adbfbeb21d

http://forum.springsource.org/showthread.php?103653-GWT-issue-with-entity-relationships&s=0cee66dd312522d9052d982a790cbdf5

Comment #5

Posted on Sep 16, 2011 by Grumpy Rhino

Comment deleted

Comment #6

Posted on Sep 16, 2011 by Grumpy Rhino

*Found in GWT Release (e.g. 1.5.3, 1.6 RC): GWT 2.4

*Encountered on OS / Browser (e.g. WinXP, IE6-7, FF3): All

*Detailed description (please be as specific as possible):

Im facing the same issue :( https://groups.google.com/forum/#!topic/google-web-toolkit/zyJ4EVxEwfM

It is one of the key feature of RequestFactory

"keeps track of objects that have been modified and sends only changes to the server, which results in very lightweight network payloads"

Comment #7

Posted on Sep 28, 2011 by Quick Rabbit

The problem with isChanged is that it uses AutoBeanUtils.diff which ends up using EntityProxyCategory.equals which returns its value using: return stableId(bean).equals(stableId(other)) && requestContext(bean) == requestContext(other);

The original object, which is stored under the PARENT_OBJECT tag in the AutoBean does not have a requestContext, so it will fail on the last part.

Comment #8

Posted on Dec 2, 2011 by Swift Rhino

+1 to Kevin's analysis. I don't know what I was thinking about in my proposed patch back in February.

Anyway, I'm working on a real fix for this issue: making equals() evaluate to 'true' when diff'ing a mutable AutoBean and its immutable "parent" (but keep the old behavior otherwise, for backwards compatibility: there must have been a reason for it)

Comment #9

Posted on Dec 4, 2011 by Swift Rhino

New patch sent for review: http://gwt-code-reviews.appspot.com/1601806/

Comment #10

Posted on Dec 22, 2011 by Happy Wombat

+++ Vote +++ Sending only changes to server is a very important feature. Especially it allows a very simple for of optimistic concurrency. Currently we are loosing collection members when adding from two browser sites at the same time. I'll try the patches next year ;-)

Comment #11

Posted on May 31, 2012 by Swift Rhino

Committed at r11004

Comment #12

Posted on May 31, 2012 by Swift Rhino

(No comment was entered for this change.)

Comment #13

Posted on Jun 1, 2012 by Quick Giraffe

Woo! I have clients waiting for this to be fixed :D

Comment #14

Posted on Jun 27, 2012 by Happy Elephant

Bulk edit: should be fixed in the GWT 2.5 release candidate.

Status: Fixed

Labels:
Category-RPC Milestone-2_5