Replaces the public and obnoxious String EntityProxy#getId() with the private ProxyImpl#encodedId(), which is set by th server and opaque to the client. EntityProxyChange is now id based, rather than record based. I tried to make the corresponding fixes to samples/expenses, but it's broken at the moment. (Rather than fixing it to work with String ids, it might be better to expend the same amount of effort making Long ids work again.) EntityProxyId is now parameterized to the type of its EntityProxy, so that the find request doesn't suck. Review at http://gwt-code-reviews.appspot.com/902801 git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8830 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/FavoritesManager.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/FavoritesManager.java index 25936c5..0268fea 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/FavoritesManager.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/FavoritesManager.java
@@ -37,7 +37,7 @@ public class FavoritesManager { private static final String COOKIE_NAME = "Favorites"; private final EventBus eventBus = new SimpleEventBus(); - private final Set<EntityProxyId> favoriteIds = new HashSet<EntityProxyId>(); + private final Set<EntityProxyId<PersonProxy>> favoriteIds = new HashSet<EntityProxyId<PersonProxy>>(); public FavoritesManager(final RequestFactory requestFactory) { String cookie = Cookies.getCookie(COOKIE_NAME); @@ -47,7 +47,8 @@ if (fragment.length() == 0) { continue; } - EntityProxyId id = requestFactory.getProxyId(fragment); + @SuppressWarnings("unchecked") + EntityProxyId<PersonProxy> id = (EntityProxyId<PersonProxy>) requestFactory.getProxyId(fragment); favoriteIds.add(id); } } catch (NumberFormatException e) { @@ -59,7 +60,7 @@ Window.addWindowClosingHandler(new ClosingHandler() { public void onWindowClosing(ClosingEvent event) { StringBuilder sb = new StringBuilder(); - for (EntityProxyId id : favoriteIds) { + for (EntityProxyId<PersonProxy> id : favoriteIds) { sb.append(requestFactory.getHistoryToken(id)).append(","); } Cookies.setCookie(COOKIE_NAME, sb.toString()); @@ -72,7 +73,7 @@ return eventBus.addHandler(MarkFavoriteEvent.TYPE, handler); } - public Set<EntityProxyId> getFavoriteIds() { + public Set<EntityProxyId<PersonProxy>> getFavoriteIds() { return Collections.unmodifiableSet(favoriteIds); }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java index 3b66f5c..ad3e35c 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/PersonEditorWorkflow.java
@@ -98,12 +98,12 @@ } @UiHandler("cancel") - void onCancel(ClickEvent e) { + void onCancel(@SuppressWarnings("unused") ClickEvent e) { dialog.hide(); } @UiHandler("save") - void onSave(ClickEvent e) { + void onSave(@SuppressWarnings("unused") ClickEvent e) { // MOVE TO ACTIVITY END final RequestObject<Void> request = editorDriver.<Void> flush(); if (editorDriver.hasErrors()) { @@ -125,7 +125,7 @@ } @UiHandler("favorite") - void onValueChanged(ValueChangeEvent<Boolean> event) { + void onValueChanged(@SuppressWarnings("unused") ValueChangeEvent<Boolean> event) { manager.setFavorite(person, favorite.getValue()); }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/FavoritesWidget.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/FavoritesWidget.java index 2dcc176..580d410 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/FavoritesWidget.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/FavoritesWidget.java
@@ -21,7 +21,6 @@ import com.google.gwt.event.shared.EventBus; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.requestfactory.client.RequestFactoryEditorDriver; -import com.google.gwt.requestfactory.shared.EntityProxy; import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.Receiver; import com.google.gwt.requestfactory.shared.RequestFactory; @@ -129,11 +128,10 @@ } }); - for (EntityProxyId id : manager.getFavoriteIds()) { - factory.find(id).fire(new Receiver<EntityProxy>() { + for (EntityProxyId<PersonProxy> id : manager.getFavoriteIds()) { + factory.find(id).fire(new Receiver<PersonProxy>() { @Override - public void onSuccess(EntityProxy response) { - PersonProxy person = (PersonProxy) response; + public void onSuccess(PersonProxy person) { onMarkFavorite(new MarkFavoriteEvent(person, true)); } });
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java index eabb21b..2878262 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/client/widgets/SummaryWidget.java
@@ -19,6 +19,7 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.event.shared.EventBus; import com.google.gwt.requestfactory.shared.EntityProxyChange; +import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.Receiver; import com.google.gwt.requestfactory.shared.WriteOperation; import com.google.gwt.resources.client.CssResource; @@ -147,21 +148,21 @@ void onPersonChanged(EntityProxyChange<PersonProxy> event) { if (WriteOperation.UPDATE.equals(event.getWriteOperation())) { - PersonProxy record = event.getProxy(); + EntityProxyId<PersonProxy> personId = event.getProxyId(); // Is the changing record onscreen? - int displayOffset = offsetOf(record); + int displayOffset = offsetOf(personId); if (displayOffset != -1) { // Record is onscreen and may differ from our data - requestFactory.personRequest().findPerson(record.getId()).fire( + requestFactory.find(personId).fire( new Receiver<PersonProxy>() { @Override - public void onSuccess(PersonProxy response) { + public void onSuccess(PersonProxy person) { // Re-check offset in case of changes while waiting for data - int offset = offsetOf(response); + int offset = offsetOf(person.stableId()); if (offset != -1) { table.setRowData(table.getPageStart() + offset, - Collections.singletonList(response)); + Collections.singletonList(person)); } } }); @@ -200,11 +201,10 @@ }); } - private int offsetOf(PersonProxy person) { - String lookFor = person.getId(); + private int offsetOf(EntityProxyId<PersonProxy> personId) { List<PersonProxy> displayedItems = table.getDisplayedItems(); for (int offset = 0, j = displayedItems.size(); offset < j; offset++) { - if (lookFor.equals(displayedItems.get(offset).getId())) { + if (personId.equals(displayedItems.get(offset).stableId())) { return offset; } }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/AddressProxy.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/AddressProxy.java index cdadf82..2e6c53f 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/AddressProxy.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/AddressProxy.java
@@ -16,6 +16,7 @@ package com.google.gwt.sample.dynatablerf.shared; import com.google.gwt.requestfactory.shared.EntityProxy; +import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.ProxyFor; import com.google.gwt.sample.dynatablerf.domain.Address; @@ -26,6 +27,8 @@ public interface AddressProxy extends EntityProxy { String getCity(); + String getId(); + String getState(); String getStreet(); @@ -39,4 +42,6 @@ void setStreet(String street); void setZip(Integer zip); + + EntityProxyId<AddressProxy> stableId(); }
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java index 1000dd5..31413a5 100644 --- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java +++ b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/shared/PersonProxy.java
@@ -16,6 +16,7 @@ package com.google.gwt.sample.dynatablerf.shared; import com.google.gwt.requestfactory.shared.EntityProxy; +import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.ProxyFor; import com.google.gwt.sample.dynatablerf.domain.Person; @@ -24,9 +25,12 @@ */ @ProxyFor(Person.class) public interface PersonProxy extends EntityProxy { + AddressProxy getAddress(); String getDescription(); + + String getId(); String getName(); @@ -39,4 +43,6 @@ void setName(String name); void setNote(String note); + + EntityProxyId<PersonProxy> stableId(); }
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseDetails.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseDetails.java index dd96fd6..51fd6f0 100644 --- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseDetails.java +++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseDetails.java
@@ -41,6 +41,7 @@ import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.requestfactory.shared.EntityProxyChange; +import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.Receiver; import com.google.gwt.requestfactory.shared.RequestObject; import com.google.gwt.resources.client.ImageResource; @@ -509,21 +510,26 @@ } public void onExpenseRecordChanged(EntityProxyChange<ExpenseProxy> event) { - ExpenseProxy newRecord = event.getProxy(); - Object newKey = items.getKey(newRecord); + final EntityProxyId<ExpenseProxy> proxyId = event.getProxyId(); int index = 0; - List<ExpenseProxy> list = items.getList(); + final List<ExpenseProxy> list = items.getList(); for (ExpenseProxy r : list) { - if (items.getKey(r).equals(newKey)) { - list.set(index, newRecord); - - // Update the view data if the approval has been updated. - ApprovalViewData avd = approvalCell.getViewData(newKey); - if (avd != null - && avd.getPendingApproval().equals(newRecord.getApproval())) { - syncCommit(newRecord, null); - } + if (items.getKey(r).equals(proxyId)) { + final int i = index; + expensesRequestFactory.find(proxyId).fire(new Receiver<ExpenseProxy>() { + @Override + public void onSuccess(ExpenseProxy newRecord) { + list.set(i, newRecord); + + // Update the view data if the approval has been updated. + ApprovalViewData avd = approvalCell.getViewData(proxyId); + if (avd != null + && avd.getPendingApproval().equals(newRecord.getApproval())) { + syncCommit(newRecord, null); + } + } + }); } index++; } @@ -535,8 +541,8 @@ } public void onReportChanged(EntityProxyChange<ReportProxy> event) { - ReportProxy changed = event.getProxy(); - if (report != null && report.getId().equals(changed.getId())) { + EntityProxyId<ReportProxy> changed = event.getProxyId(); + if (report != null && report.getId().equals(changed)) { // Request the updated report. expensesRequestFactory.reportRequest().findReport( report.getId()).fire(new Receiver<ReportProxy>() {
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseList.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseList.java index 20da657..02788dc 100644 --- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseList.java +++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseList.java
@@ -35,6 +35,7 @@ import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.requestfactory.shared.EntityProxyChange; +import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.Receiver; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.safehtml.shared.SafeHtmlUtils; @@ -346,14 +347,13 @@ } public void onProxyChange(EntityProxyChange<ReportProxy> event) { - ReportProxy changed = event.getProxy(); - Long changedId = changed.getId(); + EntityProxyId<ReportProxy> changedId = event.getProxyId(); List<ReportProxy> records = table.getDisplayedItems(); int i = 0; for (ReportProxy record : records) { - if (record != null && changedId.equals(record.getId())) { + if (record != null && changedId.equals(record.stableId())) { List<ReportProxy> changedList = new ArrayList<ReportProxy>(); - changedList.add(changed); + changedList.add(record); reports.updateRowData(i + table.getPageStart(), changedList); } i++;
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseDetails.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseDetails.java index 1dce5fe..0442b50 100644 --- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseDetails.java +++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseDetails.java
@@ -21,6 +21,7 @@ import com.google.gwt.event.shared.EventBus; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.requestfactory.shared.EntityProxyChange; +import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.Receiver; import com.google.gwt.sample.expenses.client.request.ExpenseProxy; import com.google.gwt.sample.expenses.client.request.ExpensesRequestFactory; @@ -29,8 +30,6 @@ import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; -import java.util.List; - /** * TODO: doc. */ @@ -65,8 +64,8 @@ new EntityProxyChange.Handler<ExpenseProxy>() { public void onProxyChange(EntityProxyChange<ExpenseProxy> event) { if (expense != null) { - ExpenseProxy newRecord = event.getProxy(); - if (newRecord.getId().equals(expense.getId())) { + EntityProxyId<ExpenseProxy> newRecord = event.getProxyId(); + if (newRecord.equals(expense.getId())) { onRefresh(false); } }
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/EmployeeProxy.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/EmployeeProxy.java index 64e00c1..0728e9d 100644 --- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/EmployeeProxy.java +++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/EmployeeProxy.java
@@ -15,9 +15,9 @@ */ package com.google.gwt.sample.expenses.client.request; -import com.google.gwt.requestfactory.shared.ProxyFor; - import com.google.gwt.requestfactory.shared.EntityProxy; +import com.google.gwt.requestfactory.shared.EntityProxyId; +import com.google.gwt.requestfactory.shared.ProxyFor; /** * "API Generated" DTO interface based on @@ -31,6 +31,8 @@ String getDisplayName(); + Long getId(); + String getPassword(); EmployeeProxy getSupervisor(); @@ -48,4 +50,6 @@ void setSupervisor(EmployeeProxy supervisor); void setUserName(String userName); + + EntityProxyId<EmployeeProxy> stableId(); }
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ExpenseProxy.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ExpenseProxy.java index 4c64694..71a28eb 100644 --- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ExpenseProxy.java +++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ExpenseProxy.java
@@ -16,6 +16,7 @@ package com.google.gwt.sample.expenses.client.request; import com.google.gwt.requestfactory.shared.EntityProxy; +import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.ProxyFor; import java.util.Date; @@ -29,15 +30,17 @@ @ProxyFor(com.google.gwt.sample.expenses.server.domain.Expense.class) public interface ExpenseProxy extends EntityProxy { Double getAmount(); - + String getApproval(); - + String getCategory(); Date getCreated(); String getDescription(); + Long getId(); + String getReasonDenied(); ReportProxy getReport(); @@ -57,4 +60,6 @@ void setReasonDenied(String reasonDenied); void setReport(ReportProxy report); + + EntityProxyId<ExpenseProxy> stableId(); }
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ReportProxy.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ReportProxy.java index d9293bd..aa386f2 100644 --- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ReportProxy.java +++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/request/ReportProxy.java
@@ -15,9 +15,9 @@ */ package com.google.gwt.sample.expenses.client.request; -import com.google.gwt.requestfactory.shared.ProxyFor; - import com.google.gwt.requestfactory.shared.EntityProxy; +import com.google.gwt.requestfactory.shared.EntityProxyId; +import com.google.gwt.requestfactory.shared.ProxyFor; import java.util.Date; @@ -35,6 +35,8 @@ String getDepartment(); + Long getId(); + String getNotes(); String getPurpose(); @@ -54,4 +56,6 @@ void setPurpose(String purpose); void setReporter(EmployeeProxy reporter); + + EntityProxyId<ReportProxy> stableId(); }
diff --git a/user/src/com/google/gwt/app/place/AbstractProxyEditActivity.java b/user/src/com/google/gwt/app/place/AbstractProxyEditActivity.java index af06fae..99d6678 100644 --- a/user/src/com/google/gwt/app/place/AbstractProxyEditActivity.java +++ b/user/src/com/google/gwt/app/place/AbstractProxyEditActivity.java
@@ -55,9 +55,9 @@ private AcceptsOneWidget display; private P record; - private EntityProxyId stableId; + private EntityProxyId<P> stableId; - public AbstractProxyEditActivity(ProxyEditView<P> view, EntityProxyId proxyId, + public AbstractProxyEditActivity(ProxyEditView<P> view, EntityProxyId<P> proxyId, Class<P> proxyType, boolean creating, RequestFactory requests, PlaceController placeController) { @@ -144,11 +144,10 @@ if (creating) { P tempRecord = requests.create(proxyType); - stableId = tempRecord.stableId(); + stableId = cast(tempRecord.stableId()); doStart(display, tempRecord); } else { - @SuppressWarnings("unchecked") - ProxyRequest<P> findRequest = (ProxyRequest<P>) requests.find(stableId); + ProxyRequest<P> findRequest = requests.find(stableId); findRequest.with(getView().getPaths()).fire(new Receiver<P>() { @Override public void onSuccess(P record) { @@ -180,6 +179,11 @@ protected abstract RequestObject<Void> getPersistRequest(P record); + @SuppressWarnings("unchecked") + private EntityProxyId<P> cast(EntityProxyId<?> stableId) { + return (EntityProxyId<P>) stableId; + } + private void doStart(final AcceptsOneWidget display, P record) { requestObject = getPersistRequest(record); P editableRecord = requestObject.edit(record);
diff --git a/user/src/com/google/gwt/app/place/AbstractProxyListActivity.java b/user/src/com/google/gwt/app/place/AbstractProxyListActivity.java index a5f9dd6..08d9488 100644 --- a/user/src/com/google/gwt/app/place/AbstractProxyListActivity.java +++ b/user/src/com/google/gwt/app/place/AbstractProxyListActivity.java
@@ -177,7 +177,7 @@ EntityProxyChange.registerForProxyType(eventBus, proxyType, new EntityProxyChange.Handler<P>() { public void onProxyChange(EntityProxyChange<P> event) { - update(event.getWriteOperation(), event.getProxy()); + update(event.getWriteOperation(), event.getProxyId()); } }); eventBus.addHandler(PlaceChangeEvent.TYPE, new PlaceChangeEvent.Handler() { @@ -190,10 +190,10 @@ updateSelection(placeController.getWhere()); } - public void update(WriteOperation writeOperation, P record) { + public void update(WriteOperation writeOperation, EntityProxyId<P> proxyId) { switch (writeOperation) { case UPDATE: - update(record); + update(proxyId); break; case DELETE: @@ -263,8 +263,8 @@ select((P) ((ProxyPlace) newPlace).getProxyId()); } - private void update(P record) { - final Integer row = recordToRow.get(record.stableId()); + private void update(EntityProxyId<P> proxyId) { + final Integer row = recordToRow.get(proxyId); if (row == null) { return; }
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java b/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java index 0e0a92c..15dc096 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/AbstractRequest.java
@@ -111,46 +111,7 @@ // handle violations JsArray<DeltaValueStoreJsonImpl.ReturnRecord> violationsArray = results.getViolations(); if (violationsArray != null) { - int length = violationsArray.length(); - Set<Violation> errors = new HashSet<Violation>(length); - - for (int i = 0; i < length; i++) { - ReturnRecord violationRecord = violationsArray.get(i); - String id = null; - if (violationRecord.hasFutureId()) { - id = violationRecord.getFutureId(); - } else { - id = violationRecord.getId(); - } - final EntityProxyIdImpl key = new EntityProxyIdImpl(id, - requestFactory.getSchema(violationRecord.getSchema()), - violationRecord.hasFutureId(), null); - assert violationRecord.hasViolations(); - - HashMap<String, String> violations = new HashMap<String, String>(); - violationRecord.fillViolations(violations); - - for (Map.Entry<String, String> entry : violations.entrySet()) { - final String path = entry.getKey(); - final String message = entry.getValue(); - errors.add(new Violation() { - public String getMessage() { - return message; - } - - public String getPath() { - return path; - } - - public EntityProxyId getProxyId() { - return key; - } - }); - } - } - - deltaValueStore.reuse(); - receiver.onViolation(errors); + processViolations(violationsArray); } else { deltaValueStore.commit(results.getSideEffects()); handleResult(results.getResult()); @@ -211,4 +172,48 @@ protected void succeed(T t) { receiver.onSuccess(t); } + + private void processViolations( + JsArray<DeltaValueStoreJsonImpl.ReturnRecord> violationsArray) { + int length = violationsArray.length(); + Set<Violation> errors = new HashSet<Violation>(length); + + for (int i = 0; i < length; i++) { + ReturnRecord violationRecord = violationsArray.get(i); + String id = null; + if (violationRecord.hasFutureId()) { + id = violationRecord.getFutureId(); + } else { + id = violationRecord.getEncodedId(); + } + final EntityProxyIdImpl key = new EntityProxyIdImpl(id, + requestFactory.getSchema(violationRecord.getSchema()), + violationRecord.hasFutureId(), null); + assert violationRecord.hasViolations(); + + HashMap<String, String> violations = new HashMap<String, String>(); + violationRecord.fillViolations(violations); + + for (Map.Entry<String, String> entry : violations.entrySet()) { + final String path = entry.getKey(); + final String message = entry.getValue(); + errors.add(new Violation() { + public String getMessage() { + return message; + } + + public String getPath() { + return path; + } + + public EntityProxyId getProxyId() { + return key; + } + }); + } + } + + deltaValueStore.reuse(); + receiver.onViolation(errors); + } }
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImpl.java index 2766df4..2e72a03 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImpl.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImpl.java
@@ -16,7 +16,6 @@ package com.google.gwt.requestfactory.client.impl; import com.google.gwt.core.client.JavaScriptObject; - import com.google.gwt.core.client.JsArray; import com.google.gwt.requestfactory.shared.EntityProxy; import com.google.gwt.requestfactory.shared.EntityProxyId; @@ -66,15 +65,15 @@ } }-*/; - public final native String getFutureId()/*-{ - return this.futureId; - }-*/; - - public final String getId() { + public final String getEncodedId() { String parts[] = getSchemaAndId().split("-"); return parts[1]; } + public final native String getFutureId()/*-{ + return this.futureId; + }-*/; + public final String getSchema() { String parts[] = getSchemaAndId().split("-"); return parts[0]; @@ -129,14 +128,14 @@ HashSet<String> keys = new HashSet<String>(); ReturnRecord.fillKeys(returnedJso, keys); - Set<EntityProxyId> toRemove = new HashSet<EntityProxyId>(); + Set<EntityProxyId<?>> toRemove = new HashSet<EntityProxyId<?>>(); if (keys.contains(WriteOperation.CREATE.getUnObfuscatedEnumName())) { JsArray<ReturnRecord> newRecords = ReturnRecord.getRecords(returnedJso, WriteOperation.CREATE.getUnObfuscatedEnumName()); int length = newRecords.length(); for (int i = 0; i < length; i++) { ReturnRecord newRecord = newRecords.get(i); - final EntityProxyIdImpl futureKey = new EntityProxyIdImpl( + final EntityProxyIdImpl<?> futureKey = new EntityProxyIdImpl<EntityProxy>( newRecord.getFutureId(), requestFactory.getSchema(newRecord.getSchema()), RequestFactoryJsonImpl.IS_FUTURE, null); @@ -144,9 +143,9 @@ newRecord.getFutureId(), 1, futureKey.schema, requestFactory); toRemove.add(futureKey); - requestFactory.datastoreToFutureMap.put(newRecord.getId(), - futureKey.schema, futureKey.id); - requestFactory.futureToDatastoreMap.put(futureKey.id, newRecord.getId()); + requestFactory.datastoreToFutureMap.put(newRecord.getEncodedId(), + futureKey.schema, futureKey.encodedId); + requestFactory.futureToDatastoreMap.put(futureKey.encodedId, newRecord.getEncodedId()); /* * TODO (amitmanjhi): get all the data from the server. make a copy of @@ -159,7 +158,7 @@ ProxyJsoImpl value = creates.get(futureKey); if (value != null) { copy.merge(value); - copy.set(ProxyImpl.id, newRecord.getId()); + copy.putEncodedId(newRecord.getEncodedId()); } ProxyJsoImpl masterRecord = master.records.get(futureKey); assert masterRecord == null; @@ -176,9 +175,9 @@ for (int i = 0; i < length; i++) { ReturnRecord deletedRecord = deletedRecords.get(i); final EntityProxyIdImpl key = getPersistedProxyId( - deletedRecord.getId(), + deletedRecord.getEncodedId(), requestFactory.getSchema(deletedRecord.getSchema())); - ProxyJsoImpl copy = ProxyJsoImpl.create((String) key.id, 1, key.schema, + ProxyJsoImpl copy = ProxyJsoImpl.create((String) key.encodedId, 1, key.schema, requestFactory); requestFactory.postChangeEvent(copy, WriteOperation.DELETE); master.records.remove(key); @@ -191,9 +190,9 @@ int length = updatedRecords.length(); for (int i = 0; i < length; i++) { ReturnRecord updatedRecord = updatedRecords.get(i); - final EntityProxyIdImpl key = getPersistedProxyId(updatedRecord.getId(), + final EntityProxyIdImpl key = getPersistedProxyId(updatedRecord.getEncodedId(), requestFactory.getSchema(updatedRecord.getSchema())); - ProxyJsoImpl copy = ProxyJsoImpl.create((String) key.id, 1, key.schema, + ProxyJsoImpl copy = ProxyJsoImpl.create((String) key.encodedId, 1, key.schema, requestFactory); requestFactory.postChangeEvent(copy, WriteOperation.UPDATE); ProxyJsoImpl masterRecord = master.records.get(key); @@ -228,7 +227,7 @@ public <V> void set(Property<V> property, EntityProxy record, V value) { assertNotUsedAndCorrectType(record); ProxyImpl recordImpl = (ProxyImpl) record; - EntityProxyId recordKey = recordImpl.stableId(); + EntityProxyId<?> recordKey = recordImpl.stableId(); ProxyJsoImpl rawMasterRecord = master.records.get(recordKey); WriteOperation priorOperation = operations.get(recordKey); @@ -358,11 +357,11 @@ return requestData.toString(); } - private EntityProxyIdImpl getPersistedProxyId(String datastoreId, + private EntityProxyIdImpl getPersistedProxyId(String encodedId, ProxySchema<?> schema) { - return new EntityProxyIdImpl(datastoreId, schema, + return new EntityProxyIdImpl(encodedId, schema, RequestFactoryJsonImpl.NOT_FUTURE, - requestFactory.datastoreToFutureMap.get(datastoreId, schema)); + requestFactory.datastoreToFutureMap.get(encodedId, schema)); } private Map<EntityProxyId, ProxyJsoImpl> getRecordsMap( @@ -409,9 +408,9 @@ return ProxyJsoImpl.emptyCopy(fromRecord.asJso()); } - private void processToRemove(Set<EntityProxyId> toRemove, + private void processToRemove(Set<EntityProxyId<?>> toRemove, WriteOperation writeOperation) { - for (EntityProxyId recordKey : toRemove) { + for (EntityProxyId<?> recordKey : toRemove) { operations.remove(recordKey); if (writeOperation == WriteOperation.CREATE) { creates.remove(recordKey);
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/EntityProxyIdImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/EntityProxyIdImpl.java index c906bc9..fe27403 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/EntityProxyIdImpl.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/EntityProxyIdImpl.java
@@ -15,6 +15,7 @@ */ package com.google.gwt.requestfactory.client.impl; +import com.google.gwt.requestfactory.shared.EntityProxy; import com.google.gwt.requestfactory.shared.EntityProxyId; /** @@ -33,7 +34,7 @@ * the id is the data-store id. The futureId is non-null if the entity was * created on this client. */ -final class EntityProxyIdImpl implements EntityProxyId { +final class EntityProxyIdImpl<P extends EntityProxy> implements EntityProxyId<P> { static final String SEPARATOR = "---"; private static int hashCode(ProxySchema<?> proxySchema, boolean hasFutureId, Object finalId) { @@ -45,20 +46,21 @@ } final ProxySchema<?> schema; - final Object id; + // TODO(rjrjr) These should be strings, but the future map implications are a bit daunting + final Object encodedId; final Object futureId; final boolean isFuture; - protected EntityProxyIdImpl(Object id, ProxySchema<?> schema, + protected EntityProxyIdImpl(Object encodedId, ProxySchema<?> schema, boolean isFuture, Object futureId) { - assert id != null; + assert encodedId != null; assert schema != null; if (isFuture) { assert futureId == null; } - this.id = id; + this.encodedId = encodedId; this.schema = schema; this.isFuture = isFuture; this.futureId = futureId; @@ -68,7 +70,7 @@ if (isFuture) { throw new IllegalStateException("Need to persist this proxy first"); } - return id + SEPARATOR + schema.getToken(); + return encodedId + SEPARATOR + schema.getToken(); } @Override @@ -82,18 +84,19 @@ if (getClass() != obj.getClass()) { return false; } - EntityProxyIdImpl other = (EntityProxyIdImpl) obj; + @SuppressWarnings("unchecked") + EntityProxyIdImpl<P> other = (EntityProxyIdImpl<P>) obj; if (!schema.equals(other.schema)) { return false; } - if (isFuture == other.isFuture && id.equals(other.id)) { + if (isFuture == other.isFuture && encodedId.equals(other.encodedId)) { return true; } // one of the isFuture is false. check its futureId - if (!isFuture && other.id.equals(futureId)) { + if (!isFuture && other.encodedId.equals(futureId)) { return true; } - if (!other.isFuture && id.equals(other.futureId)) { + if (!other.isFuture && encodedId.equals(other.futureId)) { return true; } return false; @@ -106,16 +109,16 @@ public int hashCode() { if (futureId == null && !isFuture) { // does not have a futureId. - return hashCode(schema, false, id); + return hashCode(schema, false, encodedId); } // has futureId - return hashCode(schema, true, isFuture ? id : futureId); + return hashCode(schema, true, isFuture ? encodedId : futureId); } @Override public String toString() { - return "[EntityProxyId schema: " + schema.getClass().getName() + " id: " + id - + " isFuture: " + (isFuture ? "true" : "false") - + (futureId != null ? ("futureId : " + futureId) : "") + "]"; + return "[EntityProxyId schema: " + schema.getClass().getName() + " id: " + + encodedId + " isFuture: " + (isFuture ? "true" : "false") + + " futureId: " + futureId + "]"; } }
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java index 30624b2..fe3aaad 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/ProxyImpl.java
@@ -35,7 +35,6 @@ */ public class ProxyImpl implements EntityProxy { - static final Property<String> id = new Property<String>("id", String.class); static final Property<Integer> version = new Property<Integer>("version", Integer.class); protected static String getWireFormatId(String id, boolean isFuture, @@ -70,6 +69,10 @@ return jso; } + public String encodedId() { + return jso.encodedId(); + } + /** * Get this proxy's value for the given property. Behavior is undefined if * the proxy has no such property, or if the property has never been set. It @@ -84,15 +87,11 @@ // javac 1.6.0_20 on mac has problems without the explicit parameterization return jso.<V> get(property); } - + public <V> V get(String propertyName, Class<?> propertyType) { // javac 1.6.0_20 on mac has problems without the explicit parameterization return jso.<V> get(propertyName, propertyType); } - - public String getId() { - return jso.getId(); - } public ProxySchema<?> getSchema() { return jso.getSchema(); @@ -103,7 +102,7 @@ } public String getWireFormatId() { - return getWireFormatId(jso.getId(), isFuture, jso.getSchema()); + return getWireFormatId(jso.encodedId(), isFuture, jso.getSchema()); } public boolean isChanged() { @@ -125,15 +124,17 @@ deltaValueStore.set(property, record, value); } + // Allow the generated subclass to return the specific type its public interface probably demands + @SuppressWarnings({"unchecked", "rawtypes"}) public EntityProxyId stableId() { if (!isFuture) { - return new EntityProxyIdImpl( - getId(), + return new EntityProxyIdImpl<ProxyImpl>( + encodedId(), getSchema(), false, - jso.getRequestFactory().datastoreToFutureMap.get(getId(), getSchema())); + jso.getRequestFactory().datastoreToFutureMap.get(encodedId(), getSchema())); } - return new EntityProxyIdImpl(getId(), getSchema(), isFuture, null); + return new EntityProxyIdImpl(encodedId(), getSchema(), isFuture, null); } protected ValueStoreJsonImpl getValueStore() {
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ProxyJsoImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/ProxyJsoImpl.java index 5f04d63..1b81e7e 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/ProxyJsoImpl.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/ProxyJsoImpl.java
@@ -42,43 +42,37 @@ ProxySchema<?> schema, RequestFactoryJsonImpl requestFactory) { ProxyJsoImpl rtn = rawJsoWithIdAndVersion.cast(); - assert rtn.getId() != null; - assert rtn.getVersion() != null; - rtn.setSchema(schema); rtn.setRequestFactory(requestFactory); + rtn.assertValid(); return rtn; }; - public static JsArray<ProxyJsoImpl> create( - JsArray<JavaScriptObject> rawJsos, ProxySchema<?> schema, - RequestFactoryJsonImpl requestFactory) { - + public static JsArray<ProxyJsoImpl> create(JsArray<JavaScriptObject> rawJsos, + ProxySchema<?> schema, RequestFactoryJsonImpl requestFactory) { + for (int i = 0; i < rawJsos.length(); i++) { ProxyJsoImpl.create(rawJsos.get(i), schema, requestFactory); } - + return rawJsos.cast(); } - public static ProxyJsoImpl create(String id, Integer version, + public static ProxyJsoImpl create(String encodedId, Integer version, ProxySchema<?> schema, RequestFactoryJsonImpl requestFactory) { ProxyJsoImpl rtn = createEmpty(); - rtn.set(ProxyImpl.id, id); - rtn.set(ProxyImpl.version, version); + rtn.putEncodedId(encodedId); + rtn.putVersion(version); return create(rtn, schema, requestFactory); } public static ProxyJsoImpl emptyCopy(ProxyJsoImpl jso) { - String tempId = jso.get(ProxyImpl.id); - Integer tempVersion = jso.get(ProxyImpl.version); ProxySchema<?> schema = jso.getSchema(); - - ProxyJsoImpl copy = create(tempId, tempVersion, schema, jso.getRequestFactory()); - return copy; + return create(jso.encodedId(), jso.getVersion(), schema, + jso.getRequestFactory()); } - /** + /** * Create an empty JSO, unsafe to return. */ private static native ProxyJsoImpl createEmpty() /*-{ @@ -88,31 +82,45 @@ protected ProxyJsoImpl() { } + public final void assertValid() { + assert encodedId() != null : "encodedId required"; + assert getRequestFactory() != null : "requestFactory required"; + assert getVersion() != null : "version required"; + assert getSchema() != null : "schema required"; + } + public final native void delete(String name)/*-{ delete this[name]; }-*/; + public final native String encodedId() /*-{ + return this[@com.google.gwt.requestfactory.shared.impl.RequestData::ENCODED_ID_PROPERTY]; + }-*/; + public final <V> V get(Property<V> property) { String name = property.getName(); Class<V> type = property.getType(); - + // javac 1.6.0_20 on mac has problems without the explicit parameterization return this.<V> get(name, type); } + public final native <T> T get(String propertyName) /*-{ + return this[propertyName] || null; + }-*/; + @SuppressWarnings("unchecked") public final <V> V get(String name, Class<?> type) { if (isNullOrUndefined(name)) { return null; } - + try { if (Boolean.class.equals(type)) { return (V) Boolean.valueOf(getBoolean(name)); } if (Character.class.equals(type)) { - return (V) Character.valueOf(String.valueOf(get(name)).charAt( - 0)); + return (V) Character.valueOf(String.valueOf(get(name)).charAt(0)); } if (Byte.class.equals(type)) { return (V) Byte.valueOf((byte) getInt(name)); @@ -154,9 +162,8 @@ } } } catch (final Exception ex) { - throw new IllegalStateException("Property " + name - + " has invalid " + " value " + get(name) - + " for type " + type); + throw new IllegalStateException("Property " + name + " has invalid " + + " value " + get(name) + " for type " + type); } if (type.isEnum()) { @@ -185,19 +192,11 @@ String schemaAndId[] = relatedId.split("-"); assert schemaAndId.length == 2; ProxySchema<?> schema = getRequestFactory().getSchema(schemaAndId[0]); - return (V) getRequestFactory().getValueStore().getRecordBySchemaAndId(schema, - schemaAndId[1], getRequestFactory()); + return (V) getRequestFactory().getValueStore().getRecordBySchemaAndId( + schema, schemaAndId[1], getRequestFactory()); } } - public final native <T> T get(String propertyName) /*-{ - return this[propertyName] || null; - }-*/; - - public final String getId() { - return this.get(ProxyImpl.id); - } - public final native RequestFactoryJsonImpl getRequestFactory() /*-{ return this['__rf']; }-*/; @@ -205,7 +204,7 @@ public final native ProxySchema<?> getSchema() /*-{ return this['__key']; }-*/; - + public final Integer getVersion() { return this.get(ProxyImpl.version); } @@ -219,8 +218,7 @@ public final boolean isEmpty() { for (Property<?> property : getSchema().allProperties()) { - if ((property != ProxyImpl.id) && (property != ProxyImpl.version) - && (isDefined(property.getName()))) { + if ((property != ProxyImpl.version) && (isDefined(property.getName()))) { return false; } } @@ -303,7 +301,7 @@ + value.getClass().getName()); } - public final EntityProxyId stableId() { + public final EntityProxyId<?> stableId() { throw new IllegalArgumentException("Can't call stableId on the jso"); } @@ -353,6 +351,10 @@ return false; } + final native void putEncodedId(String id) /*-{ + this[@com.google.gwt.requestfactory.shared.impl.RequestData::ENCODED_ID_PROPERTY] = id; + }-*/; + private native boolean copyPropertyIfDifferent(String name, ProxyJsoImpl from) /*-{ if (this[name] == from[name]) { return false; @@ -384,6 +386,13 @@ return true; }-*/; + /** + * @param version + */ + private void putVersion(Integer version) { + set(ProxyImpl.version, version); + } + private native void setBoolean(String name, boolean value) /*-{ this[name] = value; }-*/; @@ -400,8 +409,7 @@ this[name] = null; }-*/; - private native void setRequestFactory( - RequestFactoryJsonImpl requestFactory) /*-{ + private native void setRequestFactory(RequestFactoryJsonImpl requestFactory) /*-{ this['__rf'] = requestFactory; }-*/;
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ProxySchema.java b/user/src/com/google/gwt/requestfactory/client/impl/ProxySchema.java index 27f812f..ee5db74 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/ProxySchema.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/ProxySchema.java
@@ -47,7 +47,6 @@ { Set<Property<?>> set = new HashSet<Property<?>>(); - set.add(ProxyImpl.id); set.add(ProxyImpl.version); allProperties = Collections.unmodifiableSet(set); }
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryEditorDelegate.java b/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryEditorDelegate.java index eb59dad..b7a5741 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryEditorDelegate.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryEditorDelegate.java
@@ -46,15 +46,21 @@ public void onProxyChange(EntityProxyChange<EntityProxy> event) { if (event.getWriteOperation().equals(WriteOperation.UPDATE) - && event.getProxy().stableId().equals( + && event.getProxyId().equals( ((EntityProxy) getObject()).stableId())) { List<String> paths = new ArrayList<String>(); traverse(paths); - EntityProxyId id = event.getProxy().stableId(); - factory.find(id).with(paths.toArray(new String[paths.size()])).fire( - new SubscriptionReceiver()); + @SuppressWarnings("rawtypes") + EntityProxyId id = event.getProxyId(); + doFind(paths, id); } } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private void doFind(List<String> paths, EntityProxyId id) { + factory.find(id).with(paths.toArray(new String[paths.size()])).fire( + new SubscriptionReceiver()); + } } private class SubscriptionReceiver extends Receiver<EntityProxy> {
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java index 72c66a8..4e542a9 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/RequestFactoryJsonImpl.java
@@ -139,7 +139,7 @@ public String getWireFormat(EntityProxyId proxyId) { EntityProxyIdImpl proxyIdImpl = (EntityProxyIdImpl) proxyId; - String id = (String) proxyIdImpl.id; + String id = (String) proxyIdImpl.encodedId; if (proxyIdImpl.isFuture) { // search for the datastore id for this futureId. String datastoreId = (String) futureToDatastoreMap.get(id); @@ -179,9 +179,9 @@ EntityProxyIdImpl entityProxyId = (EntityProxyIdImpl) proxyId; Class<? extends EntityProxy> proxyClass = entityProxyId.schema.getProxyClass(); String rtn = recordToTypeMap.getClassToken(proxyClass) + "-"; - Object datastoreId = entityProxyId.id; + Object datastoreId = entityProxyId.encodedId; if (entityProxyId.isFuture) { - datastoreId = futureToDatastoreMap.get(entityProxyId.id); + datastoreId = futureToDatastoreMap.get(entityProxyId.encodedId); } if (datastoreId == null) { rtn += "0-FUTURE";
diff --git a/user/src/com/google/gwt/requestfactory/client/impl/ValueStoreJsonImpl.java b/user/src/com/google/gwt/requestfactory/client/impl/ValueStoreJsonImpl.java index 0d7e8b5..07fe41b 100644 --- a/user/src/com/google/gwt/requestfactory/client/impl/ValueStoreJsonImpl.java +++ b/user/src/com/google/gwt/requestfactory/client/impl/ValueStoreJsonImpl.java
@@ -34,14 +34,14 @@ final Map<EntityProxyIdImpl, ProxyJsoImpl> records = new HashMap<EntityProxyIdImpl, ProxyJsoImpl>(); - EntityProxy getRecordBySchemaAndId(ProxySchema<?> schema, String id, + EntityProxy getRecordBySchemaAndId(ProxySchema<?> schema, String encodedId, RequestFactoryJsonImpl requestFactory) { - if (id == null) { + if (encodedId == null) { return null; } // TODO: pass isFuture to this method from decoding ID string - EntityProxyIdImpl key = new EntityProxyIdImpl(id, schema, false, - requestFactory.datastoreToFutureMap.get(id, schema)); + EntityProxyIdImpl key = new EntityProxyIdImpl(encodedId, schema, false, + requestFactory.datastoreToFutureMap.get(encodedId, schema)); return schema.create(records.get(key)); } @@ -54,14 +54,15 @@ * package-protected for testing purposes. */ ProxyJsoImpl putInValueStore(ProxyJsoImpl newJsoRecord) { - EntityProxyIdImpl recordKey = new EntityProxyIdImpl(newJsoRecord.getId(), + EntityProxyIdImpl recordKey = new EntityProxyIdImpl(newJsoRecord.encodedId(), newJsoRecord.getSchema(), RequestFactoryJsonImpl.NOT_FUTURE, newJsoRecord.getRequestFactory().datastoreToFutureMap.get( - newJsoRecord.getId(), newJsoRecord.getSchema())); + newJsoRecord.encodedId(), newJsoRecord.getSchema())); ProxyJsoImpl oldRecord = records.get(recordKey); if (oldRecord == null) { records.put(recordKey, newJsoRecord); + newJsoRecord.assertValid(); newJsoRecord.getRequestFactory().postChangeEvent(newJsoRecord, WriteOperation.ACQUIRE); return null;
diff --git a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java index df25894..04e9ace 100644 --- a/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java +++ b/user/src/com/google/gwt/requestfactory/server/JsonRequestProcessor.java
@@ -21,7 +21,7 @@ import com.google.gwt.requestfactory.shared.ServerFailure; import com.google.gwt.requestfactory.shared.WriteOperation; import com.google.gwt.requestfactory.shared.impl.Property; -import com.google.gwt.requestfactory.shared.impl.RequestData; +import static com.google.gwt.requestfactory.shared.impl.RequestData.*; import org.json.JSONArray; import org.json.JSONException; @@ -80,17 +80,31 @@ } } - private static class EntityKey { - private final boolean isFuture; - // TODO: update for non-String id? - private final String id; - private final Class<? extends EntityProxy> record; + private class EntityKey { + final boolean isFuture; + final String encodedId; + final Class<? extends EntityProxy> proxyType; - EntityKey(String id, boolean isFuture, Class<? extends EntityProxy> record) { - this.id = id; + EntityKey(String id, boolean isFuture, + Class<? extends EntityProxy> proxyType) { + this.encodedId = id; this.isFuture = isFuture; - assert record != null; - this.record = record; + assert proxyType != null; + this.proxyType = proxyType; + } + + public Object decodedId(Class<?> entityIdType) throws SecurityException, + JSONException, IllegalAccessException, InvocationTargetException, + NoSuchMethodException, InstantiationException { + if (isFuture) { + return encodedId; + } + + if (String.class.isAssignableFrom(entityIdType)) { + return encodedId.substring(FAKE_ENCODED.length()); + } + + return decodeParameterValue(entityIdType, encodedId); } @Override @@ -99,14 +113,15 @@ return false; } EntityKey other = (EntityKey) ob; - return (id.equals(other.id)) && (isFuture == other.isFuture) - && (record.equals(other.record)); + return (encodedId.equals(other.encodedId)) + && (isFuture == other.isFuture) + && (proxyType.equals(other.proxyType)); } @Override public int hashCode() { - return 31 * this.record.hashCode() + (31 * this.id.hashCode() - + (isFuture ? 1 : 0)); + return 31 * this.proxyType.hashCode() + + (31 * this.encodedId.hashCode() + (isFuture ? 1 : 0)); } } @@ -122,10 +137,29 @@ } } + private static final String FAKE_ENCODED = "encoded*"; + public static final String RELATED = "related"; private static final Logger log = Logger.getLogger(JsonRequestProcessor.class.getName()); + @SuppressWarnings("unchecked") + public static Class<EntityProxy> getRecordFromClassToken(String recordToken) { + try { + // TODO(rjrjr) Should be getting class loader from servlet environment? + Class<?> clazz = Class.forName(recordToken, false, + JsonRequestProcessor.class.getClassLoader()); + if (EntityProxy.class.isAssignableFrom(clazz)) { + return (Class<EntityProxy>) clazz; + } + throw new SecurityException("Attempt to access non-record class " + + recordToken); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Non-existent record class " + + recordToken); + } + } + private RequestProperty propertyRefs; private final Map<String, JSONObject> relatedObjects = new HashMap<String, JSONObject>(); @@ -133,7 +167,6 @@ private OperationRegistry operationRegistry; private ExceptionHandler exceptionHandler; - /* * <li>Request comes in. Construct the involvedKeys, dvsDataMap and * beforeDataMap, using DVS and parameters. @@ -148,26 +181,28 @@ private final Set<EntityKey> involvedKeys = new HashSet<EntityKey>(); private final Map<EntityKey, DvsData> dvsDataMap = new HashMap<EntityKey, DvsData>(); private final Map<EntityKey, SerializedEntity> beforeDataMap = new HashMap<EntityKey, SerializedEntity>(); + private Map<EntityKey, EntityData> afterDvsDataMap = new HashMap<EntityKey, EntityData>(); @SuppressWarnings({"unchecked", "rawtypes"}) public Collection<Property<?>> allProperties( Class<? extends EntityProxy> clazz) throws IllegalArgumentException { Set<Property<?>> rtn = new HashSet<Property<?>>(); - Map<String, Class<?>> propertiesFromRecord = getPropertiesFromRecord(clazz); + Map<String, Class<?>> propertiesFromRecord = getPropertiesFromRecordProxyType(clazz); for (Entry<String, Class<?>> property : propertiesFromRecord.entrySet()) { rtn.add(new Property(property.getKey(), property.getValue())); } return rtn; } - public String decodeAndInvokeRequest(String encodedRequest) throws RequestProcessingException { + public String decodeAndInvokeRequest(String encodedRequest) + throws RequestProcessingException { try { - Logger.getLogger(this.getClass().getName()).finest("Incoming request " - + encodedRequest); + Logger.getLogger(this.getClass().getName()).finest( + "Incoming request " + encodedRequest); String response = processJsonRequest(encodedRequest).toString(); - Logger.getLogger(this.getClass().getName()).finest("Outgoing response " - + response); + Logger.getLogger(this.getClass().getName()).finest( + "Outgoing response " + response); return response; } catch (InvocationTargetException e) { JSONObject exceptionResponse = buildExceptionResponse(e.getCause()); @@ -182,19 +217,12 @@ /** * Encodes parameter value. - * @throws InstantiationException - * @throws NoSuchMethodException - * @throws InvocationTargetException - * @throws IllegalAccessException - * @throws JSONException - * @throws SecurityException - * @throws NullPointerException */ public Object decodeParameterValue(Type genericParameterType, String parameterValue) throws SecurityException, JSONException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException { - Class<?>parameterType = null; + Class<?> parameterType = null; if (genericParameterType instanceof Class<?>) { parameterType = (Class<?>) genericParameterType; } @@ -257,7 +285,8 @@ return new Date(Long.parseLong(parameterValue)); } if (EntityProxy.class.isAssignableFrom(parameterType)) { - /* TODO: 1. Don't resolve in this step, just get EntityKey. May need to + /* + * TODO: 1. Don't resolve in this step, just get EntityKey. May need to * use DVS. * * 2. Merge the following and the object resolution code in getEntityKey. @@ -265,38 +294,31 @@ */ ProxyFor service = parameterType.getAnnotation(ProxyFor.class); if (service != null) { - Class<?> sClass = service.value(); EntityKey entityKey = getEntityKey(parameterValue.toString()); DvsData dvsData = dvsDataMap.get(entityKey); - if (dvsData != null) { - EntityData entityData = getEntityDataForRecord(entityKey, - dvsData.jsonObject, dvsData.writeOperation); - return entityData.entityInstance; - } else { - involvedKeys.add(entityKey); - Method findMeth = sClass.getMethod( - getMethodNameFromPropertyName(sClass.getSimpleName(), "find"), - String.class); - return findMeth.invoke(null, entityKey.id); - } + if (dvsData != null) { + EntityData entityData = getEntityDataForRecordWithSettersApplied( + entityKey, dvsData.jsonObject, dvsData.writeOperation); + return entityData.entityInstance; + } else { + involvedKeys.add(entityKey); + return getEntityInstance(entityKey); + } } } if (EntityProxyId.class.isAssignableFrom(parameterType)) { EntityKey entityKey = getEntityKey(parameterValue.toString()); - ProxyFor service = entityKey.record.getAnnotation(ProxyFor.class); + ProxyFor service = entityKey.proxyType.getAnnotation(ProxyFor.class); if (service == null) { - throw new IllegalArgumentException("Unknown service, unable to decode " + parameterValue); + throw new IllegalArgumentException("Unknown service, unable to decode " + + parameterValue); } involvedKeys.add(entityKey); - Class<?> sClass = service.value(); - Method findMeth = sClass.getMethod( - getMethodNameFromPropertyName(sClass.getSimpleName(), "find"), - String.class); - return findMeth.invoke(null, entityKey.id); + return getEntityInstance(entityKey); } - throw new IllegalArgumentException( - "Unknown parameter type: " + parameterType); + throw new IllegalArgumentException("Unknown parameter type: " + + parameterType); } public Object encodePropertyValue(Object value) { @@ -328,22 +350,21 @@ * is sent into the response. */ public Object encodePropertyValueFromDataStore(Object entityElement, - Class<?> propertyType, String propertyName, - RequestProperty propertyContext) - throws SecurityException, NoSuchMethodException, IllegalAccessException, - InvocationTargetException, JSONException { + Class<?> proxyPropertyType, String propertyName, + RequestProperty propertyContext) throws SecurityException, + NoSuchMethodException, IllegalAccessException, InvocationTargetException, + JSONException { String methodName = getMethodNameFromPropertyName(propertyName, "get"); Method method = entityElement.getClass().getMethod(methodName); Object returnValue = method.invoke(entityElement); - if (returnValue != null && EntityProxy.class.isAssignableFrom(propertyType)) { - Method idMethod = returnValue.getClass().getMethod("getId"); - String id = (String) idMethod.invoke(returnValue); + String encodedEntityId = isEntityReference(returnValue, proxyPropertyType); + if (encodedEntityId != null) { String keyRef = operationRegistry.getSecurityProvider().encodeClassType( - propertyType) - + "-" + id; - addRelatedObject(keyRef, returnValue, - castToRecordClass(propertyType), + proxyPropertyType) + + "-" + encodedEntityId; + addRelatedObject(keyRef, returnValue, + castToRecordClass(proxyPropertyType), propertyContext.getProperty(propertyName)); // replace value with id reference return keyRef; @@ -359,65 +380,69 @@ * @return the ID of the new record, or null to auto generate */ public String generateIdForCreate(@SuppressWarnings("unused") String key) { - // ignored. id is assigned by default. + // TODO(rjrjr) is there any point to this method if a service layer + // is coming? return null; } /** - * Returns the entityData for a record in the DeltaValueStore. + * Find the entity in the server data store, apply its setters, capture any + * violations, and return an {@link EntityData} encapsulating the results. * <p> - * A <i>set</i> might have side-effects, but we don't handle that. - * @throws JSONException - * @throws NoSuchMethodException - * @throws InvocationTargetException - * @throws IllegalAccessException - * @throws SecurityException - * @throws InstantiationException + * If a <i>set</i> method has side-effects, we will not notice. */ - public EntityData getEntityDataForRecord(EntityKey entityKey, - JSONObject recordObject, WriteOperation writeOperation) throws JSONException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException { + public EntityData getEntityDataForRecordWithSettersApplied( + EntityKey entityKey, JSONObject recordObject, + WriteOperation writeOperation) throws JSONException, SecurityException, + IllegalAccessException, InvocationTargetException, NoSuchMethodException, + InstantiationException { - Class<?> entity = getEntityFromRecordAnnotation(entityKey.record); + Class<?> entityType = getEntityTypeForProxyType(entityKey.proxyType); - Map<String, Class<?>> propertiesInRecord = getPropertiesFromRecord(entityKey.record); - Map<String, Class<?>> propertiesToDTO = new HashMap<String, Class<?>>(propertiesInRecord); - validateKeys(recordObject, propertiesInRecord.keySet()); - updatePropertyTypes(propertiesInRecord, entity); + Map<String, Class<?>> entityPropTypes = getPropertiesFromRecordProxyType(entityKey.proxyType); + Map<String, Class<?>> proxyPropTypes = new HashMap<String, Class<?>>( + entityPropTypes); + validateKeys(recordObject, entityPropTypes.keySet()); + updatePropertyTypes(entityPropTypes, entityType); - // get entityInstance - Object entityInstance = getEntityInstance(writeOperation, entity, - recordObject.get("id"), propertiesInRecord.get("id")); + Object entityInstance = getEntityInstance(writeOperation, entityType, + entityKey.decodedId(entityPropTypes.get(ENTITY_ID_PROPERTY)), + entityPropTypes.get(ENTITY_ID_PROPERTY)); - cachedEntityLookup.put(entityKey, entityInstance); + cachedEntityLookup.put(entityKey, entityInstance); - Iterator<?> keys = recordObject.keys(); - while (keys.hasNext()) { - String key = (String) keys.next(); - Class<?> propertyType = propertiesInRecord.get(key); - Class<?> dtoType = propertiesToDTO.get(key); - if (writeOperation == WriteOperation.CREATE && ("id".equals(key))) { - String id = generateIdForCreate(key); - if (id != null) { - entity.getMethod(getMethodNameFromPropertyName(key, "set"), - propertyType).invoke(entityInstance, id); - } - } else { - Object propertyValue = null; - if (!recordObject.isNull(key) && EntityProxy.class.isAssignableFrom(dtoType)) { - EntityKey propKey = getEntityKey(recordObject.getString(key)); - Object cacheValue = cachedEntityLookup.get(propKey); - if (cachedEntityLookup.containsKey(propKey)) { - propertyValue = cacheValue; - } else { - propertyValue = getPropertyValueFromRequest(recordObject, key, - propertiesToDTO.get(key)); - } + Iterator<?> keys = recordObject.keys(); + while (keys.hasNext()) { + String key = (String) keys.next(); + Class<?> propertyType = entityPropTypes.get(key); + Class<?> dtoType = proxyPropTypes.get(key); + if (writeOperation == WriteOperation.CREATE + && (ENTITY_ID_PROPERTY.equals(key))) { + String id = generateIdForCreate(key); + if (id != null) { + // TODO(rjrjr) generateIdForCreate returns null. Has this ever + // executed? + entityType.getMethod(getMethodNameFromPropertyName(key, "set"), + propertyType).invoke(entityInstance, id); + } + } else { + Object propertyValue = null; + if (!recordObject.isNull(key) + && EntityProxy.class.isAssignableFrom(dtoType)) { + EntityKey propKey = getEntityKey(recordObject.getString(key)); + Object cacheValue = cachedEntityLookup.get(propKey); + if (cachedEntityLookup.containsKey(propKey)) { + propertyValue = cacheValue; } else { propertyValue = getPropertyValueFromRequest(recordObject, key, - propertiesToDTO.get(key)); + proxyPropTypes.get(key)); } - entity.getMethod(getMethodNameFromPropertyName(key, "set"), - propertyType).invoke(entityInstance, propertyValue); + } else { + propertyValue = getPropertyValueFromRequest(recordObject, key, + proxyPropTypes.get(key)); + } + entityType.getMethod(getMethodNameFromPropertyName(key, "set"), + propertyType).invoke(entityInstance, propertyValue); } } @@ -444,9 +469,34 @@ return new EntityData(entityInstance, (violations.isEmpty() ? null : getViolationsAsJson(violations))); } + + public Object getEntityInstance(EntityKey entityKey) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException, JSONException, InstantiationException { + Class<?> entityClass = getEntityTypeForProxyType(entityKey.proxyType); + Class<?> idType = getIdMethodForEntity(entityClass).getReturnType(); + Object entityInstance = entityClass.getMethod( + "find" + entityClass.getSimpleName(), idType).invoke(null, + entityKey.decodedId(idType)); + return entityInstance; + } + + public Object getEntityInstance(WriteOperation writeOperation, + Class<?> entityType, Object idValue, Class<?> idType) + throws SecurityException, InstantiationException, IllegalAccessException, + InvocationTargetException, NoSuchMethodException, + IllegalArgumentException, JSONException { + + if (writeOperation == WriteOperation.CREATE) { + return entityType.getConstructor().newInstance(); + } + // TODO: check "version" validity. + return entityType.getMethod("find" + entityType.getSimpleName(), idType).invoke( + null, decodeParameterValue(idType, idValue.toString())); + } @SuppressWarnings("unchecked") - public Class<Object> getEntityFromRecordAnnotation( + public Class<Object> getEntityTypeForProxyType( Class<? extends EntityProxy> record) { ProxyFor dtoAnn = record.getAnnotation(ProxyFor.class); if (dtoAnn != null) { @@ -456,19 +506,6 @@ + " missing DataTransferObject annotation"); } - public Object getEntityInstance(WriteOperation writeOperation, - Class<?> entity, Object idValue, Class<?> idType) - throws SecurityException, InstantiationException, IllegalAccessException, - InvocationTargetException, NoSuchMethodException, IllegalArgumentException, JSONException { - - if (writeOperation == WriteOperation.CREATE) { - return entity.getConstructor().newInstance(); - } - // TODO: check "version" validity. - return entity.getMethod("find" + entity.getSimpleName(), - idType).invoke(null, decodeParameterValue(idType, idValue.toString())); - } - /** * Converts the returnValue of a 'get' method to a JSONArray. * @@ -494,16 +531,21 @@ } public JSONObject getJsonObject(Object entityElement, - Class<? extends EntityProxy> entityKeyClass, RequestProperty propertyContext) - throws JSONException, NoSuchMethodException, IllegalAccessException, - InvocationTargetException { + Class<? extends EntityProxy> entityKeyClass, + RequestProperty propertyContext) throws JSONException, + NoSuchMethodException, IllegalAccessException, InvocationTargetException { JSONObject jsonObject = new JSONObject(); - for (Property<?> p : allProperties(entityKeyClass)) { + jsonObject.put(ENCODED_ID_PROPERTY, + isEntityReference(entityElement, entityKeyClass)); + + for (Property<?> p : allProperties(entityKeyClass)) { if (requestedProperty(p, propertyContext)) { String propertyName = p.getName(); - jsonObject.put(propertyName, encodePropertyValueFromDataStore( - entityElement, p.getType(), propertyName, propertyContext)); + jsonObject.put( + propertyName, + encodePropertyValueFromDataStore(entityElement, p.getType(), + propertyName, propertyContext)); } } return jsonObject; @@ -516,8 +558,7 @@ * Example: "userName" returns prefix + "UserName". "version" returns prefix + * "Version" */ - public String getMethodNameFromPropertyName(String propertyName, - String prefix) { + public String getMethodNameFromPropertyName(String propertyName, String prefix) { if (propertyName == null) { throw new NullPointerException("propertyName must not be null"); } @@ -531,21 +572,17 @@ /** * Returns Object[0][0] as the entityKey corresponding to the object instance * or null if it is a static method. Returns Object[1] as the params array. - * @throws InstantiationException - * @throws NoSuchMethodException - * @throws InvocationTargetException - * @throws IllegalAccessException - * @throws JSONException - * @throws SecurityException */ public Object[][] getObjectsFromParameterMap(boolean isInstanceMethod, - Map<String, String> parameterMap, Type parameterClasses[]) throws SecurityException, JSONException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException { + Map<String, String> parameterMap, Type parameterClasses[]) + throws SecurityException, JSONException, IllegalAccessException, + InvocationTargetException, NoSuchMethodException, InstantiationException { // TODO: create an EntityMethodCall (instance, args) instead. assert parameterClasses != null; Object args[][] = new Object[2][]; args[0] = new Object[1]; if (isInstanceMethod) { - EntityKey entityKey = getEntityKey(parameterMap.get(RequestData.PARAM_TOKEN + "0")); + EntityKey entityKey = getEntityKey(parameterMap.get(PARAM_TOKEN + "0")); involvedKeys.add(entityKey); args[0][0] = entityKey; } else { @@ -557,7 +594,7 @@ args[1] = new Object[parameterClasses.length - offset]; for (int i = 0; i < parameterClasses.length - offset; i++) { args[1][i] = decodeParameterValue(parameterClasses[i + offset], - parameterMap.get(RequestData.PARAM_TOKEN + (i + offset))); + parameterMap.get(PARAM_TOKEN + (i + offset))); } return args; } @@ -571,18 +608,13 @@ return operation; } - /** - * @param jsonObject - * @return - * @throws org.json.JSONException - */ public Map<String, String> getParameterMap(JSONObject jsonObject) throws JSONException { Map<String, String> parameterMap = new HashMap<String, String>(); Iterator<?> keys = jsonObject.keys(); while (keys.hasNext()) { String key = keys.next().toString(); - if (key.startsWith(RequestData.PARAM_TOKEN)) { + if (key.startsWith(PARAM_TOKEN)) { parameterMap.put(key, jsonObject.getString(key)); } } @@ -590,38 +622,50 @@ } /** - * Returns the property fields (name => type) for a record. + * Returns the property fields (name => type) for a proxyType. */ - public Map<String, Class<?>> getPropertiesFromRecord( - Class<? extends EntityProxy> record) throws SecurityException { - if (!EntityProxy.class.isAssignableFrom(record)) { + public Map<String, Class<?>> getPropertiesFromRecordProxyType( + Class<? extends EntityProxy> proxyType) throws SecurityException { + if (!EntityProxy.class.isAssignableFrom(proxyType)) { return Collections.emptyMap(); } - + Map<String, Class<?>> properties = new LinkedHashMap<String, Class<?>>(); - Method[] methods = record.getMethods(); + Method[] methods = proxyType.getMethods(); for (Method method : methods) { String methodName = method.getName(); - if (method.getDeclaringClass() == EntityProxy.class - && !methodName.equals("getId") && !methodName.equals("getVersion")) { - continue; - } + /* + * TODO(rjrjr) Let's use the Introspector for real, both here and the code + * generator + */ + Class<?> newType = null; + String propertyName = null; if (methodName.startsWith("get")) { - String propertyName = Introspector.decapitalize(methodName.substring(3)); - if (propertyName.length() > 0) { - properties.put(propertyName, method.getReturnType()); + propertyName = Introspector.decapitalize(methodName.substring(3)); + if (propertyName.length() == 0) { + continue; } + newType = method.getReturnType(); } else if (methodName.startsWith("set")) { - String propertyName = Introspector.decapitalize(methodName.substring(3)); + propertyName = Introspector.decapitalize(methodName.substring(3)); if (propertyName.length() > 0) { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length > 0) { - properties.put(propertyName, - parameterTypes[parameterTypes.length - 1]); + newType = parameterTypes[parameterTypes.length - 1]; } } } + if (newType == null) { + continue; // Void return from a getter doesn't count + } + Class<?> existing = properties.put(propertyName, newType); + if (existing != null && !existing.equals(newType)) { + throw new IllegalStateException(String.format( + "In %s, mismatched getter and setter types for property %s, " + + "found %s and %s", proxyType.getName(), propertyName, + existing.getName(), newType.getName())); + } } return properties; } @@ -629,32 +673,13 @@ /** * Returns the property value, in the specified type, from the request object. * The value is put in the DataStore. - * @throws InstantiationException - * @throws NoSuchMethodException - * @throws InvocationTargetException - * @throws IllegalAccessException - * @throws SecurityException */ - public Object getPropertyValueFromRequest(JSONObject recordObject, String key, - Class<?> propertyType) throws JSONException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException { - return decodeParameterValue(propertyType, - recordObject.isNull(key) ? null : recordObject.get(key).toString()); - } - - @SuppressWarnings("unchecked") - public Class<EntityProxy> getRecordFromClassToken(String recordToken) { - try { - Class<?> clazz = Class.forName(recordToken, false, - getClass().getClassLoader()); - if (EntityProxy.class.isAssignableFrom(clazz)) { - return (Class<EntityProxy>) clazz; - } - throw new SecurityException( - "Attempt to access non-record class " + recordToken); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException( - "Non-existent record class " + recordToken); - } + public Object getPropertyValueFromRequest(JSONObject recordObject, + String key, Class<?> propertyType) throws JSONException, + SecurityException, IllegalAccessException, InvocationTargetException, + NoSuchMethodException, InstantiationException { + return decodeParameterValue(propertyType, recordObject.isNull(key) ? null + : recordObject.get(key).toString()); } public JSONObject getViolationsAsJson( @@ -667,21 +692,22 @@ return violationsAsJson; } - public Object invokeDomainMethod(Object domainObject, Method domainMethod, Object args[]) - throws IllegalAccessException, InvocationTargetException { + public Object invokeDomainMethod(Object domainObject, Method domainMethod, + Object args[]) throws IllegalAccessException, InvocationTargetException { return domainMethod.invoke(domainObject, args); } @SuppressWarnings("unchecked") public JSONObject processJsonRequest(String jsonRequestString) throws JSONException, NoSuchMethodException, IllegalAccessException, - InvocationTargetException, ClassNotFoundException, SecurityException, InstantiationException { + InvocationTargetException, ClassNotFoundException, SecurityException, + InstantiationException { RequestDefinition operation; JSONObject topLevelJsonObject = new JSONObject(jsonRequestString); - String operationName = topLevelJsonObject.getString(RequestData.OPERATION_TOKEN); - String propertyRefsString = topLevelJsonObject.has(RequestData.PROPERTY_REF_TOKEN) - ? topLevelJsonObject.getString(RequestData.PROPERTY_REF_TOKEN) : ""; + String operationName = topLevelJsonObject.getString(OPERATION_TOKEN); + String propertyRefsString = topLevelJsonObject.has(PROPERTY_REF_TOKEN) + ? topLevelJsonObject.getString(PROPERTY_REF_TOKEN) : ""; propertyRefs = RequestProperty.parse(propertyRefsString); operation = getOperation(operationName); @@ -693,23 +719,24 @@ + " should " + (operation.isInstance() ? "not " : "") + "be static"); } - if (topLevelJsonObject.has(RequestData.CONTENT_TOKEN)) { + if (topLevelJsonObject.has(CONTENT_TOKEN)) { // updates involvedKeys and dvsDataMap. - decodeDVS(topLevelJsonObject.getString(RequestData.CONTENT_TOKEN)); + decodeDVS(topLevelJsonObject.getString(CONTENT_TOKEN)); } // get the domain object (for instance methods) and args. Object args[][] = getObjectsFromParameterMap(operation.isInstance(), - getParameterMap(topLevelJsonObject), operation.getRequestParameterTypes()); + getParameterMap(topLevelJsonObject), + operation.getRequestParameterTypes()); // Construct beforeDataMap constructBeforeDataMap(); // Construct afterDvsDataMap. - constructAfterDvsDataMap(); + constructAfterDvsDataMapAfterCallingSetters(); // violations are the only sideEffects at this point. JSONArray violationsAsJson = getViolations(); if (violationsAsJson.length() > 0) { JSONObject envelop = new JSONObject(); - envelop.put("violations", violationsAsJson); + envelop.put(VIOLATIONS_TOKEN, violationsAsJson); return envelop; } @@ -717,6 +744,7 @@ // TODO: resolve parameters other than the domainInstance EntityKey domainEntityKey = null; if (args[0][0] != null) { + // Instance method, replace the key with the actual receiver domainEntityKey = (EntityKey) args[0][0]; EntityData domainEntityData = afterDvsDataMap.get(domainEntityKey); if (domainEntityData != null) { @@ -738,26 +766,26 @@ JSONObject envelop = new JSONObject(); if (result instanceof List<?>) { - envelop.put(RequestData.RESULT_TOKEN, toJsonArray(operation, result)); + envelop.put(RESULT_TOKEN, toJsonArray(operation, result)); } else if (result instanceof Number || result instanceof Enum<?> || result instanceof String || result instanceof Date || result instanceof Character || result instanceof Boolean) { - envelop.put(RequestData.RESULT_TOKEN, result); + envelop.put(RESULT_TOKEN, result); } else { Class<? extends EntityProxy> returnType = null; if (operation.getDomainClassName().equals(FindService.class.getName())) { // HACK. if (involvedKeys.size() == 1) { - returnType = involvedKeys.iterator().next().record; + returnType = involvedKeys.iterator().next().proxyType; } } else { returnType = (Class<? extends EntityProxy>) operation.getReturnType(); } JSONObject jsonObject = toJsonObject(returnType, result); - envelop.put(RequestData.RESULT_TOKEN, jsonObject); + envelop.put(RESULT_TOKEN, jsonObject); } - envelop.put(RequestData.SIDE_EFFECTS_TOKEN, sideEffects); - envelop.put(RequestData.RELATED_TOKEN, encodeRelatedObjectsToJson()); + envelop.put(SIDE_EFFECTS_TOKEN, sideEffects); + envelop.put(RELATED_TOKEN, encodeRelatedObjectsToJson()); return envelop; } @@ -771,6 +799,12 @@ public void validateKeys(JSONObject recordObject, Set<String> declaredProperties) { + /* + * We don't need it by the time we're her (it's in the EntityKey), + * and it gums up the works. + */ + recordObject.remove(ENCODED_ID_PROPERTY); + Iterator<?> keys = recordObject.keys(); while (keys.hasNext()) { String key = (String) keys.next(); @@ -783,8 +817,6 @@ /** * Returns true iff the after and before JSONObjects are different. - * - * @throws JSONException */ boolean hasChanged(JSONObject before, JSONObject after) throws JSONException { if (before == null) { @@ -821,8 +853,8 @@ throws JSONException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { - relatedObjects.put(keyRef, getJsonObject(returnValue, propertyType, - propertyContext)); + relatedObjects.put(keyRef, + getJsonObject(returnValue, propertyType, propertyContext)); } private JSONObject buildExceptionResponse(Throwable throwable) { @@ -856,37 +888,37 @@ return (Class<? extends EntityProxy>) propertyType; } - /** - * @throws InstantiationException - * @throws NoSuchMethodException - * @throws InvocationTargetException - * @throws IllegalAccessException - * @throws SecurityException - * @throws JSONException - * - */ - private void constructAfterDvsDataMap() throws SecurityException, JSONException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException { + private void constructAfterDvsDataMapAfterCallingSetters() + throws SecurityException, JSONException, IllegalAccessException, + InvocationTargetException, NoSuchMethodException, InstantiationException { afterDvsDataMap = new HashMap<EntityKey, EntityData>(); for (EntityKey entityKey : involvedKeys) { // use the beforeDataMap and dvsDataMap DvsData dvsData = dvsDataMap.get(entityKey); if (dvsData != null) { - EntityData entityData = getEntityDataForRecord(entityKey, - dvsData.jsonObject, dvsData.writeOperation); + EntityData entityData = getEntityDataForRecordWithSettersApplied( + entityKey, dvsData.jsonObject, dvsData.writeOperation); if (entityKey.isFuture) { // TODO: assert that the id is null for entityData.entityInstance } afterDvsDataMap.put(entityKey, entityData); } else { if (entityKey.isFuture) { - // dummy create, i.e., an entity that the dvs does not know about. + /* + * dummy create, i.e., an entity for which RequestFactory#create was + * called, but for which no values were set, so it is not listed in + * the dvs TODO(rjrjr) silly to work around this on the server. Fix + * the client. + */ JSONObject dummyJson = new JSONObject(); - dummyJson.put("id", entityKey.id); + dummyJson.put(ENCODED_ID_PROPERTY, entityKey.encodedId); afterDvsDataMap.put( entityKey, - getEntityDataForRecord(entityKey, dummyJson, + getEntityDataForRecordWithSettersApplied(entityKey, dummyJson, WriteOperation.CREATE)); } else { + // Involved, but not in the deltaValueStore -- param ref to an + // unedited existing object SerializedEntity serializedEntity = beforeDataMap.get(entityKey); assert serializedEntity.entityInstance != null; afterDvsDataMap.put(entityKey, new EntityData( @@ -902,11 +934,10 @@ * <p> * Algorithm: go through the involvedKeys, and find the entityData * corresponding to each. - * */ private void constructBeforeDataMap() throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, - NoSuchMethodException, JSONException { + NoSuchMethodException, JSONException, InstantiationException { for (EntityKey entityKey : involvedKeys) { if (entityKey.isFuture) { // the "before" is empty. @@ -918,9 +949,9 @@ /** * Decode deltaValueStore to populate involvedKeys and dvsDataMap. - * @throws JSONException */ - private void decodeDVS(String content) throws SecurityException, JSONException { + private void decodeDVS(String content) throws SecurityException, + JSONException { JSONObject jsonObject = new JSONObject(content); for (WriteOperation writeOperation : WriteOperation.values()) { if (!jsonObject.has(writeOperation.name())) { @@ -943,7 +974,8 @@ } JSONObject recordObject = recordWithSchema.getJSONObject(recordToken); Class<? extends EntityProxy> record = getRecordFromClassToken(recordToken); - EntityKey entityKey = new EntityKey(recordObject.getString("id"), + EntityKey entityKey = new EntityKey( + recordObject.getString(ENCODED_ID_PROPERTY), (writeOperation == WriteOperation.CREATE), record); involvedKeys.add(entityKey); dvsDataMap.put(entityKey, new DvsData(recordObject, writeOperation)); @@ -954,26 +986,33 @@ private WriteOperation detectDeleteOrUpdate(EntityKey entityKey, EntityData entityData) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, - NoSuchMethodException, JSONException { + NoSuchMethodException, JSONException, InstantiationException { if (entityData == null || entityData.entityInstance == null) { return null; } - Class<?> entityClass = getEntityFromRecordAnnotation(entityKey.record); - // TODO: merge this lookup code with other uses. - Object entityInstance = entityClass.getMethod( - "find" + entityClass.getSimpleName(), String.class).invoke(null, - entityKey.id); + Object entityInstance = getEntityInstance(entityKey); if (entityInstance == null) { return WriteOperation.DELETE; } if (hasChanged(beforeDataMap.get(entityKey).serializedEntity, - serializeEntity(entityInstance, entityKey.record))) { + serializeEntity(entityInstance, entityKey))) { return WriteOperation.UPDATE; } return null; } + private String encodeId(Object id) throws JSONException { + if (id instanceof String) { + return FAKE_ENCODED + id; + } + + JSONObject o = new JSONObject(); + o.put("foo", encodePropertyValue(id)); + + return o.get("foo").toString(); + } + private JSONObject encodeRelatedObjectsToJson() throws JSONException { JSONObject array = new JSONObject(); for (Map.Entry<String, JSONObject> entry : relatedObjects.entrySet()) { @@ -990,16 +1029,23 @@ Object entityInstance = entityData.entityInstance; assert entityInstance != null; JSONObject returnObject = new JSONObject(); - returnObject.put("futureId", originalEntityKey.id + ""); + returnObject.put("futureId", originalEntityKey.encodedId + ""); // violations have already been taken care of. - Object newId = encodePropertyValueFromDataStore(entityInstance, String.class, - "id", propertyRefs); + + Class<?> idType = getIdMethodForEntity(entityInstance.getClass()).getReturnType(); + Object newId = encodePropertyValueFromDataStore(entityInstance, idType, + ENTITY_ID_PROPERTY, propertyRefs); if (newId == null) { - log.warning("Record with futureId " + originalEntityKey.id + log.warning("Record with futureId " + originalEntityKey.encodedId + " not persisted"); return null; // no changeRecord for this CREATE. } - returnObject.put("id", getSchemaAndId(originalEntityKey.record, newId)); + + // TODO(rjrjr) Makes testDummyCreateBar pass but breaks testDummyCreate +// newId = encodeId(newId); + + + returnObject.put("id", getSchemaAndId(originalEntityKey.proxyType, newId)); returnObject.put( "version", encodePropertyValueFromDataStore(entityInstance, Integer.class, @@ -1015,26 +1061,30 @@ String parts[] = string.split("-"); assert parts.length == 3; - String id = parts[0]; - return new EntityKey(id, "IS".equals(parts[1]), + String encodedId = parts[0]; + return new EntityKey(encodedId, "IS".equals(parts[1]), getRecordFromClassToken(parts[2])); } - private String getSchemaAndId(Class<? extends EntityProxy> record, Object newId) { - return record.getName() + "-" + newId; + private Method getIdMethodForEntity(Class<?> entityType) + throws NoSuchMethodException { + Method idMethod = entityType.getMethod( + getMethodNameFromPropertyName(ENTITY_ID_PROPERTY, "get")); + return idMethod; + } + + private String getSchemaAndId(Class<? extends EntityProxy> proxyType, + Object newId) { + return proxyType.getName() + "-" + newId; } private SerializedEntity getSerializedEntity(EntityKey entityKey) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, - JSONException { - Class<?> entityClass = getEntityFromRecordAnnotation(entityKey.record); - // TODO: merge this lookup code with other uses. - Object entityInstance = entityClass.getMethod( - "find" + entityClass.getSimpleName(), String.class).invoke(null, - entityKey.id); - JSONObject serializedEntity = serializeEntity(entityInstance, - entityKey.record); + JSONException, InstantiationException { + + Object entityInstance = getEntityInstance(entityKey); + JSONObject serializedEntity = serializeEntity(entityInstance, entityKey); return new SerializedEntity(entityInstance, serializedEntity); } @@ -1043,7 +1093,7 @@ * value is a JSONArray of JSONObjects. */ private JSONObject getSideEffects() throws SecurityException, JSONException, - IllegalAccessException, InvocationTargetException, NoSuchMethodException { + IllegalAccessException, InvocationTargetException, NoSuchMethodException, IllegalArgumentException, InstantiationException { JSONObject sideEffects = new JSONObject(); JSONArray createArray = new JSONArray(); JSONArray deleteArray = new JSONArray(); @@ -1064,12 +1114,14 @@ entityData); if (writeOperation == WriteOperation.DELETE) { JSONObject deleteRecord = new JSONObject(); - deleteRecord.put("id", getSchemaAndId(entityKey.record, entityKey.id)); + deleteRecord.put("id", + getSchemaAndId(entityKey.proxyType, entityKey.encodedId)); deleteArray.put(deleteRecord); } if (writeOperation == WriteOperation.UPDATE) { JSONObject updateRecord = new JSONObject(); - updateRecord.put("id", getSchemaAndId(entityKey.record, entityKey.id)); + updateRecord.put("id", + getSchemaAndId(entityKey.proxyType, entityKey.encodedId)); updateArray.put(updateRecord); } } @@ -1096,12 +1148,13 @@ DvsData dvsData = dvsDataMap.get(entityKey); if (dvsData != null) { JSONObject returnObject = new JSONObject(); - returnObject.put("violations", entityData.violations); + returnObject.put(VIOLATIONS_TOKEN, entityData.violations); if (entityKey.isFuture) { - returnObject.put("futureId", entityKey.id + ""); - returnObject.put("id", getSchemaAndId(entityKey.record, null)); + returnObject.put("futureId", entityKey.encodedId); + returnObject.put("id", getSchemaAndId(entityKey.proxyType, null)); } else { - returnObject.put("id", getSchemaAndId(entityKey.record, entityKey.id)); + returnObject.put("id", + getSchemaAndId(entityKey.proxyType, entityKey.encodedId)); } violations.put(returnObject); } @@ -1109,6 +1162,17 @@ return violations; } + private String isEntityReference(Object entity, Class<?> proxyPropertyType) + throws SecurityException, NoSuchMethodException, + IllegalArgumentException, IllegalAccessException, + InvocationTargetException, JSONException { + if (entity != null && EntityProxy.class.isAssignableFrom(proxyPropertyType)) { + Method idMethod = getIdMethodForEntity(entity.getClass()); + return encodeId(idMethod.invoke(entity)); + } + return null; + } + /** * returns true if the property has been requested. TODO: use the properties * that should be coming with the request. @@ -1127,31 +1191,31 @@ } /** - * Return the properties of an entityInstance, visible on the client, as a - * JSONObject. + * Return the client-visible properties of an entityInstance as a JSONObject. * <p> * TODO: clean up the copy-paste from getJSONObject. */ - private JSONObject serializeEntity(Object entityInstance, - Class<? extends EntityProxy> recordClass) throws SecurityException, - NoSuchMethodException, IllegalArgumentException, IllegalAccessException, + private JSONObject serializeEntity(Object entityInstance, EntityKey entityKey) + throws SecurityException, NoSuchMethodException, + IllegalArgumentException, IllegalAccessException, InvocationTargetException, JSONException { if (entityInstance == null) { return null; } JSONObject jsonObject = new JSONObject(); - for (Property<?> p : allProperties(recordClass)) { + jsonObject.put(ENCODED_ID_PROPERTY, entityKey.encodedId); + for (Property<?> p : allProperties(entityKey.proxyType)) { String propertyName = p.getName(); String methodName = getMethodNameFromPropertyName(propertyName, "get"); Method method = entityInstance.getClass().getMethod(methodName); Object returnValue = method.invoke(entityInstance); Object propertyValue; - if (returnValue != null && EntityProxy.class.isAssignableFrom(p.getType())) { - Method idMethod = returnValue.getClass().getMethod("getId"); - String id = (String) idMethod.invoke(returnValue); - - propertyValue = id + "-NO-" + operationRegistry.getSecurityProvider().encodeClassType( + String encodedEntityId = isEntityReference(returnValue, p.getType()); + if (encodedEntityId != null) { + propertyValue = encodedEntityId + + "-NO-" + + operationRegistry.getSecurityProvider().encodeClassType( p.getType()); } else { propertyValue = encodePropertyValue(returnValue); @@ -1170,19 +1234,19 @@ return jsonArray; } - private JSONObject toJsonObject(Class<? extends EntityProxy> returnType, Object result) - throws JSONException, NoSuchMethodException, IllegalAccessException, - InvocationTargetException { + private JSONObject toJsonObject(Class<? extends EntityProxy> returnType, + Object result) throws JSONException, NoSuchMethodException, + IllegalAccessException, InvocationTargetException { JSONObject jsonObject = getJsonObject(result, returnType, propertyRefs); return jsonObject; } /** - * Update propertiesInRecord based on the types of entity. + * Update propertiesInRecord based on the types of entity type. */ private void updatePropertyTypes(Map<String, Class<?>> propertiesInRecord, - Class<?> entity) { - for (Field field : entity.getDeclaredFields()) { + Class<?> entityType) { + for (Field field : entityType.getDeclaredFields()) { Class<?> fieldType = propertiesInRecord.get(field.getName()); if (fieldType != null) { propertiesInRecord.put(field.getName(), field.getType());
diff --git a/user/src/com/google/gwt/requestfactory/server/RequestProperty.java b/user/src/com/google/gwt/requestfactory/server/RequestProperty.java index 7287a0b..ec183b8 100644 --- a/user/src/com/google/gwt/requestfactory/server/RequestProperty.java +++ b/user/src/com/google/gwt/requestfactory/server/RequestProperty.java
@@ -84,9 +84,8 @@ } public Iterator<RequestProperty> iterator() { - return subProperties == null ? - (Iterator<RequestProperty>) Collections.EMPTY_MAP.values().iterator() : - subProperties.values().iterator(); + return subProperties == null ? emptyIterator() + : subProperties.values().iterator(); } public RequestProperty mergeProperty(RequestProperty property) { @@ -105,6 +104,11 @@ return foundProp; } + @SuppressWarnings({"cast", "unchecked"}) + private Iterator<RequestProperty> emptyIterator() { + return (Iterator<RequestProperty>) Collections.EMPTY_MAP.values().iterator(); + } + private RequestProperty getOrCreate(String part) { RequestProperty prop = getProperty(part); if (prop == null) {
diff --git a/user/src/com/google/gwt/requestfactory/server/UserInformation.java b/user/src/com/google/gwt/requestfactory/server/UserInformation.java index fc7b751..472a088 100644 --- a/user/src/com/google/gwt/requestfactory/server/UserInformation.java +++ b/user/src/com/google/gwt/requestfactory/server/UserInformation.java
@@ -55,7 +55,7 @@ } public abstract String getEmail(); - public abstract String getId(); + public abstract Long getId(); public abstract String getLoginUrl(); public abstract String getLogoutUrl(); public abstract String getName(); @@ -65,7 +65,7 @@ } public abstract boolean isUserLoggedIn(); - public abstract void setId(String id); + public abstract void setId(Long id); public void setVersion(Integer version) { this.version = version;
diff --git a/user/src/com/google/gwt/requestfactory/server/UserInformationSimpleImpl.java b/user/src/com/google/gwt/requestfactory/server/UserInformationSimpleImpl.java index cb4f75c..bd6e3ce 100644 --- a/user/src/com/google/gwt/requestfactory/server/UserInformationSimpleImpl.java +++ b/user/src/com/google/gwt/requestfactory/server/UserInformationSimpleImpl.java
@@ -21,7 +21,7 @@ */ public class UserInformationSimpleImpl extends UserInformation { - private String id = ""; + private Long id = 0L; public UserInformationSimpleImpl(String redirectUrl) { super(redirectUrl); @@ -33,7 +33,7 @@ } @Override - public String getId() { + public Long getId() { return this.id; } @@ -58,7 +58,7 @@ } @Override - public void setId(String id) { + public void setId(Long id) { this.id = id; } }
diff --git a/user/src/com/google/gwt/requestfactory/shared/EntityProxy.java b/user/src/com/google/gwt/requestfactory/shared/EntityProxy.java index 5726eba..c633ec4 100644 --- a/user/src/com/google/gwt/requestfactory/shared/EntityProxy.java +++ b/user/src/com/google/gwt/requestfactory/shared/EntityProxy.java
@@ -24,10 +24,6 @@ * A proxy for a server-side domain object. */ public interface EntityProxy { - /** - * @return the id of this Proxy. - */ - String getId(); /** * @return the version of this Proxy. @@ -35,7 +31,10 @@ Integer getVersion(); /** + * Subtypes should override to declare they return a stable id of their own type, + * to allow type safe use of the request objects returned by {@link RequestFactory#find(EntityProxyId)} + * * @return {@link EntityProxyId} that is stable across changes. */ - EntityProxyId stableId(); + EntityProxyId<?> stableId(); }
diff --git a/user/src/com/google/gwt/requestfactory/shared/EntityProxyChange.java b/user/src/com/google/gwt/requestfactory/shared/EntityProxyChange.java index 8c06444..29517cb 100644 --- a/user/src/com/google/gwt/requestfactory/shared/EntityProxyChange.java +++ b/user/src/com/google/gwt/requestfactory/shared/EntityProxyChange.java
@@ -84,8 +84,9 @@ * @return an unpopulated copy of the changed proxy — all properties are * undefined except its id */ - public P getProxy() { - return proxy; + @SuppressWarnings("unchecked") + public EntityProxyId<P> getProxyId() { + return (EntityProxyId<P>) proxy.stableId(); } public WriteOperation getWriteOperation() {
diff --git a/user/src/com/google/gwt/requestfactory/shared/EntityProxyId.java b/user/src/com/google/gwt/requestfactory/shared/EntityProxyId.java index d5f5ac6..d0ea619 100644 --- a/user/src/com/google/gwt/requestfactory/shared/EntityProxyId.java +++ b/user/src/com/google/gwt/requestfactory/shared/EntityProxyId.java
@@ -21,6 +21,8 @@ * <p> * In particular, an {@link EntityProxy} foo that is yet to be persisted and a * copy of foo after being persisted have equal {@link EntityProxyId}. + * + * @param <P> the entity type */ -public interface EntityProxyId { +public interface EntityProxyId<P extends EntityProxy> { }
diff --git a/user/src/com/google/gwt/requestfactory/shared/RequestFactory.java b/user/src/com/google/gwt/requestfactory/shared/RequestFactory.java index 80923d3..0c4a04c 100644 --- a/user/src/com/google/gwt/requestfactory/shared/RequestFactory.java +++ b/user/src/com/google/gwt/requestfactory/shared/RequestFactory.java
@@ -28,12 +28,12 @@ public interface RequestFactory { String JSON_CONTENT_TYPE_UTF8 = "application/json; charset=utf-8"; - <R extends EntityProxy> R create(Class<R> token); + <P extends EntityProxy> P create(Class<P> proxyType); /** * Return a request to find a fresh instance of the referenced proxy. */ - ProxyRequest<EntityProxy> find(EntityProxyId proxyId); + <P extends EntityProxy> ProxyRequest<P> find(EntityProxyId<P> proxyId); /** * Return the class object which may be used to create new instances of the @@ -41,7 +41,7 @@ * metadata system, calls to the proxy's getClass() method will not serve this * purpose. */ - Class<? extends EntityProxy> getClass(EntityProxyId proxyId); + <P extends EntityProxy> Class<P> getClass(EntityProxyId<P> proxyId); /** * Return the class object which may be used to create new instances of the @@ -64,12 +64,12 @@ * * @return a {@link com.google.gwt.user.client.History} compatible token */ - String getHistoryToken(EntityProxyId proxy); + String getHistoryToken(EntityProxyId<?> proxy); /** * Return the appropriate {@link EntityProxyId}, a stable id for the Proxy. */ - EntityProxyId getProxyId(String token); + EntityProxyId<?> getProxyId(String token); /** * Get a {@link com.google.gwt.user.client.History} compatible token that
diff --git a/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java b/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java index 9b452e8..1d26333 100644 --- a/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java +++ b/user/src/com/google/gwt/requestfactory/shared/impl/RequestData.java
@@ -41,6 +41,19 @@ public static final String RELATED_TOKEN = "related"; public static final String SIDE_EFFECTS_TOKEN = "sideEffects"; + + public static final String VIOLATIONS_TOKEN = "violations"; + + /** + * Property on a proxy JSO that holds its encoded server side data store id. + */ + public static final String ENCODED_ID_PROPERTY = "!id"; + + /** + * Id property that server entity objects are required to define + */ + public static final String ENTITY_ID_PROPERTY = "id"; + // TODO: non-final is a hack for now. private final String operation;
diff --git a/user/test/com/google/gwt/requestfactory/client/EditorTest.java b/user/test/com/google/gwt/requestfactory/client/EditorTest.java index bd83022..69e9da9 100644 --- a/user/test/com/google/gwt/requestfactory/client/EditorTest.java +++ b/user/test/com/google/gwt/requestfactory/client/EditorTest.java
@@ -105,7 +105,7 @@ final SimpleFooDriver driver = GWT.create(SimpleFooDriver.class); driver.initialize(req, editor); - req.simpleFooRequest().findSimpleFooById("0L").with(driver.getPaths()).fire( + req.simpleFooRequest().findSimpleFooById(0L).with(driver.getPaths()).fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy response) { @@ -144,7 +144,7 @@ assertEquals(Arrays.asList("barField.userName", "barField"), Arrays.asList(driver.getPaths())); - req.simpleFooRequest().findSimpleFooById("0L").with(driver.getPaths()).fire( + req.simpleFooRequest().findSimpleFooById(0L).with(driver.getPaths()).fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy response) { @@ -191,7 +191,7 @@ final SimpleFooDriver driver = GWT.create(SimpleFooDriver.class); driver.initialize(req, editor); - req.simpleFooRequest().findSimpleFooById("0L").with(driver.getPaths()).fire( + req.simpleFooRequest().findSimpleFooById(0L).with(driver.getPaths()).fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy response) {
diff --git a/user/test/com/google/gwt/requestfactory/client/FindServiceTest.java b/user/test/com/google/gwt/requestfactory/client/FindServiceTest.java index 66cc977..41eee52 100644 --- a/user/test/com/google/gwt/requestfactory/client/FindServiceTest.java +++ b/user/test/com/google/gwt/requestfactory/client/FindServiceTest.java
@@ -15,9 +15,9 @@ */ package com.google.gwt.requestfactory.client; -import com.google.gwt.requestfactory.shared.EntityProxy; import com.google.gwt.requestfactory.shared.EntityProxyId; import com.google.gwt.requestfactory.shared.Receiver; +import com.google.gwt.requestfactory.shared.SimpleBarProxy; import com.google.gwt.requestfactory.shared.SimpleFooProxy; @@ -34,24 +34,22 @@ return "com.google.gwt.requestfactory.RequestFactorySuite"; } - - public void testFetchEntity() { + public void testFetchEntityWithLongId() { final boolean relationsAbsent = false; delayTestFinish(5000); - req.simpleFooRequest().findSimpleFooById("999L").fire( + req.simpleFooRequest().findSimpleFooById(999L).fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy response) { checkReturnedProxy(response, relationsAbsent); - final EntityProxyId stableId = response.stableId(); - req.find(stableId).fire(new Receiver<EntityProxy>() { + final EntityProxyId<SimpleFooProxy> stableId = response.stableId(); + req.find(stableId).fire(new Receiver<SimpleFooProxy>() { @Override - public void onSuccess(EntityProxy returnedProxy) { + public void onSuccess(SimpleFooProxy returnedProxy) { assertEquals(stableId, returnedProxy.stableId()); - checkReturnedProxy((SimpleFooProxy) returnedProxy, - relationsAbsent); + checkReturnedProxy(returnedProxy, relationsAbsent); finishTestAndReset(); } }); @@ -62,27 +60,46 @@ public void testFetchEntityWithRelation() { final boolean relationsPresent = true; delayTestFinish(5000); - req.simpleFooRequest().findSimpleFooById("999L").with("barField").fire( + req.simpleFooRequest().findSimpleFooById(999L).with("barField").fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy response) { checkReturnedProxy(response, relationsPresent); - final EntityProxyId stableId = response.stableId(); + final EntityProxyId<SimpleFooProxy> stableId = response.stableId(); req.find(stableId).with("barField").fire( - new Receiver<EntityProxy>() { + new Receiver<SimpleFooProxy>() { @Override - public void onSuccess(EntityProxy returnedProxy) { + public void onSuccess(SimpleFooProxy returnedProxy) { assertEquals(stableId, returnedProxy.stableId()); - checkReturnedProxy((SimpleFooProxy) returnedProxy, - relationsPresent); + checkReturnedProxy(returnedProxy, relationsPresent); finishTestAndReset(); } }); } }); } + + public void testFetchEntityWithStringId() { + delayTestFinish(5000); + req.simpleBarRequest().findSimpleBarById("999L").fire( + new Receiver<SimpleBarProxy>() { + @Override + public void onSuccess(SimpleBarProxy response) { + final EntityProxyId<SimpleBarProxy> stableId = response.stableId(); + req.find(stableId).fire(new Receiver<SimpleBarProxy>() { + + @Override + public void onSuccess(SimpleBarProxy returnedProxy) { + assertEquals(stableId, returnedProxy.stableId()); + assertEquals("999L", returnedProxy.getId()); + finishTestAndReset(); + } + }); + } + }); + } private void checkReturnedProxy(SimpleFooProxy response, boolean checkForRelations) {
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java index 23eb58e..e8fe723 100644 --- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java +++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
@@ -16,6 +16,7 @@ package com.google.gwt.requestfactory.client; import com.google.gwt.requestfactory.client.impl.ProxyImpl; +import com.google.gwt.requestfactory.shared.EntityProxy; import com.google.gwt.requestfactory.shared.Receiver; import com.google.gwt.requestfactory.shared.RequestObject; import com.google.gwt.requestfactory.shared.ServerFailure; @@ -23,6 +24,7 @@ import com.google.gwt.requestfactory.shared.SimpleFooProxy; import com.google.gwt.requestfactory.shared.Violation; +import java.util.List; import java.util.Set; /** @@ -39,8 +41,7 @@ private final RequestObject<T> request; private boolean voidReturnExpected; - FailFixAndRefire(SimpleFooProxy proxy, - RequestObject<T> request) { + FailFixAndRefire(SimpleFooProxy proxy, RequestObject<T> request) { this.proxy = request.edit(proxy); this.request = request; } @@ -61,17 +62,17 @@ @Override public void onViolation(Set<Violation> errors) { - + // size violation expected - + assertEquals(1, errors.size()); Violation error = errors.iterator().next(); assertEquals("userName", error.getPath()); assertEquals("size must be between 3 and 30", error.getMessage()); assertEquals(proxy.stableId(), error.getProxyId()); - // Now re-used the request to fix the edit - + // Now re-used the request to fix the edit + proxy.setUserName("long enough"); request.fire(new Receiver<T>() { @Override @@ -91,7 +92,7 @@ voidReturnExpected = true; doTest(); } - + void doTest() { proxy.setUserName("a"); // too short request.fire(this); @@ -126,9 +127,32 @@ }); } + public void xx_testDummyCreateBar() { // See note JsonRequestProcessor.getCreateReturnRecord + delayTestFinish(5000); + + final SimpleBarProxy foo = req.create(SimpleBarProxy.class); + Object futureId = foo.getId(); + assertEquals(futureId, foo.getId()); + assertTrue(((ProxyImpl) foo).isFuture()); + RequestObject<SimpleBarProxy> fooReq = req.simpleBarRequest().persistAndReturnSelf( + foo); + fooReq.fire(new Receiver<SimpleBarProxy>() { + + @Override + public void onSuccess(final SimpleBarProxy returned) { + Object futureId = foo.getId(); + assertEquals(futureId, foo.getId()); + assertTrue(((ProxyImpl) foo).isFuture()); + + checkStableIdEquals(foo, returned); + finishTestAndReset(); + } + }); + } + public void testFetchEntity() { delayTestFinish(5000); - req.simpleFooRequest().findSimpleFooById("999L").fire( + req.simpleFooRequest().findSimpleFooById(999L).fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy response) { @@ -145,7 +169,7 @@ public void testFetchEntityWithRelation() { delayTestFinish(5000); - req.simpleFooRequest().findSimpleFooById("999L").with("barField").fire( + req.simpleFooRequest().findSimpleFooById(999L).with("barField").fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy response) { @@ -164,15 +188,41 @@ assertEquals(eventBus, req.getEventBus()); } + public void testGetList() { + // String ids + req.simpleBarRequest().findAll().fire(new Receiver<List<SimpleBarProxy>>() { + @Override + public void onSuccess(List<SimpleBarProxy> response) { + assertEquals("2", response.size()); + for (SimpleBarProxy bar : response) { + assertNotNull(bar.stableId()); + } + } + }); + + // Long ids + req.simpleFooRequest().findAll().with("barField.userName").fire( + new Receiver<List<SimpleFooProxy>>() { + @Override + public void onSuccess(List<SimpleFooProxy> response) { + assertEquals("1", response.size()); + for (SimpleFooProxy foo : response) { + assertNotNull(foo.stableId()); + assertEquals("GWT", foo.getBarField().getUserName()); + } + } + }); + } + /* * tests that (a) any method can have a side effect that is handled correctly. - * (b) instance methods are handled correctly and (c) a request cannot - * be reused after a successful response is received. (Yet?) + * (b) instance methods are handled correctly and (c) a request cannot be + * reused after a successful response is received. (Yet?) */ public void testMethodWithSideEffects() { delayTestFinish(5000); - req.simpleFooRequest().findSimpleFooById("999L").fire( + req.simpleFooRequest().findSimpleFooById(999L).fire( new Receiver<SimpleFooProxy>() { @Override @@ -190,7 +240,7 @@ // confirm that the instance method did have the desired // sideEffect. - req.simpleFooRequest().findSimpleFooById("999L").fire( + req.simpleFooRequest().findSimpleFooById(999L).fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy finalFoo) { @@ -223,7 +273,7 @@ new Receiver<SimpleBarProxy>() { @Override public void onSuccess(final SimpleBarProxy barProxy) { - req.simpleFooRequest().findSimpleFooById("999L").fire( + req.simpleFooRequest().findSimpleFooById(999L).fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy fooProxy) { @@ -262,7 +312,7 @@ public void onSuccess(final SimpleBarProxy persistedBar) { // It was made, now find a foo to assign it to - req.simpleFooRequest().findSimpleFooById("999L").fire( + req.simpleFooRequest().findSimpleFooById(999L).fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy response) { @@ -277,7 +327,7 @@ public void onSuccess(Void response) { // Foo was persisted, fetch it again check the goods - req.simpleFooRequest().findSimpleFooById("999L").with( + req.simpleFooRequest().findSimpleFooById(999L).with( "barField.userName").fire( new Receiver<SimpleFooProxy>() { @@ -319,7 +369,7 @@ fooReq.fire(new Receiver<Void>() { @Override public void onSuccess(Void response) { - req.simpleFooRequest().findSimpleFooById("999L").fire( + req.simpleFooRequest().findSimpleFooById(999L).fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy finalFooProxy) { @@ -369,7 +419,7 @@ fooReq2.fire(new Receiver<Void>() { @Override public void onSuccess(Void response) { - req.simpleFooRequest().findSimpleFooById("999L").with( + req.simpleFooRequest().findSimpleFooById(999L).with( "barField.userName").fire(new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy finalFooProxy) { @@ -445,7 +495,7 @@ public void testProxysAsInstanceMethodParams() { delayTestFinish(5000); - req.simpleFooRequest().findSimpleFooById("999L").fire( + req.simpleFooRequest().findSimpleFooById(999L).fire( new Receiver<SimpleFooProxy>() { @Override public void onSuccess(SimpleFooProxy response) { @@ -469,8 +519,8 @@ delayTestFinish(5000); SimpleFooProxy newFoo = req.create(SimpleFooProxy.class); - final RequestObject<SimpleFooProxy> persistRequest = - req.simpleFooRequest().persistAndReturnSelf(newFoo); + final RequestObject<SimpleFooProxy> persistRequest = req.simpleFooRequest().persistAndReturnSelf( + newFoo); final SimpleFooProxy mutableFoo = persistRequest.edit(newFoo); mutableFoo.setPleaseCrash(42); // 42 is the crash causing magic number @@ -478,7 +528,8 @@ persistRequest.fire(new Receiver<SimpleFooProxy>() { @Override public void onFailure(ServerFailure error) { - assertEquals("Server Error: THIS EXCEPTION IS EXPECTED BY A TEST", error.getMessage()); + assertEquals("Server Error: THIS EXCEPTION IS EXPECTED BY A TEST", + error.getMessage()); assertEquals("", error.getExceptionType()); assertEquals("", error.getStackTraceString()); @@ -625,8 +676,8 @@ } } - private void checkStableIdEquals(SimpleFooProxy expected, - SimpleFooProxy actual) { + private void checkStableIdEquals(EntityProxy expected, + EntityProxy actual) { assertNotSame(expected.stableId(), actual.stableId()); assertEquals(expected.stableId(), actual.stableId()); assertEquals(expected.stableId().hashCode(), actual.stableId().hashCode());
diff --git a/user/test/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImplTest.java b/user/test/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImplTest.java index 022a3c0..35b23f5 100644 --- a/user/test/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImplTest.java +++ b/user/test/com/google/gwt/requestfactory/client/impl/DeltaValueStoreJsonImplTest.java
@@ -24,6 +24,7 @@ import com.google.gwt.requestfactory.shared.EntityProxy; import com.google.gwt.requestfactory.shared.SimpleFooProxy; import com.google.gwt.requestfactory.shared.WriteOperation; +import com.google.gwt.requestfactory.shared.impl.RequestData; import java.util.Date; @@ -76,7 +77,7 @@ public void testCreate() { EntityProxy created = requestFactory.create(SimpleFooProxy.class); - assertNotNull(created.getId()); + assertNotNull(((ProxyImpl)created).encodedId()); assertNotNull(created.getVersion()); DeltaValueStoreJsonImpl deltaValueStore = new DeltaValueStoreJsonImpl( @@ -101,7 +102,7 @@ public void testCreateWithSet() { EntityProxy created = requestFactory.create(SimpleFooProxy.class); - assertNotNull(created.getId()); + assertNotNull(((ProxyImpl)created).encodedId()); assertNotNull(created.getVersion()); DeltaValueStoreJsonImpl deltaValueStore = new DeltaValueStoreJsonImpl( @@ -141,7 +142,7 @@ public void testSeparateIds() { ProxyImpl createProxy = (ProxyImpl) requestFactory.create(SimpleFooProxy.class); assertTrue(createProxy.isFuture()); - String futureId = createProxy.getId(); + String futureId = createProxy.encodedId(); ProxyImpl mockProxy = new ProxyImpl(ProxyJsoImpl.create(futureId, 1, SimpleRequestFactoryInstance.schema(), @@ -209,7 +210,7 @@ assertTrue(proxyWithName.containsKey(SIMPLE_FOO_CLASS_NAME)); JSONObject proxy = proxyWithName.get(SIMPLE_FOO_CLASS_NAME).isObject(); - assertTrue(proxy.containsKey("id")); + assertTrue(proxy.containsKey(RequestData.ENCODED_ID_PROPERTY)); assertTrue(proxy.containsKey("version")); return proxy;
diff --git a/user/test/com/google/gwt/requestfactory/client/impl/EntityProxyIdImplTest.java b/user/test/com/google/gwt/requestfactory/client/impl/EntityProxyIdImplTest.java index 07421fe..da706c7 100644 --- a/user/test/com/google/gwt/requestfactory/client/impl/EntityProxyIdImplTest.java +++ b/user/test/com/google/gwt/requestfactory/client/impl/EntityProxyIdImplTest.java
@@ -47,22 +47,22 @@ EntityProxyIdImpl newKey1 = new EntityProxyIdImpl("test", new Schema1(), RequestFactoryJsonImpl.IS_FUTURE, null); - EntityProxyIdImpl anotherNewKey1 = new EntityProxyIdImpl(newKey1.id, newKey1.schema, + EntityProxyIdImpl anotherNewKey1 = new EntityProxyIdImpl(newKey1.encodedId, newKey1.schema, newKey1.isFuture, null); assertTrue(newKey1.equals(anotherNewKey1)); assertTrue(newKey1.hashCode() == anotherNewKey1.hashCode()); - EntityProxyIdImpl newKey2 = new EntityProxyIdImpl((String) newKey1.id + 1, newKey1.schema, + EntityProxyIdImpl newKey2 = new EntityProxyIdImpl((String) newKey1.encodedId + 1, newKey1.schema, newKey1.isFuture, null); assertFalse(newKey1.equals(newKey2)); assertFalse(newKey1.hashCode() == newKey2.hashCode()); - EntityProxyIdImpl newKey1NoSchema = new EntityProxyIdImpl(newKey1.id, + EntityProxyIdImpl newKey1NoSchema = new EntityProxyIdImpl(newKey1.encodedId, new Schema2(), newKey1.isFuture, null); assertFalse(newKey1.equals(newKey1NoSchema)); assertFalse(newKey1.hashCode() == newKey1NoSchema.hashCode()); - EntityProxyIdImpl oldKey1 = new EntityProxyIdImpl(newKey1.id, newKey1.schema, + EntityProxyIdImpl oldKey1 = new EntityProxyIdImpl(newKey1.encodedId, newKey1.schema, !newKey1.isFuture, null); assertFalse(newKey1.equals(oldKey1)); assertFalse(newKey1.hashCode() == oldKey1.hashCode()); @@ -73,7 +73,7 @@ RequestFactoryJsonImpl.IS_FUTURE, null); EntityProxyIdImpl persistedNewKey1 = new EntityProxyIdImpl("test2", - newKey1.schema, RequestFactoryJsonImpl.NOT_FUTURE, newKey1.id); + newKey1.schema, RequestFactoryJsonImpl.NOT_FUTURE, newKey1.encodedId); assertTrue(persistedNewKey1.equals(persistedNewKey1)); assertTrue(newKey1.equals(persistedNewKey1)); assertTrue(persistedNewKey1.equals(newKey1)); @@ -81,7 +81,7 @@ EntityProxyIdImpl anotherPersistedNewKey1 = new EntityProxyIdImpl("test3", newKey1.schema, RequestFactoryJsonImpl.NOT_FUTURE, - (String) newKey1.id + 1); + (String) newKey1.encodedId + 1); assertTrue(anotherPersistedNewKey1.equals(anotherPersistedNewKey1)); assertFalse(persistedNewKey1.equals(anotherPersistedNewKey1)); assertFalse(anotherPersistedNewKey1.equals(persistedNewKey1));
diff --git a/user/test/com/google/gwt/requestfactory/client/impl/ProxyJsoImplTest.java b/user/test/com/google/gwt/requestfactory/client/impl/ProxyJsoImplTest.java index 3b1280d..6c797c1 100644 --- a/user/test/com/google/gwt/requestfactory/client/impl/ProxyJsoImplTest.java +++ b/user/test/com/google/gwt/requestfactory/client/impl/ProxyJsoImplTest.java
@@ -18,6 +18,7 @@ import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.requestfactory.client.SimpleRequestFactoryInstance; +import com.google.gwt.requestfactory.shared.impl.RequestData; import java.math.BigDecimal; import java.math.BigInteger; @@ -37,7 +38,7 @@ "userName", "bovik", "password", "bovik", "charField", "c", "longField", "1234567890", "bigDecimalField", "12345678901234.5678901234567890", "bigIntField", - "123456789012345678901234567890", "created", "400", "id", "42L"}; + "123456789012345678901234567890", "created", "400", RequestData.ENCODED_ID_PROPERTY, "42L"}; String[] literalBits = new String[]{ "version", "1", "intId", "4", "shortField", "5", "byteField", "6", @@ -76,8 +77,10 @@ ALL_PROPERTIES_JSON = b.toString(); } - private static final String ID_VERSION_JSON = "{\"id\":\"42L\",\"version\":1}"; - private static final String ID_VERSION_JSON2 = "{\"id\":\"43L\",\"version\":1}"; + private static final String ID_VERSION_JSON = "{\"" + + RequestData.ENCODED_ID_PROPERTY + "\":\"42L\",\"version\":1}"; + private static final String ID_VERSION_JSON2 = "{\"" + + RequestData.ENCODED_ID_PROPERTY + "\":\"43L\",\"version\":1}"; static ProxyJsoImpl getMinimalJso() { return ProxyJsoImpl.create("42L", 1, SimpleRequestFactoryInstance.schema(), @@ -122,7 +125,7 @@ ProxyJsoImpl minimalJsoCopy = getMinimalJso(); assertFalse(minimalJso.hasChanged(minimalJsoCopy)); - minimalJsoCopy.set(SimpleFooProxyProperties.id, minimalJso.getId() + 42); + minimalJsoCopy.set(SimpleFooProxyProperties.boolField, true); assertTrue(minimalJso.hasChanged(minimalJsoCopy)); } @@ -184,15 +187,15 @@ } private void testMinimalJso(ProxyJsoImpl jso) { - for (String property : new String[]{"id", "version"}) { - assertTrue(jso.isDefined(property)); + for (String property : new String[]{RequestData.ENCODED_ID_PROPERTY, "version"}) { + assertTrue("expect " + property + " to be defined", jso.isDefined(property)); } for (String property : new String[]{ "created", "intId", "userName", "password"}) { assertFalse(jso.isDefined(property)); assertNull(jso.get(property)); } - assertEquals("42L", jso.getId()); + assertEquals("42L", jso.encodedId()); assertEquals(new Integer(1), jso.getVersion()); assertEquals(null, jso.get(SimpleFooProxyProperties.longField)); assertEquals(null, jso.get(SimpleFooProxyProperties.enumField)); @@ -203,8 +206,8 @@ for (String property : new String[]{ "userName", "password", "charField", "longField", "bigDecimalField", "bigIntField", "intId", "shortField", "byteField", "created", - "doubleField", "floatField", "boolField", "otherBoolField", "id", - "version"}) { + "doubleField", "floatField", "boolField", "otherBoolField", + "version", RequestData.ENCODED_ID_PROPERTY}) { assertTrue("Expect " + property + " to be defined", jso.isDefined(property)); } @@ -234,7 +237,7 @@ assertFalse(jso.get(SimpleFooProxyProperties.boolField)); assertTrue(jso.get(SimpleFooProxyProperties.otherBoolField)); - assertEquals("42L", jso.getId()); + assertEquals("42L", jso.encodedId()); assertEquals(new Integer(1), jso.getVersion()); testSchema(jso);
diff --git a/user/test/com/google/gwt/requestfactory/client/impl/SimpleFooProxyProperties.java b/user/test/com/google/gwt/requestfactory/client/impl/SimpleFooProxyProperties.java index 232d1ea..07ba06b 100644 --- a/user/test/com/google/gwt/requestfactory/client/impl/SimpleFooProxyProperties.java +++ b/user/test/com/google/gwt/requestfactory/client/impl/SimpleFooProxyProperties.java
@@ -26,8 +26,8 @@ import java.util.Date; class SimpleFooProxyProperties { - static final Property<String> id = new Property<String>("id", "Id", - String.class); + static final Property<Long> id = new Property<Long>("id", "Id", + Long.class); static final Property<String> version = new Property<String>("version", "Version", String.class);
diff --git a/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java b/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java index 344a914..6660c3d 100644 --- a/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java +++ b/user/test/com/google/gwt/requestfactory/server/JsonRequestProcessorTest.java
@@ -257,6 +257,7 @@ assertEquals(foo.getInt("enumField"), 0); assertEquals(foo.getInt("version"), 1); assertEquals(foo.getBoolean("boolField"), true); + assertNotNull(foo.getString("!id")); assertTrue(foo.has("created")); return foo; }
diff --git a/user/test/com/google/gwt/requestfactory/server/ReflectionBasedOperationRegistryTest.java b/user/test/com/google/gwt/requestfactory/server/ReflectionBasedOperationRegistryTest.java index d1bd7d2..50ed56e 100644 --- a/user/test/com/google/gwt/requestfactory/server/ReflectionBasedOperationRegistryTest.java +++ b/user/test/com/google/gwt/requestfactory/server/ReflectionBasedOperationRegistryTest.java
@@ -15,6 +15,7 @@ */ package com.google.gwt.requestfactory.server; +import com.google.gwt.requestfactory.shared.SimpleBarProxy; import com.google.gwt.requestfactory.shared.SimpleFooProxy; import junit.framework.TestCase; @@ -57,15 +58,28 @@ } public void testGetOpertionScalarWithArgs() { - RequestDefinition request = registry.getOperation("com.google.gwt.requestfactory.shared.SimpleFooRequest::findSimpleFooById"); - assertNotNull(request); - assertEquals("com.google.gwt.requestfactory.server.SimpleFoo", - request.getDomainClassName()); - assertEquals("findSimpleFooById", request.getDomainMethodName()); - assertEquals(SimpleFooProxy.class, request.getReturnType()); - assertEquals(1, request.getParameterTypes().length); - assertEquals(String.class, request.getParameterTypes()[0]); - assertFalse(request.isReturnTypeList()); + { + RequestDefinition request = registry.getOperation("com.google.gwt.requestfactory.shared.SimpleFooRequest::findSimpleFooById"); + assertNotNull(request); + assertEquals("com.google.gwt.requestfactory.server.SimpleFoo", + request.getDomainClassName()); + assertEquals("findSimpleFooById", request.getDomainMethodName()); + assertEquals(SimpleFooProxy.class, request.getReturnType()); + assertEquals(1, request.getParameterTypes().length); + assertEquals(Long.class, request.getParameterTypes()[0]); + assertFalse(request.isReturnTypeList()); + } + { + RequestDefinition request = registry.getOperation("com.google.gwt.requestfactory.shared.SimpleBarRequest::findSimpleBarById"); + assertNotNull(request); + assertEquals("com.google.gwt.requestfactory.server.SimpleBar", + request.getDomainClassName()); + assertEquals("findSimpleBarById", request.getDomainMethodName()); + assertEquals(SimpleBarProxy.class, request.getReturnType()); + assertEquals(1, request.getParameterTypes().length); + assertEquals(String.class, request.getParameterTypes()[0]); + assertFalse(request.isReturnTypeList()); + } } public void testInsecureOperations() {
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java index c17a827..e99a5d3 100644 --- a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java +++ b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
@@ -46,11 +46,11 @@ return Collections.singletonList(get()); } - public static SimpleFoo findSimpleFoo(String id) { + public static SimpleFoo findSimpleFoo(Long id) { return findSimpleFooById(id); } - public static SimpleFoo findSimpleFooById(String id) { + public static SimpleFoo findSimpleFooById(Long id) { get().setId(id); return get(); } @@ -97,7 +97,7 @@ } @Id - private String id = "1L"; + private Long id = 1L; Integer version = 1; @@ -218,7 +218,7 @@ return fooField; } - public String getId() { + public Long getId() { return id; } @@ -269,7 +269,7 @@ } public void persist() { - setId(Long.toString(nextId++) + "L"); + setId(nextId++); } public SimpleFoo persistAndReturnSelf() { @@ -343,7 +343,7 @@ this.fooField = fooField; } - public void setId(String id) { + public void setId(Long id) { this.id = id; }
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleBarProxy.java b/user/test/com/google/gwt/requestfactory/shared/SimpleBarProxy.java index d5f501c..892f926 100644 --- a/user/test/com/google/gwt/requestfactory/shared/SimpleBarProxy.java +++ b/user/test/com/google/gwt/requestfactory/shared/SimpleBarProxy.java
@@ -23,7 +23,11 @@ */ @ProxyFor(SimpleBar.class) public interface SimpleBarProxy extends EntityProxy { + String getId(); + String getUserName(); void setUserName(String userName); + + EntityProxyId<SimpleBarProxy> stableId(); } \ No newline at end of file
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleFooProxy.java b/user/test/com/google/gwt/requestfactory/shared/SimpleFooProxy.java index 1a8e839..5de9711 100644 --- a/user/test/com/google/gwt/requestfactory/shared/SimpleFooProxy.java +++ b/user/test/com/google/gwt/requestfactory/shared/SimpleFooProxy.java
@@ -27,6 +27,8 @@ */ @ProxyFor(SimpleFoo.class) public interface SimpleFooProxy extends EntityProxy { + Long getId(); + SimpleBarProxy getBarField(); SimpleBarProxy getBarNullField(); @@ -104,4 +106,6 @@ void setShortField(Short s); void setUserName(String userName); + + EntityProxyId<SimpleFooProxy> stableId(); }
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java index ed297e1..accc1f9 100644 --- a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java +++ b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
@@ -27,7 +27,7 @@ ProxyListRequest<SimpleFooProxy> findAll(); - ProxyRequest<SimpleFooProxy> findSimpleFooById(String id); + ProxyRequest<SimpleFooProxy> findSimpleFooById(Long id); RequestObject<Integer> privateMethod();