You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2018/12/28 12:38:22 UTC

[1/4] cayenne git commit: CAY-2467 New type-aware Property API - update client cgen templates - update client tests

Repository: cayenne
Updated Branches:
  refs/heads/master 56b64c35e -> 2cca2445f


http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
index d4ed6aa..0dfd941 100644
--- a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
+++ b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
@@ -1,9 +1,14 @@
 package org.apache.cayenne.tutorial.persistent.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.Painting;
 
 /**
@@ -12,32 +17,96 @@ import org.apache.cayenne.tutorial.persistent.Painting;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Gallery extends CayenneDataObject {
+public abstract class _Gallery extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
+
+    protected String name;
+
+    protected Object paintings;
 
     public void setName(String name) {
-        writeProperty("name", name);
+        beforePropertyWrite("name", this.name, name);
+        this.name = name;
     }
+
     public String getName() {
-        return (String)readProperty("name");
+        beforePropertyRead("name");
+        return this.name;
     }
 
     public void addToPaintings(Painting obj) {
         addToManyTarget("paintings", obj, true);
     }
+
     public void removeFromPaintings(Painting obj) {
         removeToManyTarget("paintings", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<Painting> getPaintings() {
         return (List<Painting>)readProperty("paintings");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "name":
+                return this.name;
+            case "paintings":
+                return this.paintings;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "name":
+                this.name = (String)val;
+                break;
+            case "paintings":
+                this.paintings = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.name);
+        out.writeObject(this.paintings);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.name = (String)in.readObject();
+        this.paintings = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
index 0c39d79..e15e25f 100644
--- a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
+++ b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
@@ -1,7 +1,13 @@
 package org.apache.cayenne.tutorial.persistent.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.Artist;
 import org.apache.cayenne.tutorial.persistent.Gallery;
 
@@ -11,21 +17,29 @@ import org.apache.cayenne.tutorial.persistent.Gallery;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Painting extends CayenneDataObject {
+public abstract class _Painting extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<Artist> ARTIST = Property.create("artist", Artist.class);
-    public static final Property<Gallery> GALLERY = Property.create("gallery", Gallery.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.Artist> ARTIST = PropertyFactory.createEntity("artist", org.apache.cayenne.tutorial.persistent.Artist.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.Gallery> GALLERY = PropertyFactory.createEntity("gallery", org.apache.cayenne.tutorial.persistent.Gallery.class);
+
+    protected String name;
+
+    protected Object artist;
+    protected Object gallery;
 
     public void setName(String name) {
-        writeProperty("name", name);
+        beforePropertyWrite("name", this.name, name);
+        this.name = name;
     }
+
     public String getName() {
-        return (String)readProperty("name");
+        beforePropertyRead("name");
+        return this.name;
     }
 
     public void setArtist(Artist artist) {
@@ -36,7 +50,6 @@ public abstract class _Painting extends CayenneDataObject {
         return (Artist)readProperty("artist");
     }
 
-
     public void setGallery(Gallery gallery) {
         setToOneTarget("gallery", gallery, true);
     }
@@ -45,5 +58,67 @@ public abstract class _Painting extends CayenneDataObject {
         return (Gallery)readProperty("gallery");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "name":
+                return this.name;
+            case "artist":
+                return this.artist;
+            case "gallery":
+                return this.gallery;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "name":
+                this.name = (String)val;
+                break;
+            case "artist":
+                this.artist = val;
+                break;
+            case "gallery":
+                this.gallery = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.name);
+        out.writeObject(this.artist);
+        out.writeObject(this.gallery);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.name = (String)in.readObject();
+        this.artist = in.readObject();
+        this.gallery = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
index b478b8d..052709b 100644
--- a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
+++ b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
@@ -4,7 +4,10 @@ import java.time.LocalDate;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -15,9 +18,9 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _Artist extends PersistentObject {
 
-    public static final Property<LocalDate> DATE_OF_BIRTH = Property.create("dateOfBirth", LocalDate.class);
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final DateProperty<LocalDate> DATE_OF_BIRTH = PropertyFactory.createDate("dateOfBirth", LocalDate.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected LocalDate dateOfBirth;
     protected String name;
@@ -30,17 +33,13 @@ public abstract class _Artist extends PersistentObject {
 
         return dateOfBirth;
     }
+
     public void setDateOfBirth(LocalDate dateOfBirth) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "dateOfBirth", false);
+            objectContext.propertyChanged(this, "dateOfBirth", this.dateOfBirth, dateOfBirth);
         }
 
-        Object oldValue = this.dateOfBirth;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "dateOfBirth", oldValue, dateOfBirth);
-        }
-        
         this.dateOfBirth = dateOfBirth;
     }
 
@@ -51,17 +50,13 @@ public abstract class _Artist extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -69,25 +64,27 @@ public abstract class _Artist extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
index 7c59c64..57ccb07 100644
--- a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
+++ b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
@@ -3,7 +3,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -14,8 +16,8 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _Gallery extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected String name;
     protected List<Painting> paintings;
@@ -27,17 +29,13 @@ public abstract class _Gallery extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -45,25 +43,27 @@ public abstract class _Gallery extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
index ab004f9..ec9511a 100644
--- a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
+++ b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
@@ -2,7 +2,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 
 import org.apache.cayenne.PersistentObject;
 import org.apache.cayenne.ValueHolder;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Artist;
 import org.apache.cayenne.tutorial.persistent.client.Gallery;
 import org.apache.cayenne.util.PersistentObjectHolder;
@@ -14,13 +16,13 @@ import org.apache.cayenne.util.PersistentObjectHolder;
  */
 public abstract class _Painting extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<Artist> ARTIST = Property.create("artist", Artist.class);
-    public static final Property<Gallery> GALLERY = Property.create("gallery", Gallery.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final EntityProperty<Artist> ARTIST = PropertyFactory.createEntity("artist", Artist.class);
+    public static final EntityProperty<Gallery> GALLERY = PropertyFactory.createEntity("gallery", Gallery.class);
 
     protected String name;
-    protected ValueHolder artist;
-    protected ValueHolder gallery;
+    protected ValueHolder<Artist> artist;
+    protected ValueHolder<Gallery> gallery;
 
     public String getName() {
         if(objectContext != null) {
@@ -29,17 +31,13 @@ public abstract class _Painting extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -47,25 +45,19 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        return (Artist) artist.getValue();
+        return artist.getValue();
     }
+
     public void setArtist(Artist artist) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.artist.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "artist", oldValue, artist);
-        }
-        
         this.artist.setValue(artist);
     }
 
@@ -73,25 +65,19 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        return (Gallery) gallery.getValue();
+        return gallery.getValue();
     }
+
     public void setGallery(Gallery gallery) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.gallery.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "gallery", oldValue, gallery);
-        }
-        
         this.gallery.setValue(gallery);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
index 147f9f7..5ff7823 100644
--- a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
+++ b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
@@ -1,10 +1,16 @@
 package org.apache.cayenne.tutorial.persistent.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.time.LocalDate;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.Painting;
 
 /**
@@ -13,40 +19,115 @@ import org.apache.cayenne.tutorial.persistent.Painting;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Artist extends CayenneDataObject {
+public abstract class _Artist extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<LocalDate> DATE_OF_BIRTH = Property.create("dateOfBirth", LocalDate.class);
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final DateProperty<LocalDate> DATE_OF_BIRTH = PropertyFactory.createDate("dateOfBirth", LocalDate.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
+
+    protected LocalDate dateOfBirth;
+    protected String name;
+
+    protected Object paintings;
 
     public void setDateOfBirth(LocalDate dateOfBirth) {
-        writeProperty("dateOfBirth", dateOfBirth);
+        beforePropertyWrite("dateOfBirth", this.dateOfBirth, dateOfBirth);
+        this.dateOfBirth = dateOfBirth;
     }
+
     public LocalDate getDateOfBirth() {
-        return (LocalDate)readProperty("dateOfBirth");
+        beforePropertyRead("dateOfBirth");
+        return this.dateOfBirth;
     }
 
     public void setName(String name) {
-        writeProperty("name", name);
+        beforePropertyWrite("name", this.name, name);
+        this.name = name;
     }
+
     public String getName() {
-        return (String)readProperty("name");
+        beforePropertyRead("name");
+        return this.name;
     }
 
     public void addToPaintings(Painting obj) {
         addToManyTarget("paintings", obj, true);
     }
+
     public void removeFromPaintings(Painting obj) {
         removeToManyTarget("paintings", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<Painting> getPaintings() {
         return (List<Painting>)readProperty("paintings");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "dateOfBirth":
+                return this.dateOfBirth;
+            case "name":
+                return this.name;
+            case "paintings":
+                return this.paintings;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "dateOfBirth":
+                this.dateOfBirth = (LocalDate)val;
+                break;
+            case "name":
+                this.name = (String)val;
+                break;
+            case "paintings":
+                this.paintings = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.dateOfBirth);
+        out.writeObject(this.name);
+        out.writeObject(this.paintings);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.dateOfBirth = (LocalDate)in.readObject();
+        this.name = (String)in.readObject();
+        this.paintings = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
index d4ed6aa..0dfd941 100644
--- a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
+++ b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
@@ -1,9 +1,14 @@
 package org.apache.cayenne.tutorial.persistent.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.Painting;
 
 /**
@@ -12,32 +17,96 @@ import org.apache.cayenne.tutorial.persistent.Painting;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Gallery extends CayenneDataObject {
+public abstract class _Gallery extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
+
+    protected String name;
+
+    protected Object paintings;
 
     public void setName(String name) {
-        writeProperty("name", name);
+        beforePropertyWrite("name", this.name, name);
+        this.name = name;
     }
+
     public String getName() {
-        return (String)readProperty("name");
+        beforePropertyRead("name");
+        return this.name;
     }
 
     public void addToPaintings(Painting obj) {
         addToManyTarget("paintings", obj, true);
     }
+
     public void removeFromPaintings(Painting obj) {
         removeToManyTarget("paintings", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<Painting> getPaintings() {
         return (List<Painting>)readProperty("paintings");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "name":
+                return this.name;
+            case "paintings":
+                return this.paintings;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "name":
+                this.name = (String)val;
+                break;
+            case "paintings":
+                this.paintings = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.name);
+        out.writeObject(this.paintings);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.name = (String)in.readObject();
+        this.paintings = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
index 0c39d79..e15e25f 100644
--- a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
+++ b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
@@ -1,7 +1,13 @@
 package org.apache.cayenne.tutorial.persistent.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.Artist;
 import org.apache.cayenne.tutorial.persistent.Gallery;
 
@@ -11,21 +17,29 @@ import org.apache.cayenne.tutorial.persistent.Gallery;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Painting extends CayenneDataObject {
+public abstract class _Painting extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<Artist> ARTIST = Property.create("artist", Artist.class);
-    public static final Property<Gallery> GALLERY = Property.create("gallery", Gallery.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.Artist> ARTIST = PropertyFactory.createEntity("artist", org.apache.cayenne.tutorial.persistent.Artist.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.Gallery> GALLERY = PropertyFactory.createEntity("gallery", org.apache.cayenne.tutorial.persistent.Gallery.class);
+
+    protected String name;
+
+    protected Object artist;
+    protected Object gallery;
 
     public void setName(String name) {
-        writeProperty("name", name);
+        beforePropertyWrite("name", this.name, name);
+        this.name = name;
     }
+
     public String getName() {
-        return (String)readProperty("name");
+        beforePropertyRead("name");
+        return this.name;
     }
 
     public void setArtist(Artist artist) {
@@ -36,7 +50,6 @@ public abstract class _Painting extends CayenneDataObject {
         return (Artist)readProperty("artist");
     }
 
-
     public void setGallery(Gallery gallery) {
         setToOneTarget("gallery", gallery, true);
     }
@@ -45,5 +58,67 @@ public abstract class _Painting extends CayenneDataObject {
         return (Gallery)readProperty("gallery");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "name":
+                return this.name;
+            case "artist":
+                return this.artist;
+            case "gallery":
+                return this.gallery;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "name":
+                this.name = (String)val;
+                break;
+            case "artist":
+                this.artist = val;
+                break;
+            case "gallery":
+                this.gallery = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.name);
+        out.writeObject(this.artist);
+        out.writeObject(this.gallery);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.name = (String)in.readObject();
+        this.artist = in.readObject();
+        this.gallery = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
index b478b8d..052709b 100644
--- a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
+++ b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
@@ -4,7 +4,10 @@ import java.time.LocalDate;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -15,9 +18,9 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _Artist extends PersistentObject {
 
-    public static final Property<LocalDate> DATE_OF_BIRTH = Property.create("dateOfBirth", LocalDate.class);
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final DateProperty<LocalDate> DATE_OF_BIRTH = PropertyFactory.createDate("dateOfBirth", LocalDate.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected LocalDate dateOfBirth;
     protected String name;
@@ -30,17 +33,13 @@ public abstract class _Artist extends PersistentObject {
 
         return dateOfBirth;
     }
+
     public void setDateOfBirth(LocalDate dateOfBirth) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "dateOfBirth", false);
+            objectContext.propertyChanged(this, "dateOfBirth", this.dateOfBirth, dateOfBirth);
         }
 
-        Object oldValue = this.dateOfBirth;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "dateOfBirth", oldValue, dateOfBirth);
-        }
-        
         this.dateOfBirth = dateOfBirth;
     }
 
@@ -51,17 +50,13 @@ public abstract class _Artist extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -69,25 +64,27 @@ public abstract class _Artist extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
index 7c59c64..57ccb07 100644
--- a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
+++ b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
@@ -3,7 +3,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -14,8 +16,8 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _Gallery extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected String name;
     protected List<Painting> paintings;
@@ -27,17 +29,13 @@ public abstract class _Gallery extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -45,25 +43,27 @@ public abstract class _Gallery extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
index 1671057..ec9511a 100644
--- a/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
+++ b/tutorials/tutorial-rop-server/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
@@ -2,7 +2,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 
 import org.apache.cayenne.PersistentObject;
 import org.apache.cayenne.ValueHolder;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Artist;
 import org.apache.cayenne.tutorial.persistent.client.Gallery;
 import org.apache.cayenne.util.PersistentObjectHolder;
@@ -14,13 +16,13 @@ import org.apache.cayenne.util.PersistentObjectHolder;
  */
 public abstract class _Painting extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<org.apache.cayenne.tutorial.persistent.Artist> ARTIST = Property.create("artist", org.apache.cayenne.tutorial.persistent.Artist.class);
-    public static final Property<org.apache.cayenne.tutorial.persistent.Gallery> GALLERY = Property.create("gallery", org.apache.cayenne.tutorial.persistent.Gallery.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final EntityProperty<Artist> ARTIST = PropertyFactory.createEntity("artist", Artist.class);
+    public static final EntityProperty<Gallery> GALLERY = PropertyFactory.createEntity("gallery", Gallery.class);
 
     protected String name;
-    protected ValueHolder artist;
-    protected ValueHolder gallery;
+    protected ValueHolder<Artist> artist;
+    protected ValueHolder<Gallery> gallery;
 
     public String getName() {
         if(objectContext != null) {
@@ -29,17 +31,13 @@ public abstract class _Painting extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -47,25 +45,19 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        return (Artist) artist.getValue();
+        return artist.getValue();
     }
+
     public void setArtist(Artist artist) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.artist.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "artist", oldValue, artist);
-        }
-        
         this.artist.setValue(artist);
     }
 
@@ -73,25 +65,19 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        return (Gallery) gallery.getValue();
+        return gallery.getValue();
     }
+
     public void setGallery(Gallery gallery) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.gallery.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "gallery", oldValue, gallery);
-        }
-        
         this.gallery.setValue(gallery);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java b/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
index e61b543..5ff7823 100644
--- a/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
+++ b/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
@@ -7,7 +7,10 @@ import java.time.LocalDate;
 import java.util.List;
 
 import org.apache.cayenne.BaseDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.Painting;
 
 /**
@@ -22,9 +25,9 @@ public abstract class _Artist extends BaseDataObject {
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<LocalDate> DATE_OF_BIRTH = Property.create("dateOfBirth", LocalDate.class);
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final DateProperty<LocalDate> DATE_OF_BIRTH = PropertyFactory.createDate("dateOfBirth", LocalDate.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected LocalDate dateOfBirth;
     protected String name;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java b/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
index c73de7e..0dfd941 100644
--- a/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
+++ b/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Gallery.java
@@ -6,7 +6,9 @@ import java.io.ObjectOutputStream;
 import java.util.List;
 
 import org.apache.cayenne.BaseDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.Painting;
 
 /**
@@ -21,8 +23,8 @@ public abstract class _Gallery extends BaseDataObject {
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected String name;
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java b/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
index a75e249..e15e25f 100644
--- a/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
+++ b/tutorials/tutorial/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Painting.java
@@ -5,7 +5,9 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 
 import org.apache.cayenne.BaseDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.Artist;
 import org.apache.cayenne.tutorial.persistent.Gallery;
 
@@ -21,9 +23,9 @@ public abstract class _Painting extends BaseDataObject {
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<Artist> ARTIST = Property.create("artist", Artist.class);
-    public static final Property<Gallery> GALLERY = Property.create("gallery", Gallery.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.Artist> ARTIST = PropertyFactory.createEntity("artist", org.apache.cayenne.tutorial.persistent.Artist.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.Gallery> GALLERY = PropertyFactory.createEntity("gallery", org.apache.cayenne.tutorial.persistent.Gallery.class);
 
     protected String name;
 


[4/4] cayenne git commit: CAY-2467 New type-aware Property API - update tests classes in modules

Posted by nt...@apache.org.
CAY-2467 New type-aware Property API
  - update tests classes in modules


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/2cca2445
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/2cca2445
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/2cca2445

Branch: refs/heads/master
Commit: 2cca2445f8e607db11e227385ed57aa3f2ca1844
Parents: 63a32d8
Author: Nikita Timofeev <st...@gmail.com>
Authored: Fri Dec 28 15:38:15 2018 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Fri Dec 28 15:38:15 2018 +0300

----------------------------------------------------------------------
 .../cayenne/commitlog/db/auto/_AuditLog.java    |  72 +++++++-
 .../cayenne/commitlog/db/auto/_Auditable1.java  |  83 ++++++++-
 .../cayenne/commitlog/db/auto/_Auditable2.java  | 100 +++++++++--
 .../cayenne/commitlog/db/auto/_Auditable3.java  | 100 +++++++++--
 .../cayenne/commitlog/db/auto/_Auditable4.java  |  99 +++++++++--
 .../commitlog/db/auto/_AuditableChild1.java     |  82 ++++++++-
 .../commitlog/db/auto/_AuditableChild3.java     |  99 +++++++++--
 .../apache/cayenne/commitlog/db/auto/_E1.java   |  52 +++++-
 .../apache/cayenne/commitlog/db/auto/_E2.java   |  52 +++++-
 .../apache/cayenne/commitlog/db/auto/_E3.java   |  65 ++++++-
 .../apache/cayenne/commitlog/db/auto/_E4.java   |  65 ++++++-
 .../joda/db/auto/_DateTimeTestEntity.java       |  72 +++++++-
 .../joda/db/auto/_LocalDateTestEntity.java      |  72 +++++++-
 .../joda/db/auto/_LocalDateTimeTestEntity.java  |  72 +++++++-
 .../joda/db/auto/_LocalTimeTestEntity.java      |  72 +++++++-
 .../protostuff/persistent/auto/_MtTable1.java   | 169 ++++++++++++++++---
 .../protostuff/persistent/auto/_MtTable2.java   |  82 ++++++++-
 17 files changed, 1283 insertions(+), 125 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditLog.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditLog.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditLog.java
index d937b03..9caf55f 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditLog.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditLog.java
@@ -1,7 +1,12 @@
 package org.apache.cayenne.commitlog.db.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 
 /**
  * Class _AuditLog was generated by Cayenne.
@@ -9,19 +14,74 @@ import org.apache.cayenne.exp.Property;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _AuditLog extends CayenneDataObject {
+public abstract class _AuditLog extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> LOG = Property.create("log", String.class);
+    public static final StringProperty<String> LOG = PropertyFactory.createString("log", String.class);
+
+    protected String log;
+
 
     public void setLog(String log) {
-        writeProperty("log", log);
+        beforePropertyWrite("log", this.log, log);
+        this.log = log;
     }
+
     public String getLog() {
-        return (String)readProperty("log");
+        beforePropertyRead("log");
+        return this.log;
+    }
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "log":
+                return this.log;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "log":
+                this.log = (String)val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.log);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.log = (String)in.readObject();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable1.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable1.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable1.java
index 1f05a74..1493a56 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable1.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable1.java
@@ -1,10 +1,15 @@
 package org.apache.cayenne.commitlog.db.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
 import org.apache.cayenne.commitlog.db.AuditableChild1;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 
 /**
  * Class _Auditable1 was generated by Cayenne.
@@ -12,32 +17,96 @@ import org.apache.cayenne.commitlog.db.AuditableChild1;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Auditable1 extends CayenneDataObject {
+public abstract class _Auditable1 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> CHAR_PROPERTY1 = Property.create("charProperty1", String.class);
-    public static final Property<List<AuditableChild1>> CHILDREN1 = Property.create("children1", List.class);
+    public static final StringProperty<String> CHAR_PROPERTY1 = PropertyFactory.createString("charProperty1", String.class);
+    public static final ListProperty<AuditableChild1> CHILDREN1 = PropertyFactory.createList("children1", AuditableChild1.class);
+
+    protected String charProperty1;
+
+    protected Object children1;
 
     public void setCharProperty1(String charProperty1) {
-        writeProperty("charProperty1", charProperty1);
+        beforePropertyWrite("charProperty1", this.charProperty1, charProperty1);
+        this.charProperty1 = charProperty1;
     }
+
     public String getCharProperty1() {
-        return (String)readProperty("charProperty1");
+        beforePropertyRead("charProperty1");
+        return this.charProperty1;
     }
 
     public void addToChildren1(AuditableChild1 obj) {
         addToManyTarget("children1", obj, true);
     }
+
     public void removeFromChildren1(AuditableChild1 obj) {
         removeToManyTarget("children1", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<AuditableChild1> getChildren1() {
         return (List<AuditableChild1>)readProperty("children1");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "charProperty1":
+                return this.charProperty1;
+            case "children1":
+                return this.children1;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "charProperty1":
+                this.charProperty1 = (String)val;
+                break;
+            case "children1":
+                this.children1 = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.charProperty1);
+        out.writeObject(this.children1);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.charProperty1 = (String)in.readObject();
+        this.children1 = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable2.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable2.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable2.java
index fff2543..3c23f66 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable2.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable2.java
@@ -1,10 +1,15 @@
 package org.apache.cayenne.commitlog.db.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
 import org.apache.cayenne.commitlog.db.AuditableChild3;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 
 /**
  * Class _Auditable2 was generated by Cayenne.
@@ -12,40 +17,115 @@ import org.apache.cayenne.commitlog.db.AuditableChild3;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Auditable2 extends CayenneDataObject {
+public abstract class _Auditable2 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> CHAR_PROPERTY1 = Property.create("charProperty1", String.class);
-    public static final Property<String> CHAR_PROPERTY2 = Property.create("charProperty2", String.class);
-    public static final Property<List<AuditableChild3>> CHILDREN = Property.create("children", List.class);
+    public static final StringProperty<String> CHAR_PROPERTY1 = PropertyFactory.createString("charProperty1", String.class);
+    public static final StringProperty<String> CHAR_PROPERTY2 = PropertyFactory.createString("charProperty2", String.class);
+    public static final ListProperty<AuditableChild3> CHILDREN = PropertyFactory.createList("children", AuditableChild3.class);
+
+    protected String charProperty1;
+    protected String charProperty2;
+
+    protected Object children;
 
     public void setCharProperty1(String charProperty1) {
-        writeProperty("charProperty1", charProperty1);
+        beforePropertyWrite("charProperty1", this.charProperty1, charProperty1);
+        this.charProperty1 = charProperty1;
     }
+
     public String getCharProperty1() {
-        return (String)readProperty("charProperty1");
+        beforePropertyRead("charProperty1");
+        return this.charProperty1;
     }
 
     public void setCharProperty2(String charProperty2) {
-        writeProperty("charProperty2", charProperty2);
+        beforePropertyWrite("charProperty2", this.charProperty2, charProperty2);
+        this.charProperty2 = charProperty2;
     }
+
     public String getCharProperty2() {
-        return (String)readProperty("charProperty2");
+        beforePropertyRead("charProperty2");
+        return this.charProperty2;
     }
 
     public void addToChildren(AuditableChild3 obj) {
         addToManyTarget("children", obj, true);
     }
+
     public void removeFromChildren(AuditableChild3 obj) {
         removeToManyTarget("children", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<AuditableChild3> getChildren() {
         return (List<AuditableChild3>)readProperty("children");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "charProperty1":
+                return this.charProperty1;
+            case "charProperty2":
+                return this.charProperty2;
+            case "children":
+                return this.children;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "charProperty1":
+                this.charProperty1 = (String)val;
+                break;
+            case "charProperty2":
+                this.charProperty2 = (String)val;
+                break;
+            case "children":
+                this.children = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.charProperty1);
+        out.writeObject(this.charProperty2);
+        out.writeObject(this.children);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.charProperty1 = (String)in.readObject();
+        this.charProperty2 = (String)in.readObject();
+        this.children = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable3.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable3.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable3.java
index 464f121..98c4e2b 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable3.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable3.java
@@ -1,10 +1,15 @@
 package org.apache.cayenne.commitlog.db.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
 import org.apache.cayenne.commitlog.db.Auditable4;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 
 /**
  * Class _Auditable3 was generated by Cayenne.
@@ -12,40 +17,115 @@ import org.apache.cayenne.commitlog.db.Auditable4;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Auditable3 extends CayenneDataObject {
+public abstract class _Auditable3 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> CHAR_PROPERTY1 = Property.create("charProperty1", String.class);
-    public static final Property<String> CHAR_PROPERTY2 = Property.create("charProperty2", String.class);
-    public static final Property<List<Auditable4>> AUDITABLE4S = Property.create("auditable4s", List.class);
+    public static final StringProperty<String> CHAR_PROPERTY1 = PropertyFactory.createString("charProperty1", String.class);
+    public static final StringProperty<String> CHAR_PROPERTY2 = PropertyFactory.createString("charProperty2", String.class);
+    public static final ListProperty<Auditable4> AUDITABLE4S = PropertyFactory.createList("auditable4s", Auditable4.class);
+
+    protected String charProperty1;
+    protected String charProperty2;
+
+    protected Object auditable4s;
 
     public void setCharProperty1(String charProperty1) {
-        writeProperty("charProperty1", charProperty1);
+        beforePropertyWrite("charProperty1", this.charProperty1, charProperty1);
+        this.charProperty1 = charProperty1;
     }
+
     public String getCharProperty1() {
-        return (String)readProperty("charProperty1");
+        beforePropertyRead("charProperty1");
+        return this.charProperty1;
     }
 
     public void setCharProperty2(String charProperty2) {
-        writeProperty("charProperty2", charProperty2);
+        beforePropertyWrite("charProperty2", this.charProperty2, charProperty2);
+        this.charProperty2 = charProperty2;
     }
+
     public String getCharProperty2() {
-        return (String)readProperty("charProperty2");
+        beforePropertyRead("charProperty2");
+        return this.charProperty2;
     }
 
     public void addToAuditable4s(Auditable4 obj) {
         addToManyTarget("auditable4s", obj, true);
     }
+
     public void removeFromAuditable4s(Auditable4 obj) {
         removeToManyTarget("auditable4s", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<Auditable4> getAuditable4s() {
         return (List<Auditable4>)readProperty("auditable4s");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "charProperty1":
+                return this.charProperty1;
+            case "charProperty2":
+                return this.charProperty2;
+            case "auditable4s":
+                return this.auditable4s;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "charProperty1":
+                this.charProperty1 = (String)val;
+                break;
+            case "charProperty2":
+                this.charProperty2 = (String)val;
+                break;
+            case "auditable4s":
+                this.auditable4s = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.charProperty1);
+        out.writeObject(this.charProperty2);
+        out.writeObject(this.auditable4s);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.charProperty1 = (String)in.readObject();
+        this.charProperty2 = (String)in.readObject();
+        this.auditable4s = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable4.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable4.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable4.java
index 23aa652..a39fda5 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable4.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_Auditable4.java
@@ -1,8 +1,14 @@
 package org.apache.cayenne.commitlog.db.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
 import org.apache.cayenne.commitlog.db.Auditable3;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 
 /**
  * Class _Auditable4 was generated by Cayenne.
@@ -10,28 +16,39 @@ import org.apache.cayenne.commitlog.db.Auditable3;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Auditable4 extends CayenneDataObject {
+public abstract class _Auditable4 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> CHAR_PROPERTY1 = Property.create("charProperty1", String.class);
-    public static final Property<String> CHAR_PROPERTY2 = Property.create("charProperty2", String.class);
-    public static final Property<Auditable3> AUDITABLE3 = Property.create("auditable3", Auditable3.class);
+    public static final StringProperty<String> CHAR_PROPERTY1 = PropertyFactory.createString("charProperty1", String.class);
+    public static final StringProperty<String> CHAR_PROPERTY2 = PropertyFactory.createString("charProperty2", String.class);
+    public static final EntityProperty<Auditable3> AUDITABLE3 = PropertyFactory.createEntity("auditable3", Auditable3.class);
+
+    protected String charProperty1;
+    protected String charProperty2;
+
+    protected Object auditable3;
 
     public void setCharProperty1(String charProperty1) {
-        writeProperty("charProperty1", charProperty1);
+        beforePropertyWrite("charProperty1", this.charProperty1, charProperty1);
+        this.charProperty1 = charProperty1;
     }
+
     public String getCharProperty1() {
-        return (String)readProperty("charProperty1");
+        beforePropertyRead("charProperty1");
+        return this.charProperty1;
     }
 
     public void setCharProperty2(String charProperty2) {
-        writeProperty("charProperty2", charProperty2);
+        beforePropertyWrite("charProperty2", this.charProperty2, charProperty2);
+        this.charProperty2 = charProperty2;
     }
+
     public String getCharProperty2() {
-        return (String)readProperty("charProperty2");
+        beforePropertyRead("charProperty2");
+        return this.charProperty2;
     }
 
     public void setAuditable3(Auditable3 auditable3) {
@@ -42,5 +59,67 @@ public abstract class _Auditable4 extends CayenneDataObject {
         return (Auditable3)readProperty("auditable3");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "charProperty1":
+                return this.charProperty1;
+            case "charProperty2":
+                return this.charProperty2;
+            case "auditable3":
+                return this.auditable3;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "charProperty1":
+                this.charProperty1 = (String)val;
+                break;
+            case "charProperty2":
+                this.charProperty2 = (String)val;
+                break;
+            case "auditable3":
+                this.auditable3 = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.charProperty1);
+        out.writeObject(this.charProperty2);
+        out.writeObject(this.auditable3);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.charProperty1 = (String)in.readObject();
+        this.charProperty2 = (String)in.readObject();
+        this.auditable3 = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditableChild1.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditableChild1.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditableChild1.java
index bc53ce4..e400898 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditableChild1.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditableChild1.java
@@ -1,8 +1,14 @@
 package org.apache.cayenne.commitlog.db.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
 import org.apache.cayenne.commitlog.db.Auditable1;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 
 /**
  * Class _AuditableChild1 was generated by Cayenne.
@@ -10,20 +16,27 @@ import org.apache.cayenne.commitlog.db.Auditable1;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _AuditableChild1 extends CayenneDataObject {
+public abstract class _AuditableChild1 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> CHAR_PROPERTY1 = Property.create("charProperty1", String.class);
-    public static final Property<Auditable1> PARENT = Property.create("parent", Auditable1.class);
+    public static final StringProperty<String> CHAR_PROPERTY1 = PropertyFactory.createString("charProperty1", String.class);
+    public static final EntityProperty<Auditable1> PARENT = PropertyFactory.createEntity("parent", Auditable1.class);
+
+    protected String charProperty1;
+
+    protected Object parent;
 
     public void setCharProperty1(String charProperty1) {
-        writeProperty("charProperty1", charProperty1);
+        beforePropertyWrite("charProperty1", this.charProperty1, charProperty1);
+        this.charProperty1 = charProperty1;
     }
+
     public String getCharProperty1() {
-        return (String)readProperty("charProperty1");
+        beforePropertyRead("charProperty1");
+        return this.charProperty1;
     }
 
     public void setParent(Auditable1 parent) {
@@ -34,5 +47,60 @@ public abstract class _AuditableChild1 extends CayenneDataObject {
         return (Auditable1)readProperty("parent");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "charProperty1":
+                return this.charProperty1;
+            case "parent":
+                return this.parent;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "charProperty1":
+                this.charProperty1 = (String)val;
+                break;
+            case "parent":
+                this.parent = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.charProperty1);
+        out.writeObject(this.parent);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.charProperty1 = (String)in.readObject();
+        this.parent = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditableChild3.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditableChild3.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditableChild3.java
index c09b035..1a23f3a 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditableChild3.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_AuditableChild3.java
@@ -1,8 +1,14 @@
 package org.apache.cayenne.commitlog.db.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
 import org.apache.cayenne.commitlog.db.Auditable2;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 
 /**
  * Class _AuditableChild3 was generated by Cayenne.
@@ -10,28 +16,39 @@ import org.apache.cayenne.commitlog.db.Auditable2;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _AuditableChild3 extends CayenneDataObject {
+public abstract class _AuditableChild3 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<String> CHAR_PROPERTY1 = Property.create("charProperty1", String.class);
-    public static final Property<String> CHAR_PROPERTY2 = Property.create("charProperty2", String.class);
-    public static final Property<Auditable2> PARENT = Property.create("parent", Auditable2.class);
+    public static final StringProperty<String> CHAR_PROPERTY1 = PropertyFactory.createString("charProperty1", String.class);
+    public static final StringProperty<String> CHAR_PROPERTY2 = PropertyFactory.createString("charProperty2", String.class);
+    public static final EntityProperty<Auditable2> PARENT = PropertyFactory.createEntity("parent", Auditable2.class);
+
+    protected String charProperty1;
+    protected String charProperty2;
+
+    protected Object parent;
 
     public void setCharProperty1(String charProperty1) {
-        writeProperty("charProperty1", charProperty1);
+        beforePropertyWrite("charProperty1", this.charProperty1, charProperty1);
+        this.charProperty1 = charProperty1;
     }
+
     public String getCharProperty1() {
-        return (String)readProperty("charProperty1");
+        beforePropertyRead("charProperty1");
+        return this.charProperty1;
     }
 
     public void setCharProperty2(String charProperty2) {
-        writeProperty("charProperty2", charProperty2);
+        beforePropertyWrite("charProperty2", this.charProperty2, charProperty2);
+        this.charProperty2 = charProperty2;
     }
+
     public String getCharProperty2() {
-        return (String)readProperty("charProperty2");
+        beforePropertyRead("charProperty2");
+        return this.charProperty2;
     }
 
     public void setParent(Auditable2 parent) {
@@ -42,5 +59,67 @@ public abstract class _AuditableChild3 extends CayenneDataObject {
         return (Auditable2)readProperty("parent");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "charProperty1":
+                return this.charProperty1;
+            case "charProperty2":
+                return this.charProperty2;
+            case "parent":
+                return this.parent;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "charProperty1":
+                this.charProperty1 = (String)val;
+                break;
+            case "charProperty2":
+                this.charProperty2 = (String)val;
+                break;
+            case "parent":
+                this.parent = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.charProperty1);
+        out.writeObject(this.charProperty2);
+        out.writeObject(this.parent);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.charProperty1 = (String)in.readObject();
+        this.charProperty2 = (String)in.readObject();
+        this.parent = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E1.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E1.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E1.java
index 74fe998..3ec47e2 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E1.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E1.java
@@ -1,6 +1,10 @@
 package org.apache.cayenne.commitlog.db.auto;
 
-import org.apache.cayenne.CayenneDataObject;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
 
 /**
  * Class _E1 was generated by Cayenne.
@@ -8,11 +12,55 @@ import org.apache.cayenne.CayenneDataObject;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _E1 extends CayenneDataObject {
+public abstract class _E1 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
 
+
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E2.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E2.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E2.java
index 89d9852..33a8bee 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E2.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E2.java
@@ -1,6 +1,10 @@
 package org.apache.cayenne.commitlog.db.auto;
 
-import org.apache.cayenne.CayenneDataObject;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
 
 /**
  * Class _E2 was generated by Cayenne.
@@ -8,11 +12,55 @@ import org.apache.cayenne.CayenneDataObject;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _E2 extends CayenneDataObject {
+public abstract class _E2 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
 
+
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E3.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E3.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E3.java
index 99fe863..2160b8f 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E3.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E3.java
@@ -1,10 +1,14 @@
 package org.apache.cayenne.commitlog.db.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
 import org.apache.cayenne.commitlog.db.E4;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
 
 /**
  * Class _E3 was generated by Cayenne.
@@ -12,24 +16,77 @@ import org.apache.cayenne.commitlog.db.E4;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _E3 extends CayenneDataObject {
+public abstract class _E3 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<List<E4>> E4S = Property.create("e4s", List.class);
+    public static final ListProperty<E4> E4S = PropertyFactory.createList("e4s", E4.class);
+
+
+    protected Object e4s;
 
     public void addToE4s(E4 obj) {
         addToManyTarget("e4s", obj, true);
     }
+
     public void removeFromE4s(E4 obj) {
         removeToManyTarget("e4s", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<E4> getE4s() {
         return (List<E4>)readProperty("e4s");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "e4s":
+                return this.e4s;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "e4s":
+                this.e4s = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.e4s);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.e4s = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E4.java
----------------------------------------------------------------------
diff --git a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E4.java b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E4.java
index c2cefdc..22e4621 100644
--- a/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E4.java
+++ b/cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/db/auto/_E4.java
@@ -1,10 +1,14 @@
 package org.apache.cayenne.commitlog.db.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
 import org.apache.cayenne.commitlog.db.E3;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
 
 /**
  * Class _E4 was generated by Cayenne.
@@ -12,24 +16,77 @@ import org.apache.cayenne.commitlog.db.E3;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _E4 extends CayenneDataObject {
+public abstract class _E4 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<List<E3>> E3S = Property.create("e3s", List.class);
+    public static final ListProperty<E3> E3S = PropertyFactory.createList("e3s", E3.class);
+
+
+    protected Object e3s;
 
     public void addToE3s(E3 obj) {
         addToManyTarget("e3s", obj, true);
     }
+
     public void removeFromE3s(E3 obj) {
         removeToManyTarget("e3s", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<E3> getE3s() {
         return (List<E3>)readProperty("e3s");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "e3s":
+                return this.e3s;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "e3s":
+                this.e3s = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.e3s);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.e3s = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_DateTimeTestEntity.java
----------------------------------------------------------------------
diff --git a/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_DateTimeTestEntity.java b/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_DateTimeTestEntity.java
index 2fd9d91..9138bdc 100644
--- a/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_DateTimeTestEntity.java
+++ b/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_DateTimeTestEntity.java
@@ -1,7 +1,12 @@
 package org.apache.cayenne.joda.db.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.BaseProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
 import org.joda.time.DateTime;
 
 /**
@@ -10,19 +15,74 @@ import org.joda.time.DateTime;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _DateTimeTestEntity extends CayenneDataObject {
+public abstract class _DateTimeTestEntity extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<DateTime> TIMESTAMP = Property.create("timestamp", DateTime.class);
+    public static final BaseProperty<DateTime> TIMESTAMP = PropertyFactory.createBase("timestamp", DateTime.class);
+
+    protected DateTime timestamp;
+
 
     public void setTimestamp(DateTime timestamp) {
-        writeProperty("timestamp", timestamp);
+        beforePropertyWrite("timestamp", this.timestamp, timestamp);
+        this.timestamp = timestamp;
     }
+
     public DateTime getTimestamp() {
-        return (DateTime)readProperty("timestamp");
+        beforePropertyRead("timestamp");
+        return this.timestamp;
+    }
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "timestamp":
+                return this.timestamp;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "timestamp":
+                this.timestamp = (DateTime)val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.timestamp);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.timestamp = (DateTime)in.readObject();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalDateTestEntity.java
----------------------------------------------------------------------
diff --git a/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalDateTestEntity.java b/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalDateTestEntity.java
index 72c60dd..2542bd3 100644
--- a/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalDateTestEntity.java
+++ b/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalDateTestEntity.java
@@ -1,7 +1,12 @@
 package org.apache.cayenne.joda.db.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.BaseProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
 import org.joda.time.LocalDate;
 
 /**
@@ -10,19 +15,74 @@ import org.joda.time.LocalDate;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _LocalDateTestEntity extends CayenneDataObject {
+public abstract class _LocalDateTestEntity extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<LocalDate> DATE = Property.create("date", LocalDate.class);
+    public static final BaseProperty<LocalDate> DATE = PropertyFactory.createBase("date", LocalDate.class);
+
+    protected LocalDate date;
+
 
     public void setDate(LocalDate date) {
-        writeProperty("date", date);
+        beforePropertyWrite("date", this.date, date);
+        this.date = date;
     }
+
     public LocalDate getDate() {
-        return (LocalDate)readProperty("date");
+        beforePropertyRead("date");
+        return this.date;
+    }
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "date":
+                return this.date;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "date":
+                this.date = (LocalDate)val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.date);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.date = (LocalDate)in.readObject();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalDateTimeTestEntity.java
----------------------------------------------------------------------
diff --git a/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalDateTimeTestEntity.java b/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalDateTimeTestEntity.java
index bca6b26..ee812ab 100644
--- a/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalDateTimeTestEntity.java
+++ b/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalDateTimeTestEntity.java
@@ -1,7 +1,12 @@
 package org.apache.cayenne.joda.db.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.BaseProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
 import org.joda.time.LocalDateTime;
 
 /**
@@ -10,19 +15,74 @@ import org.joda.time.LocalDateTime;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _LocalDateTimeTestEntity extends CayenneDataObject {
+public abstract class _LocalDateTimeTestEntity extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<LocalDateTime> TIMESTAMP = Property.create("timestamp", LocalDateTime.class);
+    public static final BaseProperty<LocalDateTime> TIMESTAMP = PropertyFactory.createBase("timestamp", LocalDateTime.class);
+
+    protected LocalDateTime timestamp;
+
 
     public void setTimestamp(LocalDateTime timestamp) {
-        writeProperty("timestamp", timestamp);
+        beforePropertyWrite("timestamp", this.timestamp, timestamp);
+        this.timestamp = timestamp;
     }
+
     public LocalDateTime getTimestamp() {
-        return (LocalDateTime)readProperty("timestamp");
+        beforePropertyRead("timestamp");
+        return this.timestamp;
+    }
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "timestamp":
+                return this.timestamp;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "timestamp":
+                this.timestamp = (LocalDateTime)val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.timestamp);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.timestamp = (LocalDateTime)in.readObject();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalTimeTestEntity.java
----------------------------------------------------------------------
diff --git a/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalTimeTestEntity.java b/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalTimeTestEntity.java
index 422ceec..903f244 100644
--- a/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalTimeTestEntity.java
+++ b/cayenne-joda/src/test/java/org/apache/cayenne/joda/db/auto/_LocalTimeTestEntity.java
@@ -1,7 +1,12 @@
 package org.apache.cayenne.joda.db.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.BaseProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
 import org.joda.time.LocalTime;
 
 /**
@@ -10,19 +15,74 @@ import org.joda.time.LocalTime;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _LocalTimeTestEntity extends CayenneDataObject {
+public abstract class _LocalTimeTestEntity extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<LocalTime> TIME = Property.create("time", LocalTime.class);
+    public static final BaseProperty<LocalTime> TIME = PropertyFactory.createBase("time", LocalTime.class);
+
+    protected LocalTime time;
+
 
     public void setTime(LocalTime time) {
-        writeProperty("time", time);
+        beforePropertyWrite("time", this.time, time);
+        this.time = time;
     }
+
     public LocalTime getTime() {
-        return (LocalTime)readProperty("time");
+        beforePropertyRead("time");
+        return this.time;
+    }
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "time":
+                return this.time;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "time":
+                this.time = (LocalTime)val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.time);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.time = (LocalTime)in.readObject();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_MtTable1.java
----------------------------------------------------------------------
diff --git a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_MtTable1.java b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_MtTable1.java
index b512ac0..97537bf 100644
--- a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_MtTable1.java
+++ b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_MtTable1.java
@@ -1,13 +1,19 @@
 package org.apache.cayenne.rop.protostuff.persistent.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.util.Date;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.rop.protostuff.persistent.MtTable2;
 
 /**
@@ -16,72 +22,191 @@ import org.apache.cayenne.rop.protostuff.persistent.MtTable2;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _MtTable1 extends CayenneDataObject {
+public abstract class _MtTable1 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String TABLE1_ID_PK_COLUMN = "TABLE1_ID";
 
-    public static final Property<LocalDate> DATE_ATTRIBUTE = Property.create("dateAttribute", LocalDate.class);
-    public static final Property<String> GLOBAL_ATTRIBUTE = Property.create("globalAttribute", String.class);
-    public static final Property<Date> OLD_DATE_ATTRIBUTE = Property.create("oldDateAttribute", Date.class);
-    public static final Property<String> SERVER_ATTRIBUTE = Property.create("serverAttribute", String.class);
-    public static final Property<LocalTime> TIME_ATTRIBUTE = Property.create("timeAttribute", LocalTime.class);
-    public static final Property<LocalDateTime> TIMESTAMP_ATTRIBUTE = Property.create("timestampAttribute", LocalDateTime.class);
-    public static final Property<List<MtTable2>> TABLE2ARRAY = Property.create("table2Array", List.class);
+    public static final DateProperty<LocalDate> DATE_ATTRIBUTE = PropertyFactory.createDate("dateAttribute", LocalDate.class);
+    public static final StringProperty<String> GLOBAL_ATTRIBUTE = PropertyFactory.createString("globalAttribute", String.class);
+    public static final DateProperty<Date> OLD_DATE_ATTRIBUTE = PropertyFactory.createDate("oldDateAttribute", Date.class);
+    public static final StringProperty<String> SERVER_ATTRIBUTE = PropertyFactory.createString("serverAttribute", String.class);
+    public static final DateProperty<LocalTime> TIME_ATTRIBUTE = PropertyFactory.createDate("timeAttribute", LocalTime.class);
+    public static final DateProperty<LocalDateTime> TIMESTAMP_ATTRIBUTE = PropertyFactory.createDate("timestampAttribute", LocalDateTime.class);
+    public static final ListProperty<MtTable2> TABLE2ARRAY = PropertyFactory.createList("table2Array", MtTable2.class);
+
+    protected LocalDate dateAttribute;
+    protected String globalAttribute;
+    protected Date oldDateAttribute;
+    protected String serverAttribute;
+    protected LocalTime timeAttribute;
+    protected LocalDateTime timestampAttribute;
+
+    protected Object table2Array;
 
     public void setDateAttribute(LocalDate dateAttribute) {
-        writeProperty("dateAttribute", dateAttribute);
+        beforePropertyWrite("dateAttribute", this.dateAttribute, dateAttribute);
+        this.dateAttribute = dateAttribute;
     }
+
     public LocalDate getDateAttribute() {
-        return (LocalDate)readProperty("dateAttribute");
+        beforePropertyRead("dateAttribute");
+        return this.dateAttribute;
     }
 
     public void setGlobalAttribute(String globalAttribute) {
-        writeProperty("globalAttribute", globalAttribute);
+        beforePropertyWrite("globalAttribute", this.globalAttribute, globalAttribute);
+        this.globalAttribute = globalAttribute;
     }
+
     public String getGlobalAttribute() {
-        return (String)readProperty("globalAttribute");
+        beforePropertyRead("globalAttribute");
+        return this.globalAttribute;
     }
 
     public void setOldDateAttribute(Date oldDateAttribute) {
-        writeProperty("oldDateAttribute", oldDateAttribute);
+        beforePropertyWrite("oldDateAttribute", this.oldDateAttribute, oldDateAttribute);
+        this.oldDateAttribute = oldDateAttribute;
     }
+
     public Date getOldDateAttribute() {
-        return (Date)readProperty("oldDateAttribute");
+        beforePropertyRead("oldDateAttribute");
+        return this.oldDateAttribute;
     }
 
     public void setServerAttribute(String serverAttribute) {
-        writeProperty("serverAttribute", serverAttribute);
+        beforePropertyWrite("serverAttribute", this.serverAttribute, serverAttribute);
+        this.serverAttribute = serverAttribute;
     }
+
     public String getServerAttribute() {
-        return (String)readProperty("serverAttribute");
+        beforePropertyRead("serverAttribute");
+        return this.serverAttribute;
     }
 
     public void setTimeAttribute(LocalTime timeAttribute) {
-        writeProperty("timeAttribute", timeAttribute);
+        beforePropertyWrite("timeAttribute", this.timeAttribute, timeAttribute);
+        this.timeAttribute = timeAttribute;
     }
+
     public LocalTime getTimeAttribute() {
-        return (LocalTime)readProperty("timeAttribute");
+        beforePropertyRead("timeAttribute");
+        return this.timeAttribute;
     }
 
     public void setTimestampAttribute(LocalDateTime timestampAttribute) {
-        writeProperty("timestampAttribute", timestampAttribute);
+        beforePropertyWrite("timestampAttribute", this.timestampAttribute, timestampAttribute);
+        this.timestampAttribute = timestampAttribute;
     }
+
     public LocalDateTime getTimestampAttribute() {
-        return (LocalDateTime)readProperty("timestampAttribute");
+        beforePropertyRead("timestampAttribute");
+        return this.timestampAttribute;
     }
 
     public void addToTable2Array(MtTable2 obj) {
         addToManyTarget("table2Array", obj, true);
     }
+
     public void removeFromTable2Array(MtTable2 obj) {
         removeToManyTarget("table2Array", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<MtTable2> getTable2Array() {
         return (List<MtTable2>)readProperty("table2Array");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "dateAttribute":
+                return this.dateAttribute;
+            case "globalAttribute":
+                return this.globalAttribute;
+            case "oldDateAttribute":
+                return this.oldDateAttribute;
+            case "serverAttribute":
+                return this.serverAttribute;
+            case "timeAttribute":
+                return this.timeAttribute;
+            case "timestampAttribute":
+                return this.timestampAttribute;
+            case "table2Array":
+                return this.table2Array;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "dateAttribute":
+                this.dateAttribute = (LocalDate)val;
+                break;
+            case "globalAttribute":
+                this.globalAttribute = (String)val;
+                break;
+            case "oldDateAttribute":
+                this.oldDateAttribute = (Date)val;
+                break;
+            case "serverAttribute":
+                this.serverAttribute = (String)val;
+                break;
+            case "timeAttribute":
+                this.timeAttribute = (LocalTime)val;
+                break;
+            case "timestampAttribute":
+                this.timestampAttribute = (LocalDateTime)val;
+                break;
+            case "table2Array":
+                this.table2Array = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.dateAttribute);
+        out.writeObject(this.globalAttribute);
+        out.writeObject(this.oldDateAttribute);
+        out.writeObject(this.serverAttribute);
+        out.writeObject(this.timeAttribute);
+        out.writeObject(this.timestampAttribute);
+        out.writeObject(this.table2Array);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.dateAttribute = (LocalDate)in.readObject();
+        this.globalAttribute = (String)in.readObject();
+        this.oldDateAttribute = (Date)in.readObject();
+        this.serverAttribute = (String)in.readObject();
+        this.timeAttribute = (LocalTime)in.readObject();
+        this.timestampAttribute = (LocalDateTime)in.readObject();
+        this.table2Array = in.readObject();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2cca2445/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_MtTable2.java
----------------------------------------------------------------------
diff --git a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_MtTable2.java b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_MtTable2.java
index 68ab205..3e3ec94 100644
--- a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_MtTable2.java
+++ b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_MtTable2.java
@@ -1,7 +1,13 @@
 package org.apache.cayenne.rop.protostuff.persistent.auto;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.rop.protostuff.persistent.MtTable1;
 
 /**
@@ -10,20 +16,27 @@ import org.apache.cayenne.rop.protostuff.persistent.MtTable1;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _MtTable2 extends CayenneDataObject {
+public abstract class _MtTable2 extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String TABLE2_ID_PK_COLUMN = "TABLE2_ID";
 
-    public static final Property<String> GLOBAL_ATTRIBUTE = Property.create("globalAttribute", String.class);
-    public static final Property<MtTable1> TABLE1 = Property.create("table1", MtTable1.class);
+    public static final StringProperty<String> GLOBAL_ATTRIBUTE = PropertyFactory.createString("globalAttribute", String.class);
+    public static final EntityProperty<MtTable1> TABLE1 = PropertyFactory.createEntity("table1", MtTable1.class);
+
+    protected String globalAttribute;
+
+    protected Object table1;
 
     public void setGlobalAttribute(String globalAttribute) {
-        writeProperty("globalAttribute", globalAttribute);
+        beforePropertyWrite("globalAttribute", this.globalAttribute, globalAttribute);
+        this.globalAttribute = globalAttribute;
     }
+
     public String getGlobalAttribute() {
-        return (String)readProperty("globalAttribute");
+        beforePropertyRead("globalAttribute");
+        return this.globalAttribute;
     }
 
     public void setTable1(MtTable1 table1) {
@@ -34,5 +47,60 @@ public abstract class _MtTable2 extends CayenneDataObject {
         return (MtTable1)readProperty("table1");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "globalAttribute":
+                return this.globalAttribute;
+            case "table1":
+                return this.table1;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "globalAttribute":
+                this.globalAttribute = (String)val;
+                break;
+            case "table1":
+                this.table1 = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.globalAttribute);
+        out.writeObject(this.table1);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.globalAttribute = (String)in.readObject();
+        this.table1 = in.readObject();
+    }
 
 }


[3/4] cayenne git commit: CAY-2467 New type-aware Property API - update client cgen templates - update client tests

Posted by nt...@apache.org.
CAY-2467 New type-aware Property API
  - update client cgen templates
  - update client tests


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/63a32d82
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/63a32d82
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/63a32d82

Branch: refs/heads/master
Commit: 63a32d8248301829617ef6cac3fda2313b281dfd
Parents: 56b64c3
Author: Nikita Timofeev <st...@gmail.com>
Authored: Fri Dec 28 14:51:58 2018 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Fri Dec 28 14:51:58 2018 +0300

----------------------------------------------------------------------
 .../org/apache/cayenne/gen/PropertyUtils.java   |  71 ++--
 .../templates/v4_1/client-superclass.vm         |  27 +-
 .../gen/ClientSuperClassGenerationTest.java     |  23 +-
 .../cayenne/gen/SuperClassGenerationTest.java   |   3 -
 .../org/apache/cayenne/CayenneContextIT.java    |   2 +-
 .../cayenne/CayenneContextInheritanceIT.java    |  42 +-
 .../cayenne/CayenneContextMergeHandlerIT.java   |   8 +-
 .../CayenneContextPaginatedListCachingIT.java   |   8 +-
 .../CayenneContextWithDataContextIT.java        | 178 ++++-----
 .../apache/cayenne/NestedCayenneContextIT.java  | 380 ++++++++-----------
 .../cayenne/access/ClientServerChannelIT.java   |  64 ++--
 .../access/ClientServerChannelQueryIT.java      |  26 +-
 .../cayenne/query/ClientExpressionIT.java       |  96 ++---
 .../query/ClientSelectQueryExpressionIT.java    |   5 +-
 .../remote/ClientChannelServerDiffsIT.java      |   4 +-
 .../remote/RemoteIncrementalFaultListIT.java    |  33 +-
 .../persistent/auto/_ClientMtTable1.java        |  19 +-
 .../persistent/auto/_ClientMtTable2.java        |   9 +-
 .../org/apache/cayenne/access/EmbeddingIT.java  |  17 +
 .../cayenne/testdo/mt/auto/_ClientMtTable1.java |  40 +-
 .../mt/auto/_ClientMtTable1Subclass1.java       |  16 +-
 .../mt/auto/_ClientMtTable1Subclass2.java       |  16 +-
 .../cayenne/testdo/mt/auto/_ClientMtTable2.java |  44 ++-
 .../cayenne/testdo/mt/auto/_ClientMtTable3.java |  52 +--
 .../cayenne/testdo/mt/auto/_ClientMtTable4.java |  19 +-
 .../cayenne/testdo/mt/auto/_ClientMtTable5.java |  19 +-
 .../util/PersistentObjectHolderTest.java        |   4 +-
 .../persistent/client/auto/_Artist.java         |  35 +-
 .../persistent/client/auto/_Gallery.java        |  24 +-
 .../persistent/client/auto/_Painting.java       |  52 +--
 .../persistent/client/auto/_Artist.java         |  41 +-
 .../persistent/client/auto/_Gallery.java        |  24 +-
 .../persistent/client/auto/_Painting.java       |  52 +--
 .../tutorial/persistent/auto/_Artist.java       | 101 ++++-
 .../tutorial/persistent/auto/_Gallery.java      |  83 +++-
 .../tutorial/persistent/auto/_Painting.java     |  93 ++++-
 .../persistent/client/auto/_Artist.java         |  35 +-
 .../persistent/client/auto/_Gallery.java        |  24 +-
 .../persistent/client/auto/_Painting.java       |  50 +--
 .../tutorial/persistent/auto/_Artist.java       | 101 ++++-
 .../tutorial/persistent/auto/_Gallery.java      |  83 +++-
 .../tutorial/persistent/auto/_Painting.java     |  93 ++++-
 .../persistent/client/auto/_Artist.java         |  35 +-
 .../persistent/client/auto/_Gallery.java        |  24 +-
 .../persistent/client/auto/_Painting.java       |  50 +--
 .../tutorial/persistent/auto/_Artist.java       |  11 +-
 .../tutorial/persistent/auto/_Gallery.java      |   8 +-
 .../tutorial/persistent/auto/_Painting.java     |  10 +-
 48 files changed, 1287 insertions(+), 967 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-cgen/src/main/java/org/apache/cayenne/gen/PropertyUtils.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/PropertyUtils.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/PropertyUtils.java
index 4d45db6..d79d502 100644
--- a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/PropertyUtils.java
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/PropertyUtils.java
@@ -100,9 +100,16 @@ public class PropertyUtils {
     }
 
     public void addImport(ObjRelationship relationship) {
+        addImport(relationship, false);
+    }
+
+    public void addImport(ObjRelationship relationship, boolean client) {
         importUtils.addType(PropertyFactory.class.getName());
-        if (relationship.getTargetEntityName() != null && relationship.getTargetEntity() != null) {
-            importUtils.addType(relationship.getTargetEntity().getClassName());
+        if (relationship.getTargetEntity() != null) {
+            importUtils.addType(client
+                    ? relationship.getTargetEntity().getClientClassName()
+                    : relationship.getTargetEntity().getClassName())
+            ;
         } else {
             importUtils.addType(Persistent.class.getName());
         }
@@ -152,7 +159,7 @@ public class PropertyUtils {
         return BaseProperty.class.getName();
     }
 
-    public String propertyDefinition(ObjAttribute attribute) {
+    public String propertyDefinition(ObjAttribute attribute, boolean client) {
         StringUtils utils = StringUtils.getInstance();
 
         String propertyType = getPropertyTypeForAttribute(attribute);
@@ -169,52 +176,56 @@ public class PropertyUtils {
         );
     }
 
-    public String propertyDefinition(ObjRelationship relationship) {
+    public String propertyDefinition(ObjAttribute attribute) {
+        return propertyDefinition(attribute, false);
+    }
+
+    public String propertyDefinition(ObjRelationship relationship, boolean client) {
         if (relationship.isToMany()) {
-            return toManyRelationshipDefinition(relationship);
+            return toManyRelationshipDefinition(relationship, client);
         } else {
-            return toOneRelationshipDefinition(relationship);
+            return toOneRelationshipDefinition(relationship, client);
         }
     }
 
-    private String toManyRelationshipDefinition(ObjRelationship relationship) {
+    public String propertyDefinition(ObjRelationship relationship) {
+        return propertyDefinition(relationship, false);
+    }
+
+    private String toManyRelationshipDefinition(ObjRelationship relationship, boolean client) {
         if (Map.class.getName().equals(relationship.getCollectionType())) {
-            return mapRelationshipDefinition(relationship);
+            return mapRelationshipDefinition(relationship, client);
         } else {
-            return collectionRelationshipDefinition(relationship);
+            return collectionRelationshipDefinition(relationship, client);
         }
     }
 
-    private String mapRelationshipDefinition(ObjRelationship relationship) {
+    private String mapRelationshipDefinition(ObjRelationship relationship, boolean client) {
         StringUtils utils = StringUtils.getInstance();
 
         String propertyType = getPropertyTypeForJavaClass(relationship);
         String propertyFactoryMethod = factoryMethodForPropertyType(propertyType);
-        String mapKeyType = EntityUtils.getMapKeyTypeInternal(relationship);
-        String attributeType = relationship.getTargetEntity() == null
-                ? Persistent.class.getSimpleName()
-                : relationship.getTargetEntity().getClassName();
+        String mapKeyType = importUtils.formatJavaType(EntityUtils.getMapKeyTypeInternal(relationship));
+        String attributeType = getRelatedTypeName(relationship, client);
 
         return String.format("public static final %s<%s, %s> %s = PropertyFactory.%s(\"%s\", %s.class, %s.class);",
                 importUtils.formatJavaType(propertyType),
-                importUtils.formatJavaType(mapKeyType),
-                importUtils.formatJavaType(attributeType),
+                mapKeyType,
+                attributeType,
                 utils.capitalizedAsConstant(relationship.getName()),
                 propertyFactoryMethod,
                 relationship.getName(),
-                importUtils.formatJavaType(mapKeyType),
-                importUtils.formatJavaType(attributeType)
+                mapKeyType,
+                attributeType
         );
     }
 
-    private String collectionRelationshipDefinition(ObjRelationship relationship) {
+    private String collectionRelationshipDefinition(ObjRelationship relationship, boolean client) {
         StringUtils utils = StringUtils.getInstance();
 
         String propertyType = getPropertyTypeForJavaClass(relationship);
         String propertyFactoryMethod = factoryMethodForPropertyType(propertyType);
-        String entityType = importUtils.formatJavaType(relationship.getTargetEntity() == null
-                ? Persistent.class.getSimpleName()
-                : relationship.getTargetEntity().getClassName());
+        String entityType = getRelatedTypeName(relationship, client);
 
         return String.format("public static final %s<%s> %s = PropertyFactory.%s(\"%s\", %s.class);",
                 importUtils.formatJavaType(propertyType),
@@ -226,14 +237,22 @@ public class PropertyUtils {
         );
     }
 
-    private String toOneRelationshipDefinition(ObjRelationship relationship) {
+    private String getRelatedTypeName(ObjRelationship relationship, boolean client) {
+        if(relationship.getTargetEntity() == null) {
+            return Persistent.class.getSimpleName();
+        }
+
+        return importUtils.formatJavaType(client
+                ? relationship.getTargetEntity().getClientClassName()
+                : relationship.getTargetEntity().getClassName());
+    }
+
+    private String toOneRelationshipDefinition(ObjRelationship relationship, boolean client) {
         StringUtils utils = StringUtils.getInstance();
 
         String propertyType = EntityProperty.class.getName();
         String propertyFactoryMethod = "createEntity";
-        String attributeType = (relationship.getTargetEntityName() == null || relationship.getTargetEntity() == null)
-                ? Persistent.class.getSimpleName()
-                : importUtils.formatJavaType(relationship.getTargetEntity().getClassName());
+        String attributeType = getRelatedTypeName(relationship, client);
 
         return String.format("public static final %s<%s> %s = PropertyFactory.%s(\"%s\", %s.class);",
                 importUtils.formatJavaType(propertyType),

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-cgen/src/main/resources/templates/v4_1/client-superclass.vm
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/resources/templates/v4_1/client-superclass.vm b/cayenne-cgen/src/main/resources/templates/v4_1/client-superclass.vm
index 5d21ba0..a70336e 100644
--- a/cayenne-cgen/src/main/resources/templates/v4_1/client-superclass.vm
+++ b/cayenne-cgen/src/main/resources/templates/v4_1/client-superclass.vm
@@ -36,17 +36,11 @@
 ${importUtils.setPackage($superPackageName)}##
 ${importUtils.addReservedType("${$superPackageName}.${superClassName}")}##
 ${importUtils.addType("${basePackageName}.${baseClassName}")}##
-#if((${object.DeclaredAttributes} && !${object.DeclaredAttributes.isEmpty()}) || (${object.DeclaredRelationships} && !${object.DeclaredRelationships.isEmpty()}))
-${importUtils.addType('org.apache.cayenne.exp.Property')}##
-#end
 #foreach( $attr in ${object.DeclaredAttributes} )
-$importUtils.addType(${attr.Type})##
+$propertyUtils.addImport($attr)##
 #end
 #foreach( $rel in ${object.DeclaredRelationships} )
-$importUtils.addType(${rel.TargetEntity.ClientClassName})##
-#if(${rel.CollectionType}) 
-$importUtils.addType(${rel.CollectionType})##
-#end
+$propertyUtils.addImport($rel, true)##
 #end
 #if( ${entityUtils.hasToOneDeclaredRelationships()} )
 ${importUtils.addType('org.apache.cayenne.ValueHolder')}##
@@ -76,22 +70,10 @@ public abstract class ${superClassName} extends ${baseClassName} {
 #end
 ## Create Properties
 #foreach( $attr in ${object.DeclaredAttributes} )
-    #set ( $type = "$importUtils.formatJavaType(${attr.Type}, false)" )
-    public static final Property<$type> ${stringUtils.capitalizedAsConstant($attr.Name)} = Property.create("${attr.Name}", ${stringUtils.stripGeneric($type)}.class);
+    $propertyUtils.propertyDefinition($attr, true)
 #end
 #foreach( $rel in ${object.DeclaredRelationships} )
-#if( $rel.ToMany )
-#if ( ${rel.CollectionType} == "java.util.Map")
-    #set( $type = "$importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($entityUtils.getMapKeyType($rel)), $importUtils.formatJavaType($rel.TargetEntity.ClientClassName)>" )
-    public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
-#else
-    #set( $type = "$importUtils.formatJavaType($rel.CollectionType)<$importUtils.formatJavaType($rel.TargetEntity.ClientClassName)>" )
-    public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
-#end
-#else
-    #set( $type = "$importUtils.formatJavaType(${rel.TargetEntity.ClientClassName})" )
-    public static final Property<$type> ${stringUtils.capitalizedAsConstant($rel.Name)} = Property.create("${rel.Name}", ${stringUtils.stripGeneric($type)}.class);
-#end
+    $propertyUtils.propertyDefinition($rel, true)
 #end
 
 ## Create ivars
@@ -228,7 +210,6 @@ public abstract class ${superClassName} extends ${baseClassName} {
     public void set${stringUtils.capitalized($rel.Name)}(${importUtils.formatJavaType($rel.TargetEntity.ClientClassName)} $relName) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "$rel.Name", true);
-            objectContext.propertyChanged(this, "$rel.Name", this.${relName}.getValueDirectly(), $relName);
         } else if (this.$relName == null) {
         	this.$relName = new PersistentObjectHolder<>(this, "$rel.Name");
 		}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClientSuperClassGenerationTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClientSuperClassGenerationTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClientSuperClassGenerationTest.java
index b690367..083ff50 100644
--- a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClientSuperClassGenerationTest.java
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClientSuperClassGenerationTest.java
@@ -38,20 +38,25 @@ public class ClientSuperClassGenerationTest extends ClassGenerationCase {
         context.put(Artifact.OBJECT_KEY, objEntity);
 
         String res = renderTemplate(ClientClassGenerationAction.SUPERCLASS_TEMPLATE, context);
-        assertFalse(res.contains("org.apache.cayenne.exp.Property"));
+        assertFalse(res.contains("org.apache.cayenne.exp.property."));
     }
 
     @Test
     public void testContainsPropertyImportForAttributes() throws Exception {
         ObjEntity objEntity = new ObjEntity("TEST1");
         ObjAttribute attr = new ObjAttribute("attr");
+        attr.setType("int");
         objEntity.addAttribute(attr);
 
         VelocityContext context = new VelocityContext();
+        ImportUtils importUtils = new ImportUtils();
         context.put(Artifact.OBJECT_KEY, objEntity);
+        context.put(Artifact.IMPORT_UTILS_KEY, importUtils);
+        context.put(Artifact.STRING_UTILS_KEY, StringUtils.getInstance());
+        context.put(Artifact.PROPERTY_UTILS_KEY, new PropertyUtils(importUtils));
 
         String res = renderTemplate(ClientClassGenerationAction.SUPERCLASS_TEMPLATE, context);
-        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+        assertTrue(res.contains("org.apache.cayenne.exp.property.NumericProperty"));
     }
 
     @Test
@@ -61,26 +66,36 @@ public class ClientSuperClassGenerationTest extends ClassGenerationCase {
         objEntity.addRelationship(rel);
 
         VelocityContext context = new VelocityContext();
+        ImportUtils importUtils = new ImportUtils();
         context.put(Artifact.OBJECT_KEY, objEntity);
+        context.put(Artifact.IMPORT_UTILS_KEY, importUtils);
+        context.put(Artifact.STRING_UTILS_KEY, StringUtils.getInstance());
+        context.put(Artifact.PROPERTY_UTILS_KEY, new PropertyUtils(importUtils));
 
         String res = renderTemplate(ClientClassGenerationAction.SUPERCLASS_TEMPLATE, context);
-        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+        assertTrue(res.contains("org.apache.cayenne.exp.property.EntityProperty"));
     }
 
     @Test
     public void testContainsPropertyImport() throws Exception {
         ObjEntity objEntity = new ObjEntity("TEST1");
         ObjAttribute attr = new ObjAttribute("attr");
+        attr.setType("int");
         ObjRelationship rel = new ObjRelationship("rel");
 
         objEntity.addAttribute(attr);
         objEntity.addRelationship(rel);
 
         VelocityContext context = new VelocityContext();
+        ImportUtils importUtils = new ImportUtils();
         context.put(Artifact.OBJECT_KEY, objEntity);
+        context.put(Artifact.IMPORT_UTILS_KEY, importUtils);
+        context.put(Artifact.STRING_UTILS_KEY, StringUtils.getInstance());
+        context.put(Artifact.PROPERTY_UTILS_KEY, new PropertyUtils(importUtils));
 
         String res = renderTemplate(ClientClassGenerationAction.SUPERCLASS_TEMPLATE, context);
-        assertTrue(res.contains("org.apache.cayenne.exp.Property"));
+        assertTrue(res.contains("org.apache.cayenne.exp.property.NumericProperty"));
+        assertTrue(res.contains("org.apache.cayenne.exp.property.EntityProperty"));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SuperClassGenerationTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SuperClassGenerationTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SuperClassGenerationTest.java
index 8acaba3..704b01b 100644
--- a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SuperClassGenerationTest.java
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/SuperClassGenerationTest.java
@@ -37,7 +37,6 @@ public class SuperClassGenerationTest extends ClassGenerationCase {
         ObjEntity objEntity = new ObjEntity("TEST1");
 
         VelocityContext context = new VelocityContext();
-        context.put(Artifact.OBJECT_KEY, objEntity);
         ImportUtils importUtils = new ImportUtils();
         context.put(Artifact.OBJECT_KEY, objEntity);
         context.put(Artifact.IMPORT_UTILS_KEY, importUtils);
@@ -57,7 +56,6 @@ public class SuperClassGenerationTest extends ClassGenerationCase {
         objEntity.addAttribute(attr);
 
         VelocityContext context = new VelocityContext();
-        context.put(Artifact.OBJECT_KEY, objEntity);
         ImportUtils importUtils = new ImportUtils();
         context.put(Artifact.OBJECT_KEY, objEntity);
         context.put(Artifact.IMPORT_UTILS_KEY, importUtils);
@@ -76,7 +74,6 @@ public class SuperClassGenerationTest extends ClassGenerationCase {
         objEntity.addRelationship(rel);
 
         VelocityContext context = new VelocityContext();
-        context.put(Artifact.OBJECT_KEY, objEntity);
         ImportUtils importUtils = new ImportUtils();
         context.put(Artifact.OBJECT_KEY, objEntity);
         context.put(Artifact.IMPORT_UTILS_KEY, importUtils);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextIT.java
index cb44912..33bd5e8 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextIT.java
@@ -296,7 +296,7 @@ public class CayenneContextIT extends ClientCase {
 		context.graphManager.registerNode(hollow.getObjectId(), hollow);
 
 		// testing this...
-		context.prepareForAccess(hollow, ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, false);
+		context.prepareForAccess(hollow, ClientMtTable1.GLOBAL_ATTRIBUTE1.getName(), false);
 		assertTrue(selectExecuted[0]);
 		assertSame(hollow, context.getGraphManager().getNode(gid));
 		assertEquals(inflated.getGlobalAttribute1Direct(), hollow.getGlobalAttribute1Direct());

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextInheritanceIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextInheritanceIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextInheritanceIT.java
index 1862616..fc13b66 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextInheritanceIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextInheritanceIT.java
@@ -84,8 +84,8 @@ public class CayenneContextInheritanceIT extends ClientCase {
         tMtTable1.insert(2, "sub1", "zzz", "sa1");
         tMtTable1.insert(3, "1111", "aaa", null);
 
-        SelectQuery query = new SelectQuery(ClientMtTable1Subclass1.class);
-        List<ClientMtTable1Subclass1> objects = context.performQuery(query);
+        SelectQuery<ClientMtTable1Subclass1> query = new SelectQuery<>(ClientMtTable1Subclass1.class);
+        List<ClientMtTable1Subclass1> objects = query.select(context);
 
         assertEquals(1, objects.size());
         assertEquals("sa1", objects.get(0).getSubclass1Attribute1());
@@ -98,22 +98,19 @@ public class CayenneContextInheritanceIT extends ClientCase {
         tMtTable1.insert(2, "sub1", "zzz", "sa1");
         tMtTable1.insert(3, "z", "aaa", null);
 
-        SelectQuery query = new SelectQuery(ClientMtTable1.class);
-        List<ClientMtTable1> objects = context.performQuery(query);
+        SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
+        List<ClientMtTable1> objects = query.select(context);
 
         assertEquals(3, objects.size());
 
         int checkedFields = 0;
-        for (int i = 0; i < objects.size(); i++) {
-            Integer id = (Integer) objects.get(i).getObjectId().getIdSnapshot().get(
-                    "TABLE1_ID");
+        for (ClientMtTable1 object : objects) {
+            Integer id = (Integer) object.getObjectId().getIdSnapshot().get("TABLE1_ID");
             if (id == 1) {
-                assertEquals("a", objects.get(i).getGlobalAttribute1());
+                assertEquals("a", object.getGlobalAttribute1());
                 checkedFields++;
-            }
-            else if (id == 2) {
-                assertEquals("sa1", ((ClientMtTable1Subclass1) objects.get(i))
-                        .getSubclass1Attribute1());
+            } else if (id == 2) {
+                assertEquals("sa1", ((ClientMtTable1Subclass1) object).getSubclass1Attribute1());
                 checkedFields++;
             }
 
@@ -128,25 +125,20 @@ public class CayenneContextInheritanceIT extends ClientCase {
         tMtTable1.insert(2, "sub1", "XXA", "sa1");
         tMtTable1.insert(3, "z", "MM", null);
 
-        SelectQuery query = new SelectQuery(ClientMtTable1.class);
-        query.andQualifier(ExpressionFactory.likeExp(
-                ClientMtTable1.SERVER_ATTRIBUTE1_PROPERTY,
-                "X%"));
-        List<ClientMtTable1> objects = context.performQuery(query);
+        SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
+        query.andQualifier(ClientMtTable1.SERVER_ATTRIBUTE1.like("X%"));
+        List<ClientMtTable1> objects = query.select(context);
 
         assertEquals(2, objects.size());
 
         int checkedFields = 0;
-        for (int i = 0; i < objects.size(); i++) {
-            Integer id = (Integer) objects.get(i).getObjectId().getIdSnapshot().get(
-                    "TABLE1_ID");
+        for (ClientMtTable1 object : objects) {
+            Integer id = (Integer) object.getObjectId().getIdSnapshot().get("TABLE1_ID");
             if (id == 1) {
-                assertEquals("a", objects.get(i).getGlobalAttribute1());
+                assertEquals("a", object.getGlobalAttribute1());
                 checkedFields++;
-            }
-            else if (id == 2) {
-                assertEquals("sa1", ((ClientMtTable1Subclass1) objects.get(i))
-                        .getSubclass1Attribute1());
+            } else if (id == 2) {
+                assertEquals("sa1", ((ClientMtTable1Subclass1) object).getSubclass1Attribute1());
                 checkedFields++;
             }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextMergeHandlerIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextMergeHandlerIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextMergeHandlerIT.java
index 00ca30e..19e8e78 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextMergeHandlerIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextMergeHandlerIT.java
@@ -79,19 +79,19 @@ public class CayenneContextMergeHandlerIT extends ClientCase {
 
         assertNull(o1.getGlobalAttribute1Direct());
 
-        handler.nodePropertyChanged(o1.getObjectId(), ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, null, "abc");
+        handler.nodePropertyChanged(o1.getObjectId(), ClientMtTable1.GLOBAL_ATTRIBUTE1.getName(), null, "abc");
         assertEquals("abc", o1.getGlobalAttribute1Direct());
 
-        handler.nodePropertyChanged(o1.getObjectId(), ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, "abc", "xyz");
+        handler.nodePropertyChanged(o1.getObjectId(), ClientMtTable1.GLOBAL_ATTRIBUTE1.getName(), "abc", "xyz");
 
         assertEquals("xyz", o1.getGlobalAttribute1Direct());
 
         // block if old value is different
-        handler.nodePropertyChanged(o1.getObjectId(), ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, "123", "mnk");
+        handler.nodePropertyChanged(o1.getObjectId(), ClientMtTable1.GLOBAL_ATTRIBUTE1.getName(), "123", "mnk");
 
         assertEquals("xyz", o1.getGlobalAttribute1Direct());
 
-        handler.nodePropertyChanged(o1.getObjectId(), ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, "xyz", null);
+        handler.nodePropertyChanged(o1.getObjectId(), ClientMtTable1.GLOBAL_ATTRIBUTE1.getName(), "xyz", null);
 
         assertNull(o1.getGlobalAttribute1Direct());
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextPaginatedListCachingIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextPaginatedListCachingIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextPaginatedListCachingIT.java
index ee5565a..521d64e 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextPaginatedListCachingIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextPaginatedListCachingIT.java
@@ -52,7 +52,7 @@ public class CayenneContextPaginatedListCachingIT extends ClientCase {
         tMtTable1.setColumns("TABLE1_ID", "GLOBAL_ATTRIBUTE1", "SERVER_ATTRIBUTE1");
     }
 
-    protected void createSevenMtTable1sDataSet() throws Exception {
+    private void createSevenMtTable1sDataSet() throws Exception {
         for (int i = 1; i <= 7; i++) {
             tMtTable1.insert(i, "g" + i, "s" + i);
         }
@@ -62,12 +62,12 @@ public class CayenneContextPaginatedListCachingIT extends ClientCase {
     public void testLocalCache() throws Exception {
         createSevenMtTable1sDataSet();
 
-        SelectQuery query = new SelectQuery(ClientMtTable1.class);
-        query.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, SortOrder.ASCENDING);
+        SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
+        query.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1.asc());
         query.setPageSize(3);
         query.setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE);
 
-        List<ClientMtTable1> result1 = context.performQuery(query);
+        List<ClientMtTable1> result1 = query.select(context);
         assertEquals(7, result1.size());
 
         // ensure we can resolve all objects without a failure...

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextWithDataContextIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextWithDataContextIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextWithDataContextIT.java
index 6bddc00..c910c30 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextWithDataContextIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextWithDataContextIT.java
@@ -26,7 +26,6 @@ import org.apache.cayenne.map.LifecycleEvent;
 import org.apache.cayenne.query.ObjectIdQuery;
 import org.apache.cayenne.query.QueryCacheStrategy;
 import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.query.SortOrder;
 import org.apache.cayenne.reflect.LifecycleCallbackRegistry;
 import org.apache.cayenne.remote.RemoteIncrementalFaultList;
 import org.apache.cayenne.test.jdbc.DBHelper;
@@ -36,7 +35,6 @@ import org.apache.cayenne.testdo.mt.ClientMtTable1;
 import org.apache.cayenne.testdo.mt.ClientMtTable2;
 import org.apache.cayenne.testdo.mt.MtTable1;
 import org.apache.cayenne.unit.di.DataChannelInterceptor;
-import org.apache.cayenne.unit.di.UnitTestClosure;
 import org.apache.cayenne.unit.di.client.ClientCase;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
@@ -44,7 +42,6 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.sql.Types;
-import java.util.Iterator;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
@@ -97,13 +94,9 @@ public class CayenneContextWithDataContextIT extends ClientCase {
         }
     }
 
-    @SuppressWarnings("deprecation")
     @Test
     public void testLocalCacheStaysLocal() {
-
-        DataContext serverContext = (DataContext) clientServerChannel.getParentChannel();
-
-        SelectQuery query = new SelectQuery(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
         query.setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE);
 
         List<?> results = clientContext.performQuery(query);
@@ -114,7 +107,7 @@ public class CayenneContextWithDataContextIT extends ClientCase {
     }
 
     @Test
-    public void testAddToList() throws Exception {
+    public void testAddToList() {
 
         ClientMtTable1 t1 = clientContext.newObject(ClientMtTable1.class);
         ClientMtTable2 t2 = clientContext.newObject(ClientMtTable2.class);
@@ -133,7 +126,7 @@ public class CayenneContextWithDataContextIT extends ClientCase {
     }
 
     @Test
-    public void testSetValueHolder() throws Exception {
+    public void testSetValueHolder() {
 
         ClientMtTable1 t1 = clientContext.newObject(ClientMtTable1.class);
         ClientMtTable2 t2 = clientContext.newObject(ClientMtTable2.class);
@@ -144,7 +137,7 @@ public class CayenneContextWithDataContextIT extends ClientCase {
     }
 
     @Test
-    public void testPostAddCallback() throws Exception {
+    public void testPostAddCallback() {
 
         LifecycleCallbackRegistry callbackRegistry = clientServerChannel
                 .getEntityResolver()
@@ -213,11 +206,9 @@ public class CayenneContextWithDataContextIT extends ClientCase {
         new ParallelTestContainer() {
 
             @Override
-            protected void assertResult() throws Exception {
+            protected void assertResult() {
             	// find peer
-            	MtTable1 peer = (MtTable1) serverContext.getGraphManager().getNode(
-                    clientObject.getObjectId());
-
+            	MtTable1 peer = (MtTable1) serverContext.getGraphManager().getNode(clientObject.getObjectId());
             	assertNotNull(peer);
             	assertTrue(peer.isPrePersisted());
             }
@@ -231,7 +222,7 @@ public class CayenneContextWithDataContextIT extends ClientCase {
     }
 
     @Test
-    public void testPreRemoveCallback() throws Exception {
+    public void testPreRemoveCallback() {
 
         // an exception was triggered within POST_LOAD callback
         LifecycleCallbackRegistry callbackRegistry = clientServerChannel
@@ -285,7 +276,7 @@ public class CayenneContextWithDataContextIT extends ClientCase {
     }
 
     @Test
-    public void testRollbackChanges() throws Exception {
+    public void testRollbackChanges() {
 
         ClientMtTable1 o = clientContext.newObject(ClientMtTable1.class);
         o.setGlobalAttribute1("1");
@@ -352,27 +343,24 @@ public class CayenneContextWithDataContextIT extends ClientCase {
                 MtTable1.TABLE1_ID_PK_COLUMN,
                 1);
 
-        SelectQuery q = new SelectQuery(ClientMtTable2.class);
-        q.addOrdering(ClientMtTable2.GLOBAL_ATTRIBUTE_PROPERTY, SortOrder.ASCENDING);
-        q.addPrefetch(ClientMtTable2.TABLE1_PROPERTY);
-
-        final List<ClientMtTable2> results = clientContext.performQuery(q);
+        SelectQuery<ClientMtTable2> q = new SelectQuery<>(ClientMtTable2.class);
+        q.addOrdering(ClientMtTable2.GLOBAL_ATTRIBUTE.asc());
+        q.addPrefetch(ClientMtTable2.TABLE1.disjoint());
 
-        clientServerInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+        final List<ClientMtTable2> results = q.select(clientContext);
 
-            public void execute() {
-                assertEquals(2, results.size());
+        clientServerInterceptor.runWithQueriesBlocked(() -> {
+            assertEquals(2, results.size());
 
-                for (ClientMtTable2 o : results) {
-                    assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
-                    assertSame(clientContext, o.getObjectContext());
+            for (ClientMtTable2 o : results) {
+                assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
+                assertSame(clientContext, o.getObjectContext());
 
-                    ClientMtTable1 o1 = o.getTable1();
-                    assertNotNull(o1);
-                    assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
-                    assertSame(clientContext, o1.getObjectContext());
-                    assertEquals(prefetchedId, o1.getObjectId());
-                }
+                ClientMtTable1 o1 = o.getTable1();
+                assertNotNull(o1);
+                assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
+                assertSame(clientContext, o1.getObjectContext());
+                assertEquals(prefetchedId, o1.getObjectId());
             }
         });
     }
@@ -381,23 +369,19 @@ public class CayenneContextWithDataContextIT extends ClientCase {
     public void testPrefetchingToOneNull() throws Exception {
         tMtTable2.insert(15, null, "g3");
 
-        SelectQuery q = new SelectQuery(ClientMtTable2.class);
-        q.addPrefetch(ClientMtTable2.TABLE1_PROPERTY);
-
-        final List<ClientMtTable2> results = clientContext.performQuery(q);
+        SelectQuery<ClientMtTable2> q = new SelectQuery<>(ClientMtTable2.class);
+        q.addPrefetch(ClientMtTable2.TABLE1.disjoint());
 
-        clientServerInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+        final List<ClientMtTable2> results = q.select(clientContext);
 
-            public void execute() {
+        clientServerInterceptor.runWithQueriesBlocked(() -> {
+            assertEquals(1, results.size());
 
-                assertEquals(1, results.size());
-
-                ClientMtTable2 o = results.get(0);
-                assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
-                assertSame(clientContext, o.getObjectContext());
+            ClientMtTable2 o = results.get(0);
+            assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
+            assertSame(clientContext, o.getObjectContext());
 
-                assertNull(o.getTable1());
-            }
+            assertNull(o.getTable1());
         });
     }
 
@@ -405,33 +389,28 @@ public class CayenneContextWithDataContextIT extends ClientCase {
     public void testPrefetchingToMany() throws Exception {
         createTwoMtTable1sAnd2sDataSet();
 
-        SelectQuery q = new SelectQuery(ClientMtTable1.class);
-        q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, SortOrder.ASCENDING);
-        q.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
-
-        final List<ClientMtTable1> results = clientContext.performQuery(q);
+        SelectQuery<ClientMtTable1> q = new SelectQuery<>(ClientMtTable1.class);
+        q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1.asc());
+        q.addPrefetch(ClientMtTable1.TABLE2ARRAY.joint());
 
-        clientServerInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+        final List<ClientMtTable1> results = q.select(clientContext);
 
-            public void execute() {
+        clientServerInterceptor.runWithQueriesBlocked(() -> {
 
-                ClientMtTable1 o1 = results.get(0);
-                assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
-                assertSame(clientContext, o1.getObjectContext());
+            ClientMtTable1 o1 = results.get(0);
+            assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
+            assertSame(clientContext, o1.getObjectContext());
 
-                List<?> children1 = o1.getTable2Array();
+            List<ClientMtTable2> children1 = o1.getTable2Array();
 
-                assertEquals(2, children1.size());
-                Iterator<?> it = children1.iterator();
-                while (it.hasNext()) {
-                    ClientMtTable2 o = (ClientMtTable2) it.next();
-                    assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
-                    assertSame(clientContext, o.getObjectContext());
+            assertEquals(2, children1.size());
+            for (ClientMtTable2 o : children1) {
+                assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
+                assertSame(clientContext, o.getObjectContext());
 
-                    // TODO: fixme... reverse relationship is not connected and will
-                    // cause a fetch
-                    // assertEquals(o1, o.getTable1());
-                }
+                // TODO: fixme... reverse relationship is not connected and will
+                // cause a fetch
+                // assertEquals(o1, o.getTable1());
             }
         });
     }
@@ -440,9 +419,9 @@ public class CayenneContextWithDataContextIT extends ClientCase {
     public void testPerformPaginatedQuery() throws Exception {
         createEightMtTable1s();
 
-        SelectQuery query = new SelectQuery(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
         query.setPageSize(5);
-        List<ClientMtTable1> objects = clientContext.performQuery(query);
+        List<ClientMtTable1> objects = query.select(clientContext);
         assertNotNull(objects);
         assertTrue(objects instanceof RemoteIncrementalFaultList);
     }
@@ -451,62 +430,47 @@ public class CayenneContextWithDataContextIT extends ClientCase {
     public void testPrefetchingToManyEmpty() throws Exception {
         createTwoMtTable1sAnd2sDataSet();
 
-        SelectQuery q = new SelectQuery(ClientMtTable1.class);
-        q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, SortOrder.ASCENDING);
-        q.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
+        SelectQuery<ClientMtTable1> q = new SelectQuery<>(ClientMtTable1.class);
+        q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1.asc());
+        q.addPrefetch(ClientMtTable1.TABLE2ARRAY.joint());
 
-        final List<ClientMtTable1> results = clientContext.performQuery(q);
+        final List<ClientMtTable1> results = q.select(clientContext);
 
-        clientServerInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+        clientServerInterceptor.runWithQueriesBlocked(() -> {
+            ClientMtTable1 o2 = results.get(1);
+            assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
+            assertSame(clientContext, o2.getObjectContext());
 
-            public void execute() {
-                ClientMtTable1 o2 = results.get(1);
-                assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
-                assertSame(clientContext, o2.getObjectContext());
-
-                List<ClientMtTable2> children2 = o2.getTable2Array();
-                assertFalse(((ValueHolder) children2).isFault());
-                assertEquals(0, children2.size());
-            }
+            List<ClientMtTable2> children2 = o2.getTable2Array();
+            assertFalse(((ValueHolder) children2).isFault());
+            assertEquals(0, children2.size());
         });
     }
 
     @Test
-    public void testOIDQueryInterception() throws Exception {
+    public void testOIDQueryInterception() {
 
         final ClientMtTable1 o = clientContext.newObject(ClientMtTable1.class);
         o.setGlobalAttribute1("aaa");
 
         // fetch new
-        final ObjectIdQuery q1 = new ObjectIdQuery(
-                o.getObjectId(),
-                false,
-                ObjectIdQuery.CACHE);
-
-        clientServerInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+        final ObjectIdQuery q1 = new ObjectIdQuery(o.getObjectId(), false, ObjectIdQuery.CACHE);
 
-            public void execute() {
-                List<?> objects = clientContext.performQuery(q1);
-                assertEquals(1, objects.size());
-                assertSame(o, objects.get(0));
-            }
+        clientServerInterceptor.runWithQueriesBlocked(() -> {
+            List<?> objects = clientContext.performQuery(q1);
+            assertEquals(1, objects.size());
+            assertSame(o, objects.get(0));
         });
 
         clientContext.commitChanges();
 
         // fetch committed
-        final ObjectIdQuery q2 = new ObjectIdQuery(
-                o.getObjectId(),
-                false,
-                ObjectIdQuery.CACHE);
-
-        clientServerInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+        final ObjectIdQuery q2 = new ObjectIdQuery(o.getObjectId(), false, ObjectIdQuery.CACHE);
 
-            public void execute() {
-                List<?> objects = clientContext.performQuery(q2);
-                assertEquals(1, objects.size());
-                assertSame(o, objects.get(0));
-            }
+        clientServerInterceptor.runWithQueriesBlocked(() -> {
+            List<?> objects = clientContext.performQuery(q2);
+            assertEquals(1, objects.size());
+            assertSame(o, objects.get(0));
         });
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextIT.java b/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextIT.java
index 53a3145..83fad72 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextIT.java
@@ -22,6 +22,7 @@ import org.apache.cayenne.configuration.rop.client.ClientRuntime;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.graph.GraphChangeHandler;
 import org.apache.cayenne.graph.GraphDiff;
+import org.apache.cayenne.query.SelectById;
 import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.query.SortOrder;
 import org.apache.cayenne.remote.RemoteCayenneCase;
@@ -29,7 +30,6 @@ import org.apache.cayenne.remote.service.LocalConnection;
 import org.apache.cayenne.testdo.mt.ClientMtTable1;
 import org.apache.cayenne.testdo.mt.ClientMtTable2;
 import org.apache.cayenne.unit.di.DataChannelInterceptor;
-import org.apache.cayenne.unit.di.UnitTestClosure;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
 import org.junit.Test;
@@ -39,7 +39,6 @@ import org.junit.runners.Parameterized.Parameters;
 
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Iterator;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
@@ -81,18 +80,17 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 		assertSame(clientContext, child.getChannel());
 
 		// second level of nesting
-		ObjectContext grandchild = runtime.newContext((DataChannel) child);
+		ObjectContext grandchild = runtime.newContext(child);
 
 		assertNotNull(grandchild);
 		assertSame(child, grandchild.getChannel());
 	}
 
 	@Test
-	public void testSelect() throws Exception {
+	public void testSelect() {
 		ObjectContext child = runtime.newContext(clientContext);
 
-		ClientMtTable1 committed = clientContext
-				.newObject(ClientMtTable1.class);
+		ClientMtTable1 committed = clientContext.newObject(ClientMtTable1.class);
 		ClientMtTable1 deleted = clientContext.newObject(ClientMtTable1.class);
 		ClientMtTable1 modified = clientContext.newObject(ClientMtTable1.class);
 
@@ -106,16 +104,14 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 
 		ClientMtTable1 _new = clientContext.newObject(ClientMtTable1.class);
 
-		assertEquals(PersistenceState.COMMITTED,
-				committed.getPersistenceState());
+		assertEquals(PersistenceState.COMMITTED, committed.getPersistenceState());
 		assertEquals(PersistenceState.MODIFIED, modified.getPersistenceState());
 		assertEquals(PersistenceState.DELETED, deleted.getPersistenceState());
 		assertEquals(PersistenceState.NEW, _new.getPersistenceState());
 
 		List<ClientMtTable1> objects = child
-				.select(new SelectQuery<ClientMtTable1>(ClientMtTable1.class));
-		assertEquals("All but NEW object must have been included", 3,
-				objects.size());
+				.select(new SelectQuery<>(ClientMtTable1.class));
+		assertEquals("All but NEW object must have been included", 3, objects.size());
 
 		for (ClientMtTable1 next : objects) {
 			assertEquals(PersistenceState.COMMITTED, next.getPersistenceState());
@@ -128,9 +124,8 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 	}
 
 	@Test
-	public void testPrefetchingToOne() throws Exception {
-		final ClientMtTable1 mt11 = clientContext
-				.newObject(ClientMtTable1.class);
+	public void testPrefetchingToOne() {
+		final ClientMtTable1 mt11 = clientContext.newObject(ClientMtTable1.class);
 		clientContext.newObject(ClientMtTable1.class);
 		ClientMtTable2 mt21 = clientContext.newObject(ClientMtTable2.class);
 		ClientMtTable2 mt22 = clientContext.newObject(ClientMtTable2.class);
@@ -142,36 +137,28 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 
 		final ObjectContext child = runtime.newContext(clientContext);
 
-		SelectQuery<ClientMtTable2> q = new SelectQuery<ClientMtTable2>(
-				ClientMtTable2.class);
-		q.addPrefetch(ClientMtTable2.TABLE1_PROPERTY);
+		SelectQuery<ClientMtTable2> q = new SelectQuery<>(ClientMtTable2.class);
+		q.addPrefetch(ClientMtTable2.TABLE1.getName());
 
 		final List<ClientMtTable2> results = child.select(q);
 
-		queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
-			public void execute() {
-				assertEquals(2, results.size());
-				Iterator<?> it = results.iterator();
-				while (it.hasNext()) {
-					ClientMtTable2 o = (ClientMtTable2) it.next();
-					assertEquals(PersistenceState.COMMITTED,
-							o.getPersistenceState());
-					assertSame(child, o.getObjectContext());
-
-					ClientMtTable1 o1 = o.getTable1();
-					assertNotNull(o1);
-					assertEquals(PersistenceState.COMMITTED,
-							o1.getPersistenceState());
-					assertSame(child, o1.getObjectContext());
-					assertEquals(mt11.getObjectId(), o1.getObjectId());
-				}
+		queryInterceptor.runWithQueriesBlocked(() -> {
+			assertEquals(2, results.size());
+			for (ClientMtTable2 o : results) {
+				assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
+				assertSame(child, o.getObjectContext());
+
+				ClientMtTable1 o1 = o.getTable1();
+				assertNotNull(o1);
+				assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
+				assertSame(child, o1.getObjectContext());
+				assertEquals(mt11.getObjectId(), o1.getObjectId());
 			}
 		});
 	}
 
 	@Test
-	public void testPrefetchingToMany() throws Exception {
+	public void testPrefetchingToMany() {
 		ClientMtTable1 mt11 = clientContext.newObject(ClientMtTable1.class);
 		mt11.setGlobalAttribute1("1");
 
@@ -188,56 +175,46 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 
 		final ObjectContext child = runtime.newContext(clientContext);
 
-		SelectQuery<ClientMtTable1> q = new SelectQuery<ClientMtTable1>(
+		SelectQuery<ClientMtTable1> q = new SelectQuery<>(
 				ClientMtTable1.class);
 		q.addOrdering("globalAttribute1", SortOrder.ASCENDING);
-		q.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
+		q.addPrefetch(ClientMtTable1.TABLE2ARRAY.joint());
 
 		final List<ClientMtTable1> results = child.select(q);
 
-		queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+		queryInterceptor.runWithQueriesBlocked(() -> {
+			ClientMtTable1 o1 = results.get(0);
+			assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
+			assertSame(child, o1.getObjectContext());
 
-			public void execute() {
-				ClientMtTable1 o1 = results.get(0);
-				assertEquals(PersistenceState.COMMITTED,
-						o1.getPersistenceState());
-				assertSame(child, o1.getObjectContext());
+			List<ClientMtTable2> children1 = o1.getTable2Array();
 
-				List<ClientMtTable2> children1 = o1.getTable2Array();
-
-				assertEquals(2, children1.size());
-				Iterator<ClientMtTable2> it = children1.iterator();
-				while (it.hasNext()) {
-					ClientMtTable2 o = it.next();
-					assertEquals(PersistenceState.COMMITTED,
-							o.getPersistenceState());
-					assertSame(child, o.getObjectContext());
-
-					assertEquals(o1, o.getTable1());
-				}
+			assertEquals(2, children1.size());
+			for (ClientMtTable2 o : children1) {
+				assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
+				assertSame(child, o.getObjectContext());
+				assertEquals(o1, o.getTable1());
+			}
 
-				ClientMtTable1 o2 = results.get(1);
-				assertEquals(PersistenceState.COMMITTED,
-						o2.getPersistenceState());
-				assertSame(child, o2.getObjectContext());
+			ClientMtTable1 o2 = results.get(1);
+			assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
+			assertSame(child, o2.getObjectContext());
 
-				List<?> children2 = o2.getTable2Array();
+			List<?> children2 = o2.getTable2Array();
 
-				assertEquals(0, children2.size());
-			}
+			assertEquals(0, children2.size());
 		});
 	}
 
 	@Test
-	public void testDeleteNew() throws Exception {
+	public void testDeleteNew() {
 		ObjectContext child = runtime.newContext(clientContext);
 
 		ClientMtTable1 a = clientContext.newObject(ClientMtTable1.class);
 		clientContext.commitChanges();
 
 		ClientMtTable2 p = child.newObject(ClientMtTable2.class);
-		ClientMtTable1 aChild = (ClientMtTable1) Cayenne.objectForPK(child,
-				a.getObjectId());
+		ClientMtTable1 aChild = (ClientMtTable1) Cayenne.objectForPK(child, a.getObjectId());
 		p.setGlobalAttribute("X");
 		aChild.addToTable2Array(p);
 
@@ -253,78 +230,65 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 	 * A test case for CAY-698 bug.
 	 */
 	@Test
-	public void testNullifyToOne() throws Exception {
+	public void testNullifyToOne() {
 		ClientMtTable1 a = clientContext.newObject(ClientMtTable1.class);
 		ClientMtTable2 b = clientContext.newObject(ClientMtTable2.class);
 		a.addToTable2Array(b);
 
 		clientContext.commitChanges();
 
-		final ObjectContext child = runtime.newContext(clientContext);
+		ObjectContext child = runtime.newContext(clientContext);
 		ObjectContext childPeer = runtime.newContext(clientContext);
 
-		final ClientMtTable2 childP1 = (ClientMtTable2) Cayenne.objectForPK(
-				child, b.getObjectId());
+		ClientMtTable2 childP1 = SelectById.query(ClientMtTable2.class, b.getObjectId()).selectOne(child);
 
 		// trigger object creation in the peer nested DC
 		Cayenne.objectForPK(childPeer, b.getObjectId());
 		childP1.setTable1(null);
 
-		queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
-			public void execute() {
-				child.commitChangesToParent();
-				assertEquals(PersistenceState.COMMITTED,
-						childP1.getPersistenceState());
-
-				ClientMtTable2 parentP1 = (ClientMtTable2) clientContext
-						.getGraphManager().getNode(childP1.getObjectId());
+		queryInterceptor.runWithQueriesBlocked(() -> {
+			child.commitChangesToParent();
+			assertEquals(PersistenceState.COMMITTED, childP1.getPersistenceState());
 
-				assertNotNull(parentP1);
-				assertEquals(PersistenceState.MODIFIED,
-						parentP1.getPersistenceState());
-				assertNull(parentP1.getTable1());
+			ClientMtTable2 parentP1 = (ClientMtTable2) clientContext.getGraphManager().getNode(childP1.getObjectId());
 
-				// check that arc changes got recorded in the parent context
-				GraphDiff diffs = clientContext.internalGraphManager()
-						.getDiffs();
-				final int[] arcDiffs = new int[1];
+			assertNotNull(parentP1);
+			assertEquals(PersistenceState.MODIFIED, parentP1.getPersistenceState());
+			assertNull(parentP1.getTable1());
 
-				diffs.apply(new GraphChangeHandler() {
+			// check that arc changes got recorded in the parent context
+			GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
+			final int[] arcDiffs = new int[1];
 
-					public void arcCreated(Object nodeId, Object targetNodeId,
-							Object arcId) {
-						arcDiffs[0]++;
-					}
-
-					public void arcDeleted(Object nodeId, Object targetNodeId,
-							Object arcId) {
-						arcDiffs[0]--;
-					}
-
-					public void nodeCreated(Object nodeId) {
+			diffs.apply(new GraphChangeHandler() {
+				public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
+					arcDiffs[0]++;
+				}
 
-					}
+				public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
+					arcDiffs[0]--;
+				}
 
-					public void nodeIdChanged(Object nodeId, Object newId) {
-					}
+				public void nodeCreated(Object nodeId) {
+				}
 
-					public void nodePropertyChanged(Object nodeId,
-							String property, Object oldValue, Object newValue) {
-					}
+				public void nodeIdChanged(Object nodeId, Object newId) {
+				}
 
-					public void nodeRemoved(Object nodeId) {
+				public void nodePropertyChanged(Object nodeId,
+						String property, Object oldValue, Object newValue) {
+				}
 
-					}
-				});
+				public void nodeRemoved(Object nodeId) {
+				}
+			});
 
-				assertEquals(-2, arcDiffs[0]);
-			}
+			assertEquals(-2, arcDiffs[0]);
 		});
 	}
 
 	@Test
-	public void testCommitChangesToParent() throws Exception {
+	public void testCommitChangesToParent() {
 		clientContext.newObject(ClientMtTable1.class);
 		clientContext.newObject(ClientMtTable1.class);
 		clientContext.newObject(ClientMtTable1.class);
@@ -333,8 +297,7 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 
 		final ObjectContext child = runtime.newContext(clientContext);
 
-		SelectQuery<ClientMtTable1> query = new SelectQuery<ClientMtTable1>(
-				ClientMtTable1.class);
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
 		List<ClientMtTable1> objects = child.select(query);
 
 		assertEquals(4, objects.size());
@@ -350,101 +313,82 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 		final ClientMtTable1 childHollow = objects.get(3);
 		child.invalidateObjects(childHollow);
 
-		queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
-			public void execute() {
-				child.commitChangesToParent();
+		queryInterceptor.runWithQueriesBlocked(() -> {
+			child.commitChangesToParent();
 
-				// * all modified child objects must be in committed state now
-				// * all modifications should be propagated to the parent
-				// * no actual commit should occur.
+			// * all modified child objects must be in committed state now
+			// * all modifications should be propagated to the parent
+			// * no actual commit should occur.
 
-				assertEquals(PersistenceState.COMMITTED,
-						childNew.getPersistenceState());
-				assertEquals(PersistenceState.COMMITTED,
-						childModified.getPersistenceState());
-				assertEquals(PersistenceState.COMMITTED,
-						childCommitted.getPersistenceState());
-				assertEquals(PersistenceState.HOLLOW,
-						childHollow.getPersistenceState());
+			assertEquals(PersistenceState.COMMITTED, childNew.getPersistenceState());
+			assertEquals(PersistenceState.COMMITTED, childModified.getPersistenceState());
+			assertEquals(PersistenceState.COMMITTED, childCommitted.getPersistenceState());
+			assertEquals(PersistenceState.HOLLOW, childHollow.getPersistenceState());
 
-				ClientMtTable1 parentNew = (ClientMtTable1) clientContext
-						.getGraphManager().getNode(childNew.getObjectId());
-				final ClientMtTable1 parentModified = (ClientMtTable1) clientContext
-						.getGraphManager().getNode(childModified.getObjectId());
-				ClientMtTable1 parentCommitted = (ClientMtTable1) clientContext
-						.getGraphManager()
-						.getNode(childCommitted.getObjectId());
-				ClientMtTable1 parentHollow = (ClientMtTable1) clientContext
-						.getGraphManager().getNode(childHollow.getObjectId());
+			ClientMtTable1 parentNew = (ClientMtTable1) clientContext
+					.getGraphManager().getNode(childNew.getObjectId());
+			final ClientMtTable1 parentModified = (ClientMtTable1) clientContext
+					.getGraphManager().getNode(childModified.getObjectId());
+			ClientMtTable1 parentCommitted = (ClientMtTable1) clientContext
+					.getGraphManager()
+					.getNode(childCommitted.getObjectId());
+			ClientMtTable1 parentHollow = (ClientMtTable1) clientContext
+					.getGraphManager().getNode(childHollow.getObjectId());
 
-				assertNotNull(parentNew);
-				assertEquals(PersistenceState.NEW,
-						parentNew.getPersistenceState());
-				assertEquals("NNN", parentNew.getGlobalAttribute1());
+			assertNotNull(parentNew);
+			assertEquals(PersistenceState.NEW, parentNew.getPersistenceState());
+			assertEquals("NNN", parentNew.getGlobalAttribute1());
 
-				assertNotNull(parentModified);
-				assertEquals(PersistenceState.MODIFIED,
-						parentModified.getPersistenceState());
-				assertEquals("MMM", parentModified.getGlobalAttribute1());
+			assertNotNull(parentModified);
+			assertEquals(PersistenceState.MODIFIED, parentModified.getPersistenceState());
+			assertEquals("MMM", parentModified.getGlobalAttribute1());
 
-				assertNotNull(parentCommitted);
-				assertEquals(PersistenceState.COMMITTED,
-						parentCommitted.getPersistenceState());
+			assertNotNull(parentCommitted);
+			assertEquals(PersistenceState.COMMITTED, parentCommitted.getPersistenceState());
 
-				assertNotNull(parentHollow);
+			assertNotNull(parentHollow);
 
-				// check that arc changes got recorded in the parent context
-				GraphDiff diffs = clientContext.internalGraphManager()
-						.getDiffs();
+			// check that arc changes got recorded in the parent context
+			GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
 
-				final int[] modifiedProperties = new int[1];
+			final int[] modifiedProperties = new int[1];
 
-				diffs.apply(new GraphChangeHandler() {
-
-					@Override
-					public void arcCreated(Object nodeId, Object targetNodeId,
-							Object arcId) {
-
-					}
+			diffs.apply(new GraphChangeHandler() {
 
-					@Override
-					public void arcDeleted(Object nodeId, Object targetNodeId,
-							Object arcId) {
-
-					}
-
-					@Override
-					public void nodeCreated(Object nodeId) {
+				@Override
+				public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
+				}
 
-					}
+				@Override
+				public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
+				}
 
-					@Override
-					public void nodeIdChanged(Object nodeId, Object newId) {
-					}
+				@Override
+				public void nodeCreated(Object nodeId) {
+				}
 
-					@Override
-					public void nodePropertyChanged(Object nodeId,
-							String property, Object oldValue, Object newValue) {
+				@Override
+				public void nodeIdChanged(Object nodeId, Object newId) {
+				}
 
-						if (nodeId.equals(parentModified.getObjectId())) {
-							modifiedProperties[0]++;
-						}
+				@Override
+				public void nodePropertyChanged(Object nodeId, String property, Object oldValue, Object newValue) {
+					if (nodeId.equals(parentModified.getObjectId())) {
+						modifiedProperties[0]++;
 					}
+				}
 
-					@Override
-					public void nodeRemoved(Object nodeId) {
-
-					}
-				});
+				@Override
+				public void nodeRemoved(Object nodeId) {
+				}
+			});
 
-				assertEquals(1, modifiedProperties[0]);
-			}
+			assertEquals(1, modifiedProperties[0]);
 		});
 	}
 
 	@Test
-	public void testCommitChangesToParentDeleted() throws Exception {
+	public void testCommitChangesToParentDeleted() {
 		clientContext.newObject(ClientMtTable1.class);
 		clientContext.newObject(ClientMtTable1.class);
 		clientContext.newObject(ClientMtTable1.class);
@@ -454,8 +398,7 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 		ObjectContext child = runtime.newContext(clientContext);
 
 		// make sure we fetch in predictable order
-		SelectQuery<ClientMtTable1> query = new SelectQuery<ClientMtTable1>(
-				ClientMtTable1.class);
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
 		List<ClientMtTable1> objects = child.select(query);
 
 		assertEquals(4, objects.size());
@@ -473,11 +416,10 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 		// * all modifications should be propagated to the parent
 		// * no actual commit should occur.
 
-		assertEquals(PersistenceState.TRANSIENT,
-				childDeleted.getPersistenceState());
+		assertEquals(PersistenceState.TRANSIENT, childDeleted.getPersistenceState());
 
-		ClientMtTable1 parentDeleted = (ClientMtTable1) clientContext
-				.getGraphManager().getNode(childDeleted.getObjectId());
+		ClientMtTable1 parentDeleted = (ClientMtTable1) clientContext.getGraphManager()
+				.getNode(childDeleted.getObjectId());
 
 		assertNotNull(parentDeleted);
 		assertEquals(PersistenceState.DELETED,
@@ -486,7 +428,7 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 	}
 
 	@Test
-	public void testCommitChanges() throws Exception {
+	public void testCommitChanges() {
 		clientContext.newObject(ClientMtTable1.class);
 		clientContext.newObject(ClientMtTable1.class);
 		clientContext.newObject(ClientMtTable1.class);
@@ -496,8 +438,7 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 		ObjectContext child = runtime.newContext(clientContext);
 
 		// make sure we fetch in predictable order
-		SelectQuery<ClientMtTable1> query = new SelectQuery<ClientMtTable1>(
-				ClientMtTable1.class);
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
 		List<ClientMtTable1> objects = child.select(query);
 
 		assertEquals(4, objects.size());
@@ -521,12 +462,9 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 		child.commitChanges();
 
 		assertEquals(PersistenceState.COMMITTED, childNew.getPersistenceState());
-		assertEquals(PersistenceState.COMMITTED,
-				childModified.getPersistenceState());
-		assertEquals(PersistenceState.COMMITTED,
-				childCommitted.getPersistenceState());
-		assertEquals(PersistenceState.TRANSIENT,
-				childDeleted.getPersistenceState());
+		assertEquals(PersistenceState.COMMITTED, childModified.getPersistenceState());
+		assertEquals(PersistenceState.COMMITTED, childCommitted.getPersistenceState());
+		assertEquals(PersistenceState.TRANSIENT, childDeleted.getPersistenceState());
 		assertEquals(PersistenceState.HOLLOW, childHollow.getPersistenceState());
 
 		ClientMtTable1 parentNew = (ClientMtTable1) clientContext
@@ -541,26 +479,23 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 				.getGraphManager().getNode(childHollow.getObjectId());
 
 		assertNotNull(parentNew);
-		assertEquals(PersistenceState.COMMITTED,
-				parentNew.getPersistenceState());
+		assertEquals(PersistenceState.COMMITTED, parentNew.getPersistenceState());
 		assertEquals("NNN", parentNew.getGlobalAttribute1());
 
 		assertNotNull(parentModified);
-		assertEquals(PersistenceState.COMMITTED,
-				parentModified.getPersistenceState());
+		assertEquals(PersistenceState.COMMITTED, parentModified.getPersistenceState());
 		assertEquals("MMM", parentModified.getGlobalAttribute1());
 
 		assertNull("Deleted object should not be registered.", parentDeleted);
 
 		assertNotNull(parentCommitted);
-		assertEquals(PersistenceState.COMMITTED,
-				parentCommitted.getPersistenceState());
+		assertEquals(PersistenceState.COMMITTED, parentCommitted.getPersistenceState());
 
 		assertNotNull(parentHollow);
 	}
 
 	@Test
-	public void testAddRemove() throws Exception {
+	public void testAddRemove() {
 		ObjectContext child = runtime.newContext(clientContext);
 
 		ClientMtTable1 a = child.newObject(ClientMtTable1.class);
@@ -585,7 +520,7 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 	}
 
 	@Test
-	public void testChangeRel() throws Exception {
+	public void testChangeRel() {
 		ObjectContext child = runtime.newContext(clientContext);
 
 		ClientMtTable1 a = child.newObject(ClientMtTable1.class);
@@ -617,7 +552,7 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 	}
 
 	@Test
-	public void testCAY1183() throws Exception {
+	public void testCAY1183()  {
 		ClientMtTable1 parentMt = clientContext.newObject(ClientMtTable1.class);
 		clientContext.commitChanges();
 
@@ -639,15 +574,12 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 	 * CAY1714
 	 */
 	@Test
-	public void testQueriesOnTemporaryObject() throws Exception {
-		ObjectContext clientContext = runtime
-				.newContext((DataChannel) this.clientContext);
+	public void testQueriesOnTemporaryObject() {
+		ObjectContext clientContext = runtime.newContext(this.clientContext);
 		ClientMtTable1 parentMt = clientContext.newObject(ClientMtTable1.class);
 
-		ObjectContext childContext = runtime
-				.newContext((DataChannel) clientContext);
-		ClientMtTable1 childMt = (ClientMtTable1) Cayenne.objectForPK(
-				childContext, parentMt.getObjectId());
+		ObjectContext childContext = runtime.newContext(clientContext);
+		ClientMtTable1 childMt = (ClientMtTable1) Cayenne.objectForPK(childContext, parentMt.getObjectId());
 		childMt.setGlobalAttribute1("1183");
 		ClientMtTable2 childMt2 = childContext.newObject(ClientMtTable2.class);
 		childMt2.setGlobalAttribute("1183");
@@ -659,7 +591,7 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 	}
 
 	@Test
-	public void testCAY1194() throws Exception {
+	public void testCAY1194() {
 		ClientMtTable1 parentMt = clientContext.newObject(ClientMtTable1.class);
 		ObjectContext child = runtime.newContext(clientContext);
 
@@ -685,7 +617,7 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 	}
 
 	@Test
-	public void testCommitChangesToParentOneToMany() throws Exception {
+	public void testCommitChangesToParentOneToMany() {
 		ObjectContext child = runtime.newContext(clientContext);
 
 		ClientMtTable1 master = child.newObject(ClientMtTable1.class);
@@ -712,14 +644,11 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 		final int[] newNodes = new int[1];
 
 		diffs.apply(new GraphChangeHandler() {
-
-			public void arcCreated(Object nodeId, Object targetNodeId,
-					Object arcId) {
+			public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
 				arcDiffs[0]++;
 			}
 
-			public void arcDeleted(Object nodeId, Object targetNodeId,
-					Object arcId) {
+			public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
 				arcDiffs[0]--;
 			}
 
@@ -730,8 +659,7 @@ public class NestedCayenneContextIT extends RemoteCayenneCase {
 			public void nodeIdChanged(Object nodeId, Object newId) {
 			}
 
-			public void nodePropertyChanged(Object nodeId, String property,
-					Object oldValue, Object newValue) {
+			public void nodePropertyChanged(Object nodeId, String property, Object oldValue, Object newValue) {
 			}
 
 			public void nodeRemoved(Object nodeId) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelIT.java b/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelIT.java
index 507d63d..62ecbe6 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelIT.java
@@ -43,7 +43,6 @@ import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.query.MockQuery;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.query.SortOrder;
 import org.apache.cayenne.remote.QueryMessage;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
@@ -53,7 +52,6 @@ import org.apache.cayenne.testdo.mt.ClientMtTable2;
 import org.apache.cayenne.testdo.mt.ClientMtTable3;
 import org.apache.cayenne.testdo.mt.MtTable1;
 import org.apache.cayenne.unit.di.DataChannelInterceptor;
-import org.apache.cayenne.unit.di.UnitTestClosure;
 import org.apache.cayenne.unit.di.client.ClientCase;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
@@ -98,7 +96,7 @@ public class ClientServerChannelIT extends ClientCase {
 		tMtTable3.setColumns("TABLE3_ID", "BINARY_COLUMN", "CHAR_COLUMN", "INT_COLUMN");
 	}
 
-	protected void createTwoMtTable1sAnd2sDataSet() throws Exception {
+	private void createTwoMtTable1sAnd2sDataSet() throws Exception {
 
 		tMtTable1.insert(1, "g1", "s1");
 		tMtTable1.insert(2, "g2", "s2");
@@ -108,7 +106,7 @@ public class ClientServerChannelIT extends ClientCase {
 	}
 
 	@Test
-	public void testGetEntityResolver() throws Exception {
+	public void testGetEntityResolver() {
 		EntityResolver resolver = clientServerChannel.getEntityResolver();
 		assertNotNull(resolver);
 		assertNull(resolver.getObjEntity(ClientMtTable1.class));
@@ -116,9 +114,9 @@ public class ClientServerChannelIT extends ClientCase {
 	}
 
 	@Test
-	public void testSynchronizeCommit() throws Exception {
+	public void testSynchronizeCommit() {
 
-		SelectQuery query = new SelectQuery(MtTable1.class);
+		SelectQuery<MtTable1> query = new SelectQuery<>(MtTable1.class);
 
 		// no changes...
 		clientServerChannel.onSync(serverContext, mock(GraphDiff.class), DataChannel.FLUSH_CASCADE_SYNC);
@@ -126,8 +124,9 @@ public class ClientServerChannelIT extends ClientCase {
 		assertEquals(0, serverContext.performQuery(query).size());
 
 		// introduce changes
-		clientServerChannel.onSync(serverContext, new NodeCreateOperation(new ObjectId("MtTable1")),
-				DataChannel.FLUSH_CASCADE_SYNC);
+		clientServerChannel.onSync(serverContext
+				, new NodeCreateOperation(new ObjectId("MtTable1"))
+				, DataChannel.FLUSH_CASCADE_SYNC);
 
 		assertEquals(1, serverContext.performQuery(query).size());
 	}
@@ -185,7 +184,7 @@ public class ClientServerChannelIT extends ClientCase {
 
 		tMtTable1.insert(65, "sub1", "xyz");
 
-		SelectQuery query = new SelectQuery(ClientMtTable1.class);
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
 		QueryResponse response = clientServerChannel.onQuery(null, query);
 
 		assertNotNull(response);
@@ -225,24 +224,21 @@ public class ClientServerChannelIT extends ClientCase {
 	public void testOnQueryPrefetchingToMany() throws Exception {
 		createTwoMtTable1sAnd2sDataSet();
 
-		SelectQuery query = new SelectQuery(ClientMtTable1.class);
-		query.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, SortOrder.ASCENDING);
-		query.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
+		query.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1.asc());
+		query.addPrefetch(ClientMtTable1.TABLE2ARRAY.joint());
 
 		final List<?> results = clientServerChannel.onQuery(null, query).firstList();
 
-		queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+		queryInterceptor.runWithQueriesBlocked(() -> {
+			ClientMtTable1 o1 = (ClientMtTable1) results.get(0);
+			assertNull(o1.getObjectContext());
 
-			public void execute() {
-				ClientMtTable1 o1 = (ClientMtTable1) results.get(0);
-				assertNull(o1.getObjectContext());
+			List<ClientMtTable2> children1 = o1.getTable2Array();
 
-				List<ClientMtTable2> children1 = o1.getTable2Array();
-
-				assertEquals(2, children1.size());
-				for (ClientMtTable2 o : children1) {
-					assertNull(o.getObjectContext());
-				}
+			assertEquals(2, children1.size());
+			for (ClientMtTable2 o : children1) {
+				assertNull(o.getObjectContext());
 			}
 		});
 	}
@@ -251,24 +247,20 @@ public class ClientServerChannelIT extends ClientCase {
 	public void testOnQueryPrefetchingToManyEmpty() throws Exception {
 		createTwoMtTable1sAnd2sDataSet();
 
-		SelectQuery q = new SelectQuery(ClientMtTable1.class);
-		q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, SortOrder.ASCENDING);
-		q.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
+		SelectQuery<ClientMtTable1> q = new SelectQuery<>(ClientMtTable1.class);
+		q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1.asc());
+		q.addPrefetch(ClientMtTable1.TABLE2ARRAY.joint());
 
 		final List<?> results = clientServerChannel.onQuery(null, q).firstList();
 
-		queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
-			public void execute() {
+		queryInterceptor.runWithQueriesBlocked(() -> {
+			ClientMtTable1 o2 = (ClientMtTable1) results.get(1);
+			assertNull(o2.getObjectContext());
 
-				ClientMtTable1 o2 = (ClientMtTable1) results.get(1);
-				assertNull(o2.getObjectContext());
-
-				List<?> children2 = o2.getTable2Array();
-				assertNotNull(children2);
-				assertFalse(((ValueHolder) children2).isFault());
-				assertEquals(0, children2.size());
-			}
+			List<?> children2 = o2.getTable2Array();
+			assertNotNull(children2);
+			assertFalse(((ValueHolder) children2).isFault());
+			assertEquals(0, children2.size());
 		});
 	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelQueryIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelQueryIT.java b/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelQueryIT.java
index d5afa0a..e809e35 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelQueryIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelQueryIT.java
@@ -88,8 +88,8 @@ public class ClientServerChannelQueryIT extends ClientCase {
     public void testPaginatedQueryServerCacheOverflow() throws Exception {
         createSevenMtTable1sDataSet();
 
-        SelectQuery query = new SelectQuery(ClientMtTable1.class);
-        query.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, SortOrder.ASCENDING);
+        SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
+        query.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1.asc());
         query.setPageSize(3);
 
         List<?> results = context.performQuery(query);
@@ -135,7 +135,7 @@ public class ClientServerChannelQueryIT extends ClientCase {
     public void testSelectQueryClientClassRoot() throws Exception {
         createTwoMtTable1sAnd2sDataSet();
 
-        SelectQuery q = new SelectQuery(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> q = new SelectQuery<>(ClientMtTable1.class);
         List<?> results = context.performQuery(q);
 
         assertEquals(2, results.size());
@@ -146,7 +146,8 @@ public class ClientServerChannelQueryIT extends ClientCase {
     public void testSelectQuerySimpleQualifier() throws Exception {
         createTwoMtTable1sAnd2sDataSet();
 
-        SelectQuery q = new SelectQuery(ClientMtTable1.class, ExpressionFactory.exp("globalAttribute1 = 'g1'"));
+        SelectQuery<ClientMtTable1> q = new SelectQuery<>(ClientMtTable1.class
+                , ExpressionFactory.exp("globalAttribute1 = 'g1'"));
         List<?> results = context.performQuery(q);
 
         assertEquals(1, results.size());
@@ -158,7 +159,8 @@ public class ClientServerChannelQueryIT extends ClientCase {
     public void testSelectQueryToManyRelationshipQualifier() throws Exception {
         createTwoMtTable1sAnd2sDataSet();
 
-        SelectQuery q = new SelectQuery(ClientMtTable1.class, ExpressionFactory.exp("table2Array.globalAttribute = 'g1'"));
+        SelectQuery<ClientMtTable1> q = new SelectQuery<>(ClientMtTable1.class
+                , ExpressionFactory.exp("table2Array.globalAttribute = 'g1'"));
         List<?> results = context.performQuery(q);
 
         assertEquals(1, results.size());
@@ -170,7 +172,7 @@ public class ClientServerChannelQueryIT extends ClientCase {
         createTwoMtTable1sAnd2sDataSet();
 
         SelectQuery q = new SelectQuery("MtTable1");
-        q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, SortOrder.ASCENDING);
+        q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1.asc());
         List<?> results = context.performQuery(q);
 
         assertEquals(2, results.size());
@@ -183,7 +185,7 @@ public class ClientServerChannelQueryIT extends ClientCase {
         // result wasn't coincidental.
 
         q.clearOrderings();
-        q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, SortOrder.DESCENDING);
+        q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1.desc());
         List<?> results1 = context.performQuery(q);
 
         assertEquals(2, results1.size());
@@ -197,8 +199,9 @@ public class ClientServerChannelQueryIT extends ClientCase {
     public void testSelectQueryPrefetchToOne() throws Exception {
         createTwoMtTable1sAnd2sDataSet();
 
-        SelectQuery q = new SelectQuery(ClientMtTable2.class, ExpressionFactory.exp("globalAttribute = 'g1'"));
-        q.addPrefetch(ClientMtTable2.TABLE1_PROPERTY);
+        SelectQuery<ClientMtTable2> q = new SelectQuery<>(ClientMtTable2.class
+                , ExpressionFactory.exp("globalAttribute = 'g1'"));
+        q.addPrefetch(ClientMtTable2.TABLE1.disjoint());
         List<?> results = context.performQuery(q);
 
         assertEquals(1, results.size());
@@ -219,8 +222,9 @@ public class ClientServerChannelQueryIT extends ClientCase {
     public void testSelectQueryPrefetchToMany() throws Exception {
         createTwoMtTable1sAnd2sDataSet();
 
-        SelectQuery q = new SelectQuery(ClientMtTable1.class, ExpressionFactory.exp("globalAttribute1 = 'g1'"));
-        q.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
+        SelectQuery<ClientMtTable1> q = new SelectQuery<>(ClientMtTable1.class
+                , ExpressionFactory.exp("globalAttribute1 = 'g1'"));
+        q.addPrefetch(ClientMtTable1.TABLE2ARRAY.joint());
         List<?> results = context.performQuery(q);
 
         assertEquals(1, results.size());


[2/4] cayenne git commit: CAY-2467 New type-aware Property API - update client cgen templates - update client tests

Posted by nt...@apache.org.
http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/query/ClientExpressionIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/query/ClientExpressionIT.java b/cayenne-client/src/test/java/org/apache/cayenne/query/ClientExpressionIT.java
index d7a9836..1a345a6 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/query/ClientExpressionIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/query/ClientExpressionIT.java
@@ -65,7 +65,7 @@ public class ClientExpressionIT extends ClientCase {
         tMtTable2.setColumns("TABLE2_ID", "TABLE1_ID", "GLOBAL_ATTRIBUTE");
     }
     
-    protected void createDataSet() throws Exception {
+    private void createDataSet() throws Exception {
         for(int i = 1; i <= 10; i++) {
             tMtTable1.insert(i ,"1_global" + i, "server" + i);
             tMtTable2.insert(i , i, "2_global" + i);
@@ -74,7 +74,7 @@ public class ClientExpressionIT extends ClientCase {
     }
 
     @Test
-    public void testPersistentValueInExpression() throws Exception {
+    public void testPersistentValueInExpression() {
         ClientMtTable1 t1 = context.newObject(ClientMtTable1.class);
         ClientMtTable1 t2 = context.newObject(ClientMtTable1.class);
         
@@ -89,18 +89,18 @@ public class ClientExpressionIT extends ClientCase {
     }
 
     @Test
-    public void testListInASTList() throws Exception {
+    public void testListInASTList() {
         ClientMtTable1 t1 = context.newObject(ClientMtTable1.class);
         ClientMtTable1 t2 = context.newObject(ClientMtTable1.class);
         
         context.commitChanges();
         
-        List<ClientMtTable1> table1List = new ArrayList<ClientMtTable1>();
+        List<ClientMtTable1> table1List = new ArrayList<>();
         table1List.add(t1);
         table1List.add(t2);
         
         // send list in expression factory
-        Expression list = ExpressionFactory.inExp(ClientMtTable2.TABLE1_PROPERTY, table1List);
+        Expression list = ClientMtTable2.TABLE1.in(table1List);
         
         Object[] values = (Object[])((ASTList)list.getOperand(1)).getOperand(0);
         assertEquals(t1.getObjectId(), values[0]);
@@ -117,19 +117,19 @@ public class ClientExpressionIT extends ClientCase {
     }
 
     @Test
-    public void testArrayInASTList() throws Exception {
+    public void testArrayInASTList() {
         ClientMtTable1 t1 = context.newObject(ClientMtTable1.class);
         ClientMtTable1 t2 = context.newObject(ClientMtTable1.class);
         ClientMtTable1 t3 = context.newObject(ClientMtTable1.class);
         
         context.commitChanges();
-        
+
         Object[] tArray = new Object[3];
         tArray[0] = t1;
         tArray[1] = t2;
         
         // send array in expression factory
-        Expression list = ExpressionFactory.inExp(ClientMtTable2.TABLE1_PROPERTY, tArray);
+        Expression list = ExpressionFactory.inExp(ClientMtTable2.TABLE1.getName(), tArray);
         tArray[2] = t3;
         
         Object[] values = (Object[])((ASTList)list.getOperand(1)).getOperand(0);
@@ -151,25 +151,25 @@ public class ClientExpressionIT extends ClientCase {
     @Test
     public void testExpressionFactoryMatch() throws Exception {
         createDataSet();
-        
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class);
+
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class);
         table1Query.addOrdering(new Ordering("db:TABLE1_ID", SortOrder.ASCENDING));
-        List<ClientMtTable1> table1List = context.select(table1Query);
-        
+        List<ClientMtTable1> table1List = table1Query.select(context);
+
         assertNotNull(table1List);
-        
+
         ClientMtTable1 element_1 = table1List.get(0);
         ClientMtTable1 element_2 = table1List.get(1);
-        
-        Expression exp = ExpressionFactory.matchExp(ClientMtTable2.TABLE1_PROPERTY, element_1);
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
-        List<ClientMtTable2> table2List = context.select(table2Query);
-        
+
+        Expression exp = ClientMtTable2.TABLE1.eq(element_1);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
+        List<ClientMtTable2> table2List = table2Query.select(context);
+
         assertNotNull(table2List);
         assertEquals(2, table2List.size());
-        
+
         exp = ExpressionFactory.matchExp(element_2);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
 
         assertNotNull(table2List);
@@ -180,7 +180,7 @@ public class ClientExpressionIT extends ClientCase {
     public void testExpressionFactoryMatchAll() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class);
         table2Query.addOrdering(new Ordering("db:TABLE2_ID", SortOrder.ASCENDING));
         List<ClientMtTable2> table2List = context.select(table2Query);
         
@@ -189,9 +189,9 @@ public class ClientExpressionIT extends ClientCase {
         
         assertEquals(element_1.getTable1(), element_2.getTable1());
         
-        Expression exp = ExpressionFactory.matchAllExp("|"+ClientMtTable1.TABLE2ARRAY_PROPERTY, Arrays.asList(element_1, element_2));
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class, exp);
-        List<ClientMtTable1> table1List = context.select(table1Query);
+        Expression exp = ExpressionFactory.matchAllExp("|"+ClientMtTable1.TABLE2ARRAY.getName(), Arrays.asList(element_1, element_2));
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class, exp);
+        List<ClientMtTable1> table1List = table1Query.select(context);
         
         assertEquals(1, table1List.size());
     }
@@ -200,7 +200,7 @@ public class ClientExpressionIT extends ClientCase {
     public void testExpressionFactoryMatchAny() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class);
         table2Query.addOrdering(new Ordering("db:TABLE2_ID", SortOrder.ASCENDING));
         List<ClientMtTable2> table2List = context.select(table2Query);
         
@@ -208,7 +208,7 @@ public class ClientExpressionIT extends ClientCase {
         ClientMtTable2 element_2 = table2List.get(10);
         
         Expression exp = ExpressionFactory.matchAnyExp(element_1, element_2);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(2, table2List.size());
@@ -218,7 +218,7 @@ public class ClientExpressionIT extends ClientCase {
     public void testExpressionFactoryIn() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class);
         table1Query.addOrdering(new Ordering("db:TABLE1_ID", SortOrder.ASCENDING));
         List<ClientMtTable1> table1List = context.select(table1Query);
         
@@ -226,15 +226,15 @@ public class ClientExpressionIT extends ClientCase {
         ClientMtTable1 element_8 = table1List.get(7);
         
         // IN expression via Collection
-        Expression exp = ExpressionFactory.inExp(ClientMtTable2.TABLE1_PROPERTY, table1List.subList(3, 6));
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        Expression exp = ExpressionFactory.inExp(ClientMtTable2.TABLE1.getName(), table1List.subList(3, 6));
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         List<ClientMtTable2> table2List = context.select(table2Query);
         
         assertEquals(6, table2List.size());
         
         // IN expression via Array
-        exp = ExpressionFactory.inExp(ClientMtTable2.TABLE1_PROPERTY, element_3, element_8);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        exp = ExpressionFactory.inExp(ClientMtTable2.TABLE1.getName(), element_3, element_8);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(4, table2List.size());
@@ -244,7 +244,7 @@ public class ClientExpressionIT extends ClientCase {
     public void testExpressionFactoryBetween() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class);
         table1Query.addOrdering(new Ordering("db:TABLE1_ID", SortOrder.ASCENDING));
         List<ClientMtTable1> table1List = context.select(table1Query);
         
@@ -252,15 +252,15 @@ public class ClientExpressionIT extends ClientCase {
         ClientMtTable1 element_7 = table1List.get(6);
         
         // between
-        Expression exp = ExpressionFactory.betweenExp(ClientMtTable2.TABLE1_PROPERTY, element_1, element_7);
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        Expression exp = ExpressionFactory.betweenExp(ClientMtTable2.TABLE1.getName(), element_1, element_7);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         List<ClientMtTable2> table2List = context.select(table2Query);
         
         assertEquals(14, table2List.size());
         
         // not between
-        exp = ExpressionFactory.notBetweenExp(ClientMtTable2.TABLE1_PROPERTY, element_1, element_7);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        exp = ExpressionFactory.notBetweenExp(ClientMtTable2.TABLE1.getName(), element_1, element_7);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(6, table2List.size());
@@ -270,36 +270,36 @@ public class ClientExpressionIT extends ClientCase {
     public void testExpressionFactoryOperators() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class);
         table1Query.addOrdering(new Ordering("db:TABLE1_ID", SortOrder.ASCENDING));
         List<ClientMtTable1> table1List = context.select(table1Query);
         
         ClientMtTable1 element_7 = table1List.get(6);
         
         // greater than, ">"
-        Expression exp = ExpressionFactory.greaterExp(ClientMtTable2.TABLE1_PROPERTY, element_7);
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        Expression exp = ExpressionFactory.greaterExp(ClientMtTable2.TABLE1.getName(), element_7);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         List<ClientMtTable2> table2List = context.select(table2Query);
         
         assertEquals(6, table2List.size());
         
         // greater than or equal, ">="
-        exp = ExpressionFactory.greaterOrEqualExp(ClientMtTable2.TABLE1_PROPERTY, element_7);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        exp = ExpressionFactory.greaterOrEqualExp(ClientMtTable2.TABLE1.getName(), element_7);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(8, table2List.size());
         
         // less than, "<"
-        exp = ExpressionFactory.lessExp(ClientMtTable2.TABLE1_PROPERTY, element_7);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        exp = ExpressionFactory.lessExp(ClientMtTable2.TABLE1.getName(), element_7);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(12, table2List.size());
         
         // less than or equal, "<="
-        exp = ExpressionFactory.lessOrEqualExp(ClientMtTable2.TABLE1_PROPERTY, element_7);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        exp = ExpressionFactory.lessOrEqualExp(ClientMtTable2.TABLE1.getName(), element_7);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(14, table2List.size());
@@ -309,7 +309,7 @@ public class ClientExpressionIT extends ClientCase {
     public void testParams() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class);
         table1Query.addOrdering(new Ordering("db:TABLE1_ID", SortOrder.ASCENDING));
         List<ClientMtTable1> table1List = context.select(table1Query);
         
@@ -318,13 +318,13 @@ public class ClientExpressionIT extends ClientCase {
         
         Expression exp = ExpressionFactory.exp("table1 = $attr");
         exp = exp.params(Collections.singletonMap("attr", element_1));
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         List<ClientMtTable2> table2List = context.select(table2Query);
         
         assertEquals(2, table2List.size());
         
         exp = exp.andExp(ExpressionFactory.exp("table1 = $attr")).params(Collections.singletonMap("attr", element_5));
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(0, table2List.size());

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/query/ClientSelectQueryExpressionIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/query/ClientSelectQueryExpressionIT.java b/cayenne-client/src/test/java/org/apache/cayenne/query/ClientSelectQueryExpressionIT.java
index 3d0c05a..5ccdea2 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/query/ClientSelectQueryExpressionIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/query/ClientSelectQueryExpressionIT.java
@@ -21,7 +21,6 @@ package org.apache.cayenne.query;
 import org.apache.cayenne.CayenneContext;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.mt.ClientMtTable1;
@@ -52,7 +51,7 @@ public class ClientSelectQueryExpressionIT extends ClientCase {
         tMtTable1.setColumns("TABLE1_ID", "GLOBAL_ATTRIBUTE1", "SERVER_ATTRIBUTE1");
     }
 
-    protected void createMtTable1DataSet() throws Exception {
+    private void createMtTable1DataSet() throws Exception {
         for (int i = 1; i <= 20; i++) {
             tMtTable1.insert(i, "globalAttr" + i, "serverAttr" + i);
         }
@@ -64,7 +63,7 @@ public class ClientSelectQueryExpressionIT extends ClientCase {
 
         List<ClientMtTable1> mtTable1List = context.select(SelectQuery.query(ClientMtTable1.class));
 
-        Expression exp = ExpressionFactory.likeExp(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, "globalAttr1%");
+        Expression exp = ClientMtTable1.GLOBAL_ATTRIBUTE1.like("globalAttr1%");
         exp.filterObjects(mtTable1List);
 
         List<ClientMtTable1> matchingMtTableList = context.select(SelectQuery.query(ClientMtTable1.class, exp));

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsIT.java b/cayenne-client/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsIT.java
index 4c3b79b..1bfdb24 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsIT.java
@@ -103,7 +103,7 @@ public class ClientChannelServerDiffsIT extends ClientCase {
     @Test
     public void testReturnDiffInPrePersist() {
 
-        final List<GenericDiff> diffs = new ArrayList<GenericDiff>();
+        final List<GenericDiff> diffs = new ArrayList<>();
         final NoopGraphChangeHandler diffReader = new NoopGraphChangeHandler() {
 
             @Override
@@ -168,7 +168,7 @@ public class ClientChannelServerDiffsIT extends ClientCase {
             assertEquals(2, diffReader.size);
             assertEquals(1, diffs.size());
             assertEquals(tempId, diffs.get(0).sourceId);
-            assertEquals(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, diffs.get(0).property);
+            assertEquals(ClientMtTable1.GLOBAL_ATTRIBUTE1.getName(), diffs.get(0).property);
             assertNull(diffs.get(0).oldValue);
             assertEquals("XXX", diffs.get(0).newValue);
         }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/remote/RemoteIncrementalFaultListIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/remote/RemoteIncrementalFaultListIT.java b/cayenne-client/src/test/java/org/apache/cayenne/remote/RemoteIncrementalFaultListIT.java
index c5df3a6..3d7fb3a 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/remote/RemoteIncrementalFaultListIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/remote/RemoteIncrementalFaultListIT.java
@@ -23,7 +23,6 @@ import org.apache.cayenne.CayenneContext;
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.query.SortOrder;
 import org.apache.cayenne.test.jdbc.DBHelper;
@@ -68,7 +67,7 @@ public class RemoteIncrementalFaultListIT extends ClientCase {
 				"SERVER_ATTRIBUTE1");
 	}
 
-	protected void createObjectsDataSet() throws Exception {
+	private void createObjectsDataSet() throws Exception {
 		tMTTable.insert(1, "g1", "s1");
 		tMTTable.insert(2, "g2", "s2");
 		tMTTable.insert(3, "g3", "s3");
@@ -100,14 +99,12 @@ public class RemoteIncrementalFaultListIT extends ClientCase {
 
 		createObjectsDataSet();
 
-		SelectQuery<ClientMtTable1> query = new SelectQuery<ClientMtTable1>(
-				ClientMtTable1.class);
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
 
 		// make sure total number of objects is not divisable
 		// by the page size, to test the last smaller page
 		query.setPageSize(pageSize);
-		query.addOrdering("db:" + MtTable1.TABLE1_ID_PK_COLUMN,
-				SortOrder.ASCENDING);
+		query.addOrdering("db:" + MtTable1.TABLE1_ID_PK_COLUMN, SortOrder.ASCENDING);
 
 		list = new RemoteIncrementalFaultList(clientContext, query);
 	}
@@ -161,14 +158,12 @@ public class RemoteIncrementalFaultListIT extends ClientCase {
 			assertTrue(obj instanceof Persistent);
 
 			// iterator must be resolved page by page
-			int expectedResolved = list.pageIndex(counter) * list.getPageSize()
-					+ list.getPageSize();
+			int expectedResolved = list.pageIndex(counter) * list.getPageSize() + list.getPageSize();
 			if (expectedResolved > list.size()) {
 				expectedResolved = list.size();
 			}
 
-			assertEquals(list.size() - expectedResolved,
-					list.getUnfetchedObjects());
+			assertEquals(list.size() - expectedResolved, list.getUnfetchedObjects());
 
 			counter++;
 		}
@@ -229,35 +224,29 @@ public class RemoteIncrementalFaultListIT extends ClientCase {
 	public void testIndexOf() throws Exception {
 		prepareList(6);
 
-		Expression qual = ExpressionFactory.matchExp(
-				ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, "g20");
-		SelectQuery<ClientMtTable1> query = new SelectQuery<ClientMtTable1>(
-				ClientMtTable1.class, qual);
+		Expression qual = ClientMtTable1.GLOBAL_ATTRIBUTE1.eq("g20");
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class, qual);
 		List<?> artists = list.context.performQuery(query);
 
 		assertEquals(1, artists.size());
 
 		ClientMtTable1 row = (ClientMtTable1) artists.get(0);
 		assertEquals(19, list.indexOf(row));
-		assertEquals(-1,
-				list.indexOf(list.context.newObject(ClientMtTable1.class)));
+		assertEquals(-1, list.indexOf(list.context.newObject(ClientMtTable1.class)));
 	}
 
 	@Test
 	public void testLastIndexOf() throws Exception {
 		prepareList(6);
-		Expression qual = ExpressionFactory.matchExp(
-				ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, "g20");
-		SelectQuery<ClientMtTable1> query = new SelectQuery<ClientMtTable1>(
-				ClientMtTable1.class, qual);
+		Expression qual = ClientMtTable1.GLOBAL_ATTRIBUTE1.eq("g20");
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class, qual);
 		List<?> objects = list.context.performQuery(query);
 
 		assertEquals(1, objects.size());
 
 		ClientMtTable1 row = (ClientMtTable1) objects.get(0);
 		assertEquals(19, list.lastIndexOf(row));
-		assertEquals(-1,
-				list.lastIndexOf(list.context.newObject(ClientMtTable1.class)));
+		assertEquals(-1, list.lastIndexOf(list.context.newObject(ClientMtTable1.class)));
 	}
 
 	private void doTestIterator(int size) throws Exception {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable1.java
----------------------------------------------------------------------
diff --git a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable1.java b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable1.java
index e699ccf..9e36772 100644
--- a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable1.java
+++ b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable1.java
@@ -7,7 +7,10 @@ import java.util.Date;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.rop.protostuff.persistent.ClientMtTable2;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -18,13 +21,13 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _ClientMtTable1 extends PersistentObject {
 
-    public static final Property<LocalDate> DATE_ATTRIBUTE = Property.create("dateAttribute", LocalDate.class);
-    public static final Property<String> GLOBAL_ATTRIBUTE = Property.create("globalAttribute", String.class);
-    public static final Property<Date> OLD_DATE_ATTRIBUTE = Property.create("oldDateAttribute", Date.class);
-    public static final Property<String> SERVER_ATTRIBUTE = Property.create("serverAttribute", String.class);
-    public static final Property<LocalTime> TIME_ATTRIBUTE = Property.create("timeAttribute", LocalTime.class);
-    public static final Property<LocalDateTime> TIMESTAMP_ATTRIBUTE = Property.create("timestampAttribute", LocalDateTime.class);
-    public static final Property<List<ClientMtTable2>> TABLE2ARRAY = Property.create("table2Array", List.class);
+    public static final DateProperty<LocalDate> DATE_ATTRIBUTE = PropertyFactory.createDate("dateAttribute", LocalDate.class);
+    public static final StringProperty<String> GLOBAL_ATTRIBUTE = PropertyFactory.createString("globalAttribute", String.class);
+    public static final DateProperty<Date> OLD_DATE_ATTRIBUTE = PropertyFactory.createDate("oldDateAttribute", Date.class);
+    public static final StringProperty<String> SERVER_ATTRIBUTE = PropertyFactory.createString("serverAttribute", String.class);
+    public static final DateProperty<LocalTime> TIME_ATTRIBUTE = PropertyFactory.createDate("timeAttribute", LocalTime.class);
+    public static final DateProperty<LocalDateTime> TIMESTAMP_ATTRIBUTE = PropertyFactory.createDate("timestampAttribute", LocalDateTime.class);
+    public static final ListProperty<ClientMtTable2> TABLE2ARRAY = PropertyFactory.createList("table2Array", ClientMtTable2.class);
 
     protected LocalDate dateAttribute;
     protected String globalAttribute;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable2.java
----------------------------------------------------------------------
diff --git a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable2.java b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable2.java
index 6128e40..6020a3e 100644
--- a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable2.java
+++ b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable2.java
@@ -2,7 +2,9 @@ package org.apache.cayenne.rop.protostuff.persistent.auto;
 
 import org.apache.cayenne.PersistentObject;
 import org.apache.cayenne.ValueHolder;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.rop.protostuff.persistent.ClientMtTable1;
 import org.apache.cayenne.util.PersistentObjectHolder;
 
@@ -13,8 +15,8 @@ import org.apache.cayenne.util.PersistentObjectHolder;
  */
 public abstract class _ClientMtTable2 extends PersistentObject {
 
-    public static final Property<String> GLOBAL_ATTRIBUTE = Property.create("globalAttribute", String.class);
-    public static final Property<ClientMtTable1> TABLE1 = Property.create("table1", ClientMtTable1.class);
+    public static final StringProperty<String> GLOBAL_ATTRIBUTE = PropertyFactory.createString("globalAttribute", String.class);
+    public static final EntityProperty<ClientMtTable1> TABLE1 = PropertyFactory.createEntity("table1", ClientMtTable1.class);
 
     protected String globalAttribute;
     protected ValueHolder<ClientMtTable1> table1;
@@ -49,7 +51,6 @@ public abstract class _ClientMtTable2 extends PersistentObject {
     public void setTable1(ClientMtTable1 table1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table1", true);
-            objectContext.propertyChanged(this, "table1", this.table1.getValueDirectly(), table1);
         } else if (this.table1 == null) {
         	this.table1 = new PersistentObjectHolder<>(this, "table1");
 		}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
index 9675a0c..883bca0 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
@@ -23,6 +23,9 @@ import org.apache.cayenne.DataRow;
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.PersistenceState;
 import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
@@ -105,6 +108,20 @@ public class EmbeddingIT extends ServerCase {
     }
 
     @Test
+    public void testEmbeddableInWhere() throws Exception {
+        createSelectDataSet();
+
+        Embeddable1 embeddable1 = new Embeddable1();
+        embeddable1.setEmbedded10("e1");
+        embeddable1.setEmbedded20("e2");
+
+        Expression exp = ExpressionFactory.matchDbExp(Embeddable1.EMBEDDED10.getName().toUpperCase(), "e1");
+
+
+        ObjectSelect.query(EmbedEntity1.class).where(exp).select(context);
+    }
+
+    @Test
     public void testInsert() throws Exception {
 
         EmbedEntity1 o1 = context.newObject(EmbedEntity1.class);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1.java
index 8178b9d..e249272 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1.java
@@ -3,7 +3,11 @@ package org.apache.cayenne.testdo.mt.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.testdo.mt.ClientMtTable2;
+import org.apache.cayenne.util.PersistentObjectList;
 
 /**
  * A generated persistent class mapped as "MtTable1" Cayenne entity. It is a good idea to
@@ -12,9 +16,9 @@ import org.apache.cayenne.testdo.mt.ClientMtTable2;
  */
 public abstract class _ClientMtTable1 extends PersistentObject {
 
-    public static final String GLOBAL_ATTRIBUTE1_PROPERTY = "globalAttribute1";
-    public static final String SERVER_ATTRIBUTE1_PROPERTY = "serverAttribute1";
-    public static final String TABLE2ARRAY_PROPERTY = "table2Array";
+    public static final StringProperty<String> GLOBAL_ATTRIBUTE1 = PropertyFactory.createString("globalAttribute1", String.class);
+    public static final StringProperty<String> SERVER_ATTRIBUTE1 = PropertyFactory.createString("serverAttribute1", String.class);
+    public static final ListProperty<ClientMtTable2> TABLE2ARRAY = PropertyFactory.createList("table2Array", ClientMtTable2.class);
 
     protected String globalAttribute1;
     protected String serverAttribute1;
@@ -27,18 +31,14 @@ public abstract class _ClientMtTable1 extends PersistentObject {
 
         return globalAttribute1;
     }
+
     public void setGlobalAttribute1(String globalAttribute1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "globalAttribute1", false);
+            objectContext.propertyChanged(this, "globalAttribute1", this.globalAttribute1, globalAttribute1);
         }
 
-        Object oldValue = this.globalAttribute1;
         this.globalAttribute1 = globalAttribute1;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "globalAttribute1", oldValue, globalAttribute1);
-        }
     }
 
     public String getServerAttribute1() {
@@ -48,38 +48,42 @@ public abstract class _ClientMtTable1 extends PersistentObject {
 
         return serverAttribute1;
     }
+
     public void setServerAttribute1(String serverAttribute1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "serverAttribute1", false);
+            objectContext.propertyChanged(this, "serverAttribute1", this.serverAttribute1, serverAttribute1);
         }
 
-        Object oldValue = this.serverAttribute1;
         this.serverAttribute1 = serverAttribute1;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "serverAttribute1", oldValue, serverAttribute1);
-        }
     }
 
     public List<ClientMtTable2> getTable2Array() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         return table2Array;
     }
+
     public void addToTable2Array(ClientMtTable2 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         this.table2Array.add(object);
     }
+
     public void removeFromTable2Array(ClientMtTable2 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         this.table2Array.remove(object);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass1.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass1.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass1.java
index 259af58..b54bf1b 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass1.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass1.java
@@ -1,6 +1,7 @@
 package org.apache.cayenne.testdo.mt.auto;
 
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.testdo.mt.ClientMtTable1;
 
 /**
@@ -10,10 +11,7 @@ import org.apache.cayenne.testdo.mt.ClientMtTable1;
  */
 public abstract class _ClientMtTable1Subclass1 extends ClientMtTable1 {
 
-    @Deprecated
-    public static final String SUBCLASS1ATTRIBUTE1_PROPERTY = "subclass1Attribute1";
-
-    public static final Property<String> SUBCLASS1ATTRIBUTE1 = Property.create("subclass1Attribute1", String.class);
+    public static final StringProperty<String> SUBCLASS1ATTRIBUTE1 = PropertyFactory.createString("subclass1Attribute1", String.class);
 
     protected String subclass1Attribute1;
 
@@ -24,17 +22,13 @@ public abstract class _ClientMtTable1Subclass1 extends ClientMtTable1 {
 
         return subclass1Attribute1;
     }
+
     public void setSubclass1Attribute1(String subclass1Attribute1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "subclass1Attribute1", false);
+            objectContext.propertyChanged(this, "subclass1Attribute1", this.subclass1Attribute1, subclass1Attribute1);
         }
 
-        Object oldValue = this.subclass1Attribute1;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "subclass1Attribute1", oldValue, subclass1Attribute1);
-        }
-        
         this.subclass1Attribute1 = subclass1Attribute1;
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass2.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass2.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass2.java
index eb29449..e4efeb5 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass2.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass2.java
@@ -1,6 +1,7 @@
 package org.apache.cayenne.testdo.mt.auto;
 
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.testdo.mt.ClientMtTable1;
 
 /**
@@ -10,10 +11,7 @@ import org.apache.cayenne.testdo.mt.ClientMtTable1;
  */
 public abstract class _ClientMtTable1Subclass2 extends ClientMtTable1 {
 
-    @Deprecated
-    public static final String SUBCLASS2ATTRIBUTE1_PROPERTY = "subclass2Attribute1";
-
-    public static final Property<String> SUBCLASS2ATTRIBUTE1 = Property.create("subclass2Attribute1", String.class);
+    public static final StringProperty<String> SUBCLASS2ATTRIBUTE1 = PropertyFactory.createString("subclass2Attribute1", String.class);
 
     protected String subclass2Attribute1;
 
@@ -24,17 +22,13 @@ public abstract class _ClientMtTable1Subclass2 extends ClientMtTable1 {
 
         return subclass2Attribute1;
     }
+
     public void setSubclass2Attribute1(String subclass2Attribute1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "subclass2Attribute1", false);
+            objectContext.propertyChanged(this, "subclass2Attribute1", this.subclass2Attribute1, subclass2Attribute1);
         }
 
-        Object oldValue = this.subclass2Attribute1;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "subclass2Attribute1", oldValue, subclass2Attribute1);
-        }
-        
         this.subclass2Attribute1 = subclass2Attribute1;
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable2.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable2.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable2.java
index a8ac1f5..77c9b60 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable2.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable2.java
@@ -2,8 +2,12 @@ package org.apache.cayenne.testdo.mt.auto;
 
 import org.apache.cayenne.PersistentObject;
 import org.apache.cayenne.ValueHolder;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.testdo.mt.ClientMtTable1;
 import org.apache.cayenne.testdo.mt.ClientMtTable3;
+import org.apache.cayenne.util.PersistentObjectHolder;
 
 /**
  * A generated persistent class mapped as "MtTable2" Cayenne entity. It is a good idea to
@@ -12,13 +16,13 @@ import org.apache.cayenne.testdo.mt.ClientMtTable3;
  */
 public abstract class _ClientMtTable2 extends PersistentObject {
 
-    public static final String GLOBAL_ATTRIBUTE_PROPERTY = "globalAttribute";
-    public static final String TABLE1_PROPERTY = "table1";
-    public static final String TABLE3_PROPERTY = "table3";
+    public static final StringProperty<String> GLOBAL_ATTRIBUTE = PropertyFactory.createString("globalAttribute", String.class);
+    public static final EntityProperty<ClientMtTable1> TABLE1 = PropertyFactory.createEntity("table1", ClientMtTable1.class);
+    public static final EntityProperty<ClientMtTable3> TABLE3 = PropertyFactory.createEntity("table3", ClientMtTable3.class);
 
     protected String globalAttribute;
-    protected ValueHolder table1;
-    protected ValueHolder table3;
+    protected ValueHolder<ClientMtTable1> table1;
+    protected ValueHolder<ClientMtTable3> table3;
 
     public String getGlobalAttribute() {
         if(objectContext != null) {
@@ -27,31 +31,32 @@ public abstract class _ClientMtTable2 extends PersistentObject {
 
         return globalAttribute;
     }
+
     public void setGlobalAttribute(String globalAttribute) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "globalAttribute", false);
+            objectContext.propertyChanged(this, "globalAttribute", this.globalAttribute, globalAttribute);
         }
 
-        Object oldValue = this.globalAttribute;
         this.globalAttribute = globalAttribute;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "globalAttribute", oldValue, globalAttribute);
-        }
     }
 
     public ClientMtTable1 getTable1() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table1", true);
-        }
+        } else if (this.table1 == null) {
+        	this.table1 = new PersistentObjectHolder<>(this, "table1");
+		}
 
-        return (ClientMtTable1) table1.getValue();
+        return table1.getValue();
     }
+
     public void setTable1(ClientMtTable1 table1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table1", true);
-        }
+        } else if (this.table1 == null) {
+        	this.table1 = new PersistentObjectHolder<>(this, "table1");
+		}
 
         this.table1.setValue(table1);
     }
@@ -59,14 +64,19 @@ public abstract class _ClientMtTable2 extends PersistentObject {
     public ClientMtTable3 getTable3() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table3", true);
-        }
+        } else if (this.table3 == null) {
+        	this.table3 = new PersistentObjectHolder<>(this, "table3");
+		}
 
-        return (ClientMtTable3) table3.getValue();
+        return table3.getValue();
     }
+
     public void setTable3(ClientMtTable3 table3) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table3", true);
-        }
+        } else if (this.table3 == null) {
+        	this.table3 = new PersistentObjectHolder<>(this, "table3");
+		}
 
         this.table3.setValue(table3);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable3.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable3.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable3.java
index cf84a87..e8e52c1 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable3.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable3.java
@@ -3,7 +3,13 @@ package org.apache.cayenne.testdo.mt.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.exp.property.BaseProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.NumericProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.testdo.mt.ClientMtTable2;
+import org.apache.cayenne.util.PersistentObjectList;
 
 /**
  * A generated persistent class mapped as "MtTable3" Cayenne entity. It is a good idea to
@@ -12,10 +18,10 @@ import org.apache.cayenne.testdo.mt.ClientMtTable2;
  */
 public abstract class _ClientMtTable3 extends PersistentObject {
 
-    public static final String BINARY_COLUMN_PROPERTY = "binaryColumn";
-    public static final String CHAR_COLUMN_PROPERTY = "charColumn";
-    public static final String INT_COLUMN_PROPERTY = "intColumn";
-    public static final String TABLE2ARRAY_PROPERTY = "table2Array";
+    public static final BaseProperty<byte[]> BINARY_COLUMN = PropertyFactory.createBase("binaryColumn", byte[].class);
+    public static final StringProperty<String> CHAR_COLUMN = PropertyFactory.createString("charColumn", String.class);
+    public static final NumericProperty<Integer> INT_COLUMN = PropertyFactory.createNumeric("intColumn", Integer.class);
+    public static final ListProperty<ClientMtTable2> TABLE2ARRAY = PropertyFactory.createList("table2Array", ClientMtTable2.class);
 
     protected byte[] binaryColumn;
     protected String charColumn;
@@ -29,18 +35,14 @@ public abstract class _ClientMtTable3 extends PersistentObject {
 
         return binaryColumn;
     }
+
     public void setBinaryColumn(byte[] binaryColumn) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "binaryColumn", false);
+            objectContext.propertyChanged(this, "binaryColumn", this.binaryColumn, binaryColumn);
         }
 
-        Object oldValue = this.binaryColumn;
         this.binaryColumn = binaryColumn;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "binaryColumn", oldValue, binaryColumn);
-        }
     }
 
     public String getCharColumn() {
@@ -50,18 +52,14 @@ public abstract class _ClientMtTable3 extends PersistentObject {
 
         return charColumn;
     }
+
     public void setCharColumn(String charColumn) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "charColumn", false);
+            objectContext.propertyChanged(this, "charColumn", this.charColumn, charColumn);
         }
 
-        Object oldValue = this.charColumn;
         this.charColumn = charColumn;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "charColumn", oldValue, charColumn);
-        }
     }
 
     public Integer getIntColumn() {
@@ -71,38 +69,42 @@ public abstract class _ClientMtTable3 extends PersistentObject {
 
         return intColumn;
     }
+
     public void setIntColumn(Integer intColumn) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "intColumn", false);
+            objectContext.propertyChanged(this, "intColumn", this.intColumn, intColumn);
         }
 
-        Object oldValue = this.intColumn;
         this.intColumn = intColumn;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "intColumn", oldValue, intColumn);
-        }
     }
 
     public List<ClientMtTable2> getTable2Array() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         return table2Array;
     }
+
     public void addToTable2Array(ClientMtTable2 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         this.table2Array.add(object);
     }
+
     public void removeFromTable2Array(ClientMtTable2 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         this.table2Array.remove(object);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable4.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable4.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable4.java
index 92c6f1b..adeb8e4 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable4.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable4.java
@@ -3,7 +3,10 @@ package org.apache.cayenne.testdo.mt.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.testdo.mt.ClientMtTable5;
+import org.apache.cayenne.util.PersistentObjectList;
 
 /**
  * A generated persistent class mapped as "MtTable4" Cayenne entity. It is a good idea to
@@ -12,28 +15,36 @@ import org.apache.cayenne.testdo.mt.ClientMtTable5;
  */
 public abstract class _ClientMtTable4 extends PersistentObject {
 
-    public static final String TABLE5S_PROPERTY = "table5s";
+    public static final ListProperty<ClientMtTable5> TABLE5S = PropertyFactory.createList("table5s", ClientMtTable5.class);
 
     protected List<ClientMtTable5> table5s;
 
     public List<ClientMtTable5> getTable5s() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table5s", true);
-        }
+        } else if (this.table5s == null) {
+        	this.table5s = new PersistentObjectList<>(this, "table5s");
+		}
 
         return table5s;
     }
+
     public void addToTable5s(ClientMtTable5 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table5s", true);
-        }
+        } else if (this.table5s == null) {
+        	this.table5s = new PersistentObjectList<>(this, "table5s");
+		}
 
         this.table5s.add(object);
     }
+
     public void removeFromTable5s(ClientMtTable5 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table5s", true);
-        }
+        } else if (this.table5s == null) {
+        	this.table5s = new PersistentObjectList<>(this, "table5s");
+		}
 
         this.table5s.remove(object);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable5.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable5.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable5.java
index 3eb221c..17672a3 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable5.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable5.java
@@ -3,7 +3,10 @@ package org.apache.cayenne.testdo.mt.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.testdo.mt.ClientMtTable4;
+import org.apache.cayenne.util.PersistentObjectList;
 
 /**
  * A generated persistent class mapped as "MtTable5" Cayenne entity. It is a good idea to
@@ -12,28 +15,36 @@ import org.apache.cayenne.testdo.mt.ClientMtTable4;
  */
 public abstract class _ClientMtTable5 extends PersistentObject {
 
-    public static final String TABLE4S_PROPERTY = "table4s";
+    public static final ListProperty<ClientMtTable4> TABLE4S = PropertyFactory.createList("table4s", ClientMtTable4.class);
 
     protected List<ClientMtTable4> table4s;
 
     public List<ClientMtTable4> getTable4s() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table4s", true);
-        }
+        } else if (this.table4s == null) {
+        	this.table4s = new PersistentObjectList<>(this, "table4s");
+		}
 
         return table4s;
     }
+
     public void addToTable4s(ClientMtTable4 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table4s", true);
-        }
+        } else if (this.table4s == null) {
+        	this.table4s = new PersistentObjectList<>(this, "table4s");
+		}
 
         this.table4s.add(object);
     }
+
     public void removeFromTable4s(ClientMtTable4 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table4s", true);
-        }
+        } else if (this.table4s == null) {
+        	this.table4s = new PersistentObjectList<>(this, "table4s");
+		}
 
         this.table4s.remove(object);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/util/PersistentObjectHolderTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/util/PersistentObjectHolderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/util/PersistentObjectHolderTest.java
index ca9080b..18a2519 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/util/PersistentObjectHolderTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/util/PersistentObjectHolderTest.java
@@ -41,7 +41,7 @@ public class PersistentObjectHolderTest {
         ClientMtTable2 o = new ClientMtTable2();
         o.setPersistenceState(PersistenceState.COMMITTED);
         o.setObjectContext(context);
-        PersistentObjectHolder holder = new PersistentObjectHolder(o, ClientMtTable2.TABLE1_PROPERTY);
+        PersistentObjectHolder holder = new PersistentObjectHolder(o, ClientMtTable2.TABLE1.getName());
 
         assertTrue(holder.isFault());
         ClientMtTable1 o1 = new ClientMtTable1();
@@ -59,7 +59,7 @@ public class PersistentObjectHolderTest {
         ClientMtTable2 o = new ClientMtTable2();
         o.setPersistenceState(PersistenceState.COMMITTED);
         o.setObjectContext(context);
-        PersistentObjectHolder holder = new PersistentObjectHolder(o, ClientMtTable2.TABLE1_PROPERTY);
+        PersistentObjectHolder holder = new PersistentObjectHolder(o, ClientMtTable2.TABLE1.getName());
 
         assertTrue(holder.isFault());
         ClientMtTable1 o1 = new ClientMtTable1();

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
index b478b8d..052709b 100644
--- a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
+++ b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
@@ -4,7 +4,10 @@ import java.time.LocalDate;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -15,9 +18,9 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _Artist extends PersistentObject {
 
-    public static final Property<LocalDate> DATE_OF_BIRTH = Property.create("dateOfBirth", LocalDate.class);
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final DateProperty<LocalDate> DATE_OF_BIRTH = PropertyFactory.createDate("dateOfBirth", LocalDate.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected LocalDate dateOfBirth;
     protected String name;
@@ -30,17 +33,13 @@ public abstract class _Artist extends PersistentObject {
 
         return dateOfBirth;
     }
+
     public void setDateOfBirth(LocalDate dateOfBirth) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "dateOfBirth", false);
+            objectContext.propertyChanged(this, "dateOfBirth", this.dateOfBirth, dateOfBirth);
         }
 
-        Object oldValue = this.dateOfBirth;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "dateOfBirth", oldValue, dateOfBirth);
-        }
-        
         this.dateOfBirth = dateOfBirth;
     }
 
@@ -51,17 +50,13 @@ public abstract class _Artist extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -69,25 +64,27 @@ public abstract class _Artist extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
index 7c59c64..57ccb07 100644
--- a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
+++ b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
@@ -3,7 +3,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -14,8 +16,8 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _Gallery extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected String name;
     protected List<Painting> paintings;
@@ -27,17 +29,13 @@ public abstract class _Gallery extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -45,25 +43,27 @@ public abstract class _Gallery extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
index ab004f9..d6a4db2 100644
--- a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
+++ b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
@@ -2,7 +2,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 
 import org.apache.cayenne.PersistentObject;
 import org.apache.cayenne.ValueHolder;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Artist;
 import org.apache.cayenne.tutorial.persistent.client.Gallery;
 import org.apache.cayenne.util.PersistentObjectHolder;
@@ -14,13 +16,13 @@ import org.apache.cayenne.util.PersistentObjectHolder;
  */
 public abstract class _Painting extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<Artist> ARTIST = Property.create("artist", Artist.class);
-    public static final Property<Gallery> GALLERY = Property.create("gallery", Gallery.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.client.Artist> ARTIST = PropertyFactory.createEntity("artist", org.apache.cayenne.tutorial.persistent.client.Artist.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.client.Gallery> GALLERY = PropertyFactory.createEntity("gallery", org.apache.cayenne.tutorial.persistent.client.Gallery.class);
 
     protected String name;
-    protected ValueHolder artist;
-    protected ValueHolder gallery;
+    protected ValueHolder<Artist> artist;
+    protected ValueHolder<Gallery> gallery;
 
     public String getName() {
         if(objectContext != null) {
@@ -29,17 +31,13 @@ public abstract class _Painting extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -47,25 +45,20 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        return (Artist) artist.getValue();
+        return artist.getValue();
     }
+
     public void setArtist(Artist artist) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
+            objectContext.propertyChanged(this, "artist", this.artist.getValueDirectly(), artist);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.artist.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "artist", oldValue, artist);
-        }
-        
         this.artist.setValue(artist);
     }
 
@@ -73,25 +66,20 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        return (Gallery) gallery.getValue();
+        return gallery.getValue();
     }
+
     public void setGallery(Gallery gallery) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
+            objectContext.propertyChanged(this, "gallery", this.gallery.getValueDirectly(), gallery);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.gallery.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "gallery", oldValue, gallery);
-        }
-        
         this.gallery.setValue(gallery);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
index a558c2b..052709b 100644
--- a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
+++ b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
@@ -1,13 +1,16 @@
 package org.apache.cayenne.tutorial.persistent.client.auto;
 
+import java.time.LocalDate;
+import java.util.List;
+
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
-import java.time.LocalDate;
-import java.util.List;
-
 /**
  * A generated persistent class mapped as "Artist" Cayenne entity. It is a good idea to
  * avoid changing this class manually, since it will be overwritten next time code is
@@ -15,9 +18,9 @@ import java.util.List;
  */
 public abstract class _Artist extends PersistentObject {
 
-    public static final Property<LocalDate> DATE_OF_BIRTH = Property.create("dateOfBirth", LocalDate.class);
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final DateProperty<LocalDate> DATE_OF_BIRTH = PropertyFactory.createDate("dateOfBirth", LocalDate.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected LocalDate dateOfBirth;
     protected String name;
@@ -30,17 +33,13 @@ public abstract class _Artist extends PersistentObject {
 
         return dateOfBirth;
     }
+
     public void setDateOfBirth(LocalDate dateOfBirth) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "dateOfBirth", false);
+            objectContext.propertyChanged(this, "dateOfBirth", this.dateOfBirth, dateOfBirth);
         }
 
-        Object oldValue = this.dateOfBirth;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "dateOfBirth", oldValue, dateOfBirth);
-        }
-        
         this.dateOfBirth = dateOfBirth;
     }
 
@@ -51,17 +50,13 @@ public abstract class _Artist extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -69,25 +64,27 @@ public abstract class _Artist extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
index 7c59c64..57ccb07 100644
--- a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
+++ b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
@@ -3,7 +3,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -14,8 +16,8 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _Gallery extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected String name;
     protected List<Painting> paintings;
@@ -27,17 +29,13 @@ public abstract class _Gallery extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -45,25 +43,27 @@ public abstract class _Gallery extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
index ab004f9..d6a4db2 100644
--- a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
+++ b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
@@ -2,7 +2,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 
 import org.apache.cayenne.PersistentObject;
 import org.apache.cayenne.ValueHolder;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Artist;
 import org.apache.cayenne.tutorial.persistent.client.Gallery;
 import org.apache.cayenne.util.PersistentObjectHolder;
@@ -14,13 +16,13 @@ import org.apache.cayenne.util.PersistentObjectHolder;
  */
 public abstract class _Painting extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<Artist> ARTIST = Property.create("artist", Artist.class);
-    public static final Property<Gallery> GALLERY = Property.create("gallery", Gallery.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.client.Artist> ARTIST = PropertyFactory.createEntity("artist", org.apache.cayenne.tutorial.persistent.client.Artist.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.client.Gallery> GALLERY = PropertyFactory.createEntity("gallery", org.apache.cayenne.tutorial.persistent.client.Gallery.class);
 
     protected String name;
-    protected ValueHolder artist;
-    protected ValueHolder gallery;
+    protected ValueHolder<Artist> artist;
+    protected ValueHolder<Gallery> gallery;
 
     public String getName() {
         if(objectContext != null) {
@@ -29,17 +31,13 @@ public abstract class _Painting extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -47,25 +45,20 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        return (Artist) artist.getValue();
+        return artist.getValue();
     }
+
     public void setArtist(Artist artist) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
+            objectContext.propertyChanged(this, "artist", this.artist.getValueDirectly(), artist);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.artist.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "artist", oldValue, artist);
-        }
-        
         this.artist.setValue(artist);
     }
 
@@ -73,25 +66,20 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        return (Gallery) gallery.getValue();
+        return gallery.getValue();
     }
+
     public void setGallery(Gallery gallery) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
+            objectContext.propertyChanged(this, "gallery", this.gallery.getValueDirectly(), gallery);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.gallery.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "gallery", oldValue, gallery);
-        }
-        
         this.gallery.setValue(gallery);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
index 147f9f7..5ff7823 100644
--- a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
+++ b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
@@ -1,10 +1,16 @@
 package org.apache.cayenne.tutorial.persistent.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.time.LocalDate;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.Painting;
 
 /**
@@ -13,40 +19,115 @@ import org.apache.cayenne.tutorial.persistent.Painting;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Artist extends CayenneDataObject {
+public abstract class _Artist extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<LocalDate> DATE_OF_BIRTH = Property.create("dateOfBirth", LocalDate.class);
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final DateProperty<LocalDate> DATE_OF_BIRTH = PropertyFactory.createDate("dateOfBirth", LocalDate.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
+
+    protected LocalDate dateOfBirth;
+    protected String name;
+
+    protected Object paintings;
 
     public void setDateOfBirth(LocalDate dateOfBirth) {
-        writeProperty("dateOfBirth", dateOfBirth);
+        beforePropertyWrite("dateOfBirth", this.dateOfBirth, dateOfBirth);
+        this.dateOfBirth = dateOfBirth;
     }
+
     public LocalDate getDateOfBirth() {
-        return (LocalDate)readProperty("dateOfBirth");
+        beforePropertyRead("dateOfBirth");
+        return this.dateOfBirth;
     }
 
     public void setName(String name) {
-        writeProperty("name", name);
+        beforePropertyWrite("name", this.name, name);
+        this.name = name;
     }
+
     public String getName() {
-        return (String)readProperty("name");
+        beforePropertyRead("name");
+        return this.name;
     }
 
     public void addToPaintings(Painting obj) {
         addToManyTarget("paintings", obj, true);
     }
+
     public void removeFromPaintings(Painting obj) {
         removeToManyTarget("paintings", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<Painting> getPaintings() {
         return (List<Painting>)readProperty("paintings");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "dateOfBirth":
+                return this.dateOfBirth;
+            case "name":
+                return this.name;
+            case "paintings":
+                return this.paintings;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "dateOfBirth":
+                this.dateOfBirth = (LocalDate)val;
+                break;
+            case "name":
+                this.name = (String)val;
+                break;
+            case "paintings":
+                this.paintings = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.dateOfBirth);
+        out.writeObject(this.name);
+        out.writeObject(this.paintings);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.dateOfBirth = (LocalDate)in.readObject();
+        this.name = (String)in.readObject();
+        this.paintings = in.readObject();
+    }
 
 }