Disallow persisted entities with null version properties because it breaks RequestFactory update semantics.
Patch by: bobv
Review by: rjrjr

Review at http://gwt-code-reviews.appspot.com/1201801


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9381 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java b/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java
index 465facb..2835056 100644
--- a/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java
+++ b/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java
@@ -186,7 +186,7 @@
     processOperationMessages(state, message);
     List<Object> decoded = decodeInvocationArguments(state,
         message.getInvocations().get(0).getParameters(),
-        new Class<?>[] {proxyType}, new Type[] {domainClass});
+        new Class<?>[]{proxyType}, new Type[]{domainClass});
 
     @SuppressWarnings("unchecked")
     List<T> toReturn = (List<T>) decoded;
@@ -273,10 +273,16 @@
       Splittable version = null;
       if (writeOperation == WriteOperation.PERSIST
           || writeOperation == WriteOperation.UPDATE) {
+        /*
+         * If we're sending an operation, the domain object must be persistent.
+         * This means that it must also have a non-null version.
+         */
         Object domainVersion = service.getVersion(domainObject);
-        if (domainVersion != null) {
-          version = returnState.flatten(domainVersion);
+        if (domainVersion == null) {
+          throw new UnexpectedException("The persisted entity with id "
+              + service.getId(domainObject) + " has a null version", null);
         }
+        version = returnState.flatten(domainVersion);
       }
 
       boolean inResponse = bean.getTag(Constants.IN_RESPONSE) != null;
diff --git a/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestFactory.java b/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestFactory.java
index b5ffeda..9616776 100644
--- a/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestFactory.java
+++ b/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestFactory.java
@@ -82,7 +82,7 @@
       protected RequestData makeRequestData() {
         return new RequestData(
             "com.google.gwt.requestfactory.shared.impl.FindRequest::find",
-            new Object[] {proxyId}, propertyRefs, proxyId.getProxyClass(), null);
+            new Object[]{proxyId}, propertyRefs, proxyId.getProxyClass(), null);
       }
     };
   }
@@ -142,6 +142,8 @@
    */
   protected boolean hasVersionChanged(SimpleProxyId<?> id,
       String observedVersion) {
+    assert id != null : "id";
+    assert observedVersion != null : "observedVersion";
     String key = getHistoryToken(id);
     String existingVersion = version.get(key);
     // Return true if we haven't seen this before or the versions differ
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
index 8dec044..1763de6 100644
--- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
@@ -1069,6 +1069,27 @@
     });
   }
 
+  /**
+   * Test that the server code will not allow a persisted entity to be returned
+   * if it has a null version property.
+   */
+  public void testPersistedEntityWithNullVersion() {
+    delayTestFinish(DELAY_TEST_FINISH);
+    simpleFooRequest().getSimpleFooWithNullVersion().fire(
+        new Receiver<SimpleFooProxy>() {
+
+          @Override
+          public void onFailure(ServerFailure error) {
+            finishTestAndReset();
+          }
+
+          @Override
+          public void onSuccess(SimpleFooProxy response) {
+            fail();
+          }
+        });
+  }
+
   public void testPersistExistingEntityExistingRelation() {
     delayTestFinish(DELAY_TEST_FINISH);
 
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
index cd4f8d6..afcd18e 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
@@ -124,6 +124,16 @@
     return list;
   }
 
+  /**
+   * This tests that the server detects and disallows the use of persisted
+   * objects with a null version property.
+   */
+  public static SimpleFoo getSimpleFooWithNullVersion() {
+    SimpleFoo foo = new SimpleFoo();
+    foo.setVersion(null);
+    return foo;
+  }
+
   public static SimpleFoo getSimpleFooWithSubPropertyCollection() {
     SimpleFoo foo = new SimpleFoo();
     SimpleFoo subFoo = new SimpleFoo();
diff --git a/user/test/com/google/gwt/requestfactory/shared/ComplexKeysTest.java b/user/test/com/google/gwt/requestfactory/shared/ComplexKeysTest.java
index 60af61d..701a276 100644
--- a/user/test/com/google/gwt/requestfactory/shared/ComplexKeysTest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/ComplexKeysTest.java
@@ -67,8 +67,8 @@
       return key;
     }
 
-    public Void getVersion() {
-      return null;
+    public Integer getVersion() {
+      return 0;
     }
   }
 
@@ -101,8 +101,8 @@
       return key;
     }
 
-    public Void getVersion() {
-      return null;
+    public Integer getVersion() {
+      return 0;
     }
   }
 
@@ -129,8 +129,8 @@
       return key;
     }
 
-    public Void getVersion() {
-      return null;
+    public Integer getVersion() {
+      return 0;
     }
   }
 
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
index bbb4c6b..a27ad31 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
@@ -49,6 +49,8 @@
 
   Request<Set<Integer>> getNumberSet();
 
+  Request<SimpleFooProxy> getSimpleFooWithNullVersion();
+  
   Request<SimpleFooProxy> getSimpleFooWithSubPropertyCollection();
 
   Request<SimpleFooProxy> getTripletReference();