This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit fee848de3895952a70f93ff4ec5f6ce3b27fa177
Author: Nikita Timofeev <[email protected]>
AuthorDate: Thu Jul 14 10:55:05 2022 +0300

    Add generics for the type-safety to the Entity/Attribute/Relationship 
hierarchy
---
 .../java/org/apache/cayenne/map/Attribute.java     | 12 +--
 .../main/java/org/apache/cayenne/map/DataMap.java  | 10 +--
 .../java/org/apache/cayenne/map/DbAttribute.java   |  2 +-
 .../main/java/org/apache/cayenne/map/DbEntity.java | 89 +++-------------------
 .../org/apache/cayenne/map/DbRelationship.java     |  2 +-
 .../main/java/org/apache/cayenne/map/Entity.java   | 56 +++++++-------
 .../java/org/apache/cayenne/map/ObjAttribute.java  |  2 +-
 .../java/org/apache/cayenne/map/ObjEntity.java     | 71 ++++++-----------
 .../org/apache/cayenne/map/ObjRelationship.java    | 18 ++---
 .../apache/cayenne/map/PathComponentIterator.java  | 30 ++++----
 .../java/org/apache/cayenne/map/Relationship.java  | 20 ++---
 .../java/org/apache/cayenne/map/AttributeTest.java |  6 +-
 .../test/java/org/apache/cayenne/map/EntityIT.java | 36 ++++-----
 .../java/org/apache/cayenne/map/MockAttribute.java |  2 +-
 .../java/org/apache/cayenne/map/MockEntity.java    |  8 +-
 .../org/apache/cayenne/map/MockRelationship.java   |  2 +-
 .../org/apache/cayenne/map/RelationshipTest.java   | 12 +--
 .../modeler/editor/ObjAttributeTableModel.java     | 55 ++++++-------
 .../editor/wrapper/ObjAttributeWrapper.java        | 12 +--
 .../cayenne/modeler/graph/BaseGraphBuilder.java    |  2 +-
 .../modeler/graph/DbEntityCellMetadata.java        | 20 ++---
 .../cayenne/modeler/graph/EntityCellMetadata.java  | 13 ++--
 .../modeler/graph/ObjEntityCellMetadata.java       | 19 ++---
 .../modeler/undo/RelationshipUndoableEdit.java     | 42 +++++-----
 .../cayenne/modeler/util/EntityTreeModel.java      | 24 +++---
 .../org/apache/cayenne/wocompat/EOObjEntity.java   |  3 +-
 26 files changed, 228 insertions(+), 340 deletions(-)

diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/Attribute.java 
b/cayenne-server/src/main/java/org/apache/cayenne/map/Attribute.java
index 48a40ab09..3dc4d318a 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/Attribute.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/Attribute.java
@@ -32,10 +32,11 @@ import org.apache.cayenne.util.XMLSerializable;
  * are described by attributes are Java class properties and database table 
columns.
  * 
  */
-public abstract class Attribute implements CayenneMapEntry, XMLSerializable, 
Serializable {
+public abstract class Attribute<E extends Entity<E,T,U>, T extends 
Attribute<E,T,U>, U extends Relationship<E,T,U>>
+        implements CayenneMapEntry, XMLSerializable, Serializable {
 
     protected String name;
-    protected Entity entity;
+    protected Entity<E,T,U> entity;
 
     /**
      * Creates an unnamed Attribute.
@@ -61,14 +62,14 @@ public abstract class Attribute implements CayenneMapEntry, 
XMLSerializable, Ser
     /**
      * Returns parent entity that holds this attribute.
      */
-    public Entity getEntity() {
+    public Entity<E,T,U> getEntity() {
         return entity;
     }
 
     /**
      * Sets parent entity that holds this attribute.
      */
-    public void setEntity(Entity entity) {
+    public void setEntity(Entity<E,T,U> entity) {
         this.entity = entity;
     }
 
@@ -84,11 +85,12 @@ public abstract class Attribute implements CayenneMapEntry, 
XMLSerializable, Ser
         return getEntity();
     }
 
+    @SuppressWarnings("unchecked")
     public void setParent(Object parent) {
         if (parent != null && !(parent instanceof Entity)) {
             throw new IllegalArgumentException("Expected null or Entity, got: 
" + parent);
         }
 
-        setEntity((Entity) parent);
+        setEntity((Entity<E,T,U>) parent);
     }
 }
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/DataMap.java 
b/cayenne-server/src/main/java/org/apache/cayenne/map/DataMap.java
index 94c6d5988..bda2ea70b 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/DataMap.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DataMap.java
@@ -271,7 +271,7 @@ public class DataMap implements Serializable, 
ConfigurationNode, XMLSerializable
 
        // stores relationships for the map of entities
        private void encodeDbRelationshipsAsXML(XMLEncoder encoder, 
ConfigurationNodeVisitor delegate) {
-               for (Entity entity : new TreeMap<>(getDbEntityMap()).values()) {
+               for (DbEntity entity : new 
TreeMap<>(getDbEntityMap()).values()) {
                        entity.getRelationships().stream()
                                        .filter(r -> !r.isRuntime())
                                        
.sorted(Comparator.comparing(Relationship::getName))
@@ -759,7 +759,7 @@ public class DataMap implements Serializable, 
ConfigurationNode, XMLSerializable
                if (dbEntityToDelete != null && clearDependencies) {
                        for (DbEntity dbEnt : this.getDbEntities()) {
                                // take a copy since we're going to modify the 
entity
-                               for (Relationship rel : new 
ArrayList<>(dbEnt.getRelationships())) {
+                               for (DbRelationship rel : new 
ArrayList<>(dbEnt.getRelationships())) {
                                        if 
(dbEntityName.equals(rel.getTargetEntityName())) {
                                                
dbEnt.removeRelationship(rel.getName());
                                        }
@@ -810,7 +810,7 @@ public class DataMap implements Serializable, 
ConfigurationNode, XMLSerializable
                        // remove relationships that point to this entity
                        for (ObjEntity ent : getObjEntities()) {
                                // take a copy since we're going to modify the 
entity
-                               for (Relationship relationship : new 
ArrayList<>(ent.getRelationships())) {
+                               for (ObjRelationship relationship : new 
ArrayList<>(ent.getRelationships())) {
                                        if 
(objEntityName.equals(relationship.getSourceEntity().getName())
                                                        || 
objEntityName.equals(relationship.getTargetEntityName())) {
                                                
ent.removeRelationship(relationship.getName());
@@ -970,7 +970,7 @@ public class DataMap implements Serializable, 
ConfigurationNode, XMLSerializable
         * @since 1.2
         */
        public void dbEntityChanged(EntityEvent e) {
-               Entity entity = e.getEntity();
+               Entity<?,?,?> entity = e.getEntity();
                if (entity instanceof DbEntity) {
 
                        DbEntity dbEntity = (DbEntity) entity;
@@ -1013,7 +1013,7 @@ public class DataMap implements Serializable, 
ConfigurationNode, XMLSerializable
         * @since 1.2
         */
        public void objEntityChanged(EntityEvent e) {
-               Entity entity = e.getEntity();
+               Entity<?,?,?> entity = e.getEntity();
                if (entity instanceof ObjEntity) {
 
                        ObjEntity objEntity = (ObjEntity) entity;
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/map/DbAttribute.java 
b/cayenne-server/src/main/java/org/apache/cayenne/map/DbAttribute.java
index a50e79098..1c1cd9f44 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/DbAttribute.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DbAttribute.java
@@ -29,7 +29,7 @@ import org.apache.cayenne.util.XMLEncoder;
 /**
  * A DbAttribute defines a descriptor for a single database table column.
  */
-public class DbAttribute extends Attribute implements ConfigurationNode {
+public class DbAttribute extends Attribute<DbEntity, DbAttribute, 
DbRelationship> implements ConfigurationNode {
 
     /**
      * Defines JDBC type of the column.
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java 
b/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java
index e68c1feaf..ef4305f15 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DbEntity.java
@@ -52,8 +52,8 @@ import org.apache.cayenne.util.XMLEncoder;
  * A DbEntity is a mapping descriptor that defines a structure of a database
  * table.
  */
-public class DbEntity extends Entity implements ConfigurationNode, 
DbEntityListener, DbAttributeListener,
-        DbRelationshipListener {
+public class DbEntity extends Entity<DbEntity, DbAttribute, DbRelationship>
+        implements ConfigurationNode, DbEntityListener, DbAttributeListener, 
DbRelationshipListener {
 
     protected String catalog;
     protected String schema;
@@ -76,7 +76,6 @@ public class DbEntity extends Entity implements 
ConfigurationNode, DbEntityListe
      */
     public DbEntity() {
         super();
-
         this.primaryKey = new ArrayList<>(2);
         this.generatedAttributes = new ArrayList<>(2);
     }
@@ -89,16 +88,6 @@ public class DbEntity extends Entity implements 
ConfigurationNode, DbEntityListe
         this.setName(name);
     }
 
-    @Override
-    public DbRelationship getRelationship(String relName) {
-        return (DbRelationship) super.getRelationship(relName);
-    }
-
-    @Override
-    public DbAttribute getAttribute(String attributeName) {
-        return (DbAttribute) super.getAttribute(attributeName);
-    }
-
     /**
      * @since 3.1
      */
@@ -189,16 +178,6 @@ public class DbEntity extends Entity implements 
ConfigurationNode, DbEntityListe
         return Collections.unmodifiableList(primaryKey);
     }
 
-    /**
-     * Returns a Collection of all attributes that either belong to this
-     * DbEntity or inherited.
-     */
-    @SuppressWarnings("unchecked")
-    @Override
-    public Collection<DbAttribute> getAttributes() {
-        return (Collection<DbAttribute>) super.getAttributes();
-    }
-
     /**
      * Returns an unmodifiable collection of DbAttributes that are generated by
      * the database.
@@ -231,7 +210,7 @@ public class DbEntity extends Entity implements 
ConfigurationNode, DbEntityListe
      */
     @Override
     public void removeAttribute(String attrName) {
-        Attribute attr = getAttribute(attrName);
+        DbAttribute attr = getAttribute(attrName);
         if (attr == null) {
             return;
         }
@@ -256,30 +235,6 @@ public class DbEntity extends Entity implements 
ConfigurationNode, DbEntityListe
         this.dbAttributeRemoved(new AttributeEvent(this, null, this, 
MapEvent.REMOVE));
     }
 
-    /**
-     * Returns a Collection of relationships from this entity or inherited.
-     */
-    @SuppressWarnings("unchecked")
-    @Override
-    public Collection<DbRelationship> getRelationships() {
-        return (Collection<DbRelationship>) super.getRelationships();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public Map<String, DbRelationship> getRelationshipMap() {
-        return (Map<String, DbRelationship>) super.getRelationshipMap();
-    }
-
-    /**
-     * @since 3.0
-     */
-    @Override
-    @SuppressWarnings("unchecked")
-    public PathComponent<DbAttribute, DbRelationship> 
lastPathComponent(Expression path, Map aliasMap) {
-        return super.lastPathComponent(path, aliasMap);
-    }
-
     /**
      * Returns an Iterable instance over expression path components based on
      * this entity.
@@ -287,17 +242,10 @@ public class DbEntity extends Entity implements 
ConfigurationNode, DbEntityListe
      * @since 3.0
      */
     @Override
-    @SuppressWarnings("unchecked")
-    public Iterable<PathComponent<DbAttribute, DbRelationship>> 
resolvePath(final Expression pathExp, final Map aliasMap) {
+    public Iterable<PathComponent<DbAttribute, DbRelationship>> 
resolvePath(Expression pathExp, Map<String, String> aliasMap) {
 
         if (pathExp.getType() == Expression.DB_PATH) {
-
-            return new Iterable<PathComponent<DbAttribute, DbRelationship>>() {
-
-                public Iterator iterator() {
-                    return new PathComponentIterator(DbEntity.this, (String) 
pathExp.getOperand(0), aliasMap);
-                }
-            };
+            return () -> new PathComponentIterator<>(DbEntity.this, (String) 
pathExp.getOperand(0), aliasMap);
         }
 
         throw new ExpressionException("Invalid expression type: '" + 
pathExp.expName() + "',  DB_PATH is expected.");
@@ -400,7 +348,7 @@ public class DbEntity extends Entity implements 
ConfigurationNode, DbEntityListe
         }
 
         // catch clearing (event with null ('any') DbAttribute)
-        Attribute attribute = e.getAttribute();
+        Attribute<?,?,?> attribute = e.getAttribute();
         if (attribute == null && this.attributes.isEmpty()) {
             this.primaryKey.clear();
             this.generatedAttributes.clear();
@@ -516,7 +464,7 @@ public class DbEntity extends Entity implements 
ConfigurationNode, DbEntityListe
             return;
         }
 
-        Relationship rel = e.getRelationship();
+        Relationship<?,?,?> rel = e.getRelationship();
         // make sure we handle a DbRelationship
         if (!(rel instanceof DbRelationship)) {
             return;
@@ -676,17 +624,17 @@ public class DbEntity extends Entity implements 
ConfigurationNode, DbEntityListe
             return transformed;
         }
 
-        private PathComponentIterator createPathIterator(String path) {
-            return new PathComponentIterator(DbEntity.this, path, 
Collections.emptyMap());
+        private PathComponentIterator<DbEntity, DbAttribute, DbRelationship> 
createPathIterator(String path) {
+            return new PathComponentIterator<>(DbEntity.this, path, 
Collections.emptyMap());
             // TODO: do we need aliases here?
         }
 
         String translatePath(String path) {
             LinkedList<String> finalPath = new LinkedList<>();
-            PathComponentIterator pathIt = 
createPathIterator(relationshipPath);
+            PathComponentIterator<DbEntity, DbAttribute, DbRelationship> 
pathIt = createPathIterator(relationshipPath);
             while (pathIt.hasNext()) {
                 // relationship path components must be DbRelationships
-                DbRelationship lastDBR = (DbRelationship) 
pathIt.next().getRelationship();
+                DbRelationship lastDBR = pathIt.next().getRelationship();
                 if(lastDBR != null) {
                     prependReversedPath(finalPath, lastDBR);
                 }
@@ -706,20 +654,5 @@ public class DbEntity extends Entity implements 
ConfigurationNode, DbEntityListe
 
             finalPath.addFirst(revNextDBR.getName());
         }
-
-        private void appendPath(LinkedList<String> finalPath, CayenneMapEntry 
pathComponent) {
-            finalPath.addLast(pathComponent.getName());
-        }
-
-        private void appendPath(LinkedList<String> finalPath, 
PathComponent<Attribute, Relationship> pathComponent) {
-            CayenneMapEntry mapEntry = pathComponent.getAttribute() != null ? 
pathComponent.getAttribute()
-                    : pathComponent.getRelationship();
-            String name = mapEntry.getName();
-            if (pathComponent.getJoinType() == JoinType.LEFT_OUTER) {
-                name += OUTER_JOIN_INDICATOR;
-            }
-
-            finalPath.addLast(name);
-        }
     }
 }
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java 
b/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java
index 2b581b78a..98351a78c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/DbRelationship.java
@@ -37,7 +37,7 @@ import java.util.function.Function;
  * A DbRelationship is a descriptor of a database inter-table relationship 
based
  * on one or more primary key/foreign key pairs.
  */
-public class DbRelationship extends Relationship implements ConfigurationNode {
+public class DbRelationship extends Relationship<DbEntity, DbAttribute, 
DbRelationship> implements ConfigurationNode {
 
     // The columns through which the join is implemented.
     protected List<DbJoin> joins = new ArrayList<>(2);
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/Entity.java 
b/cayenne-server/src/main/java/org/apache/cayenne/map/Entity.java
index f2a9a349a..1d57c60cb 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/Entity.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/Entity.java
@@ -27,12 +27,10 @@ import org.apache.cayenne.util.ToStringBuilder;
 import org.apache.cayenne.util.XMLSerializable;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
 
@@ -41,7 +39,8 @@ import java.util.StringTokenizer;
  * either a descriptor of database table or a persistent object.
  * 
  */
-public abstract class Entity implements CayenneMapEntry, XMLSerializable, 
Serializable {
+public abstract class Entity<E extends Entity<E,T,U>, T extends 
Attribute<E,T,U>, U extends Relationship<E,T,U>>
+        implements CayenneMapEntry, XMLSerializable, Serializable {
 
     public static final String PATH_SEPARATOR = ".";
 
@@ -56,8 +55,8 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
     protected String name;
     protected DataMap dataMap;
 
-    protected final Map<String, Attribute> attributes = new LinkedHashMap<>();
-    protected final Map<String, Relationship> relationships = new 
LinkedHashMap<>();
+    protected final Map<String, T> attributes = new LinkedHashMap<>();
+    protected final Map<String, U> relationships = new LinkedHashMap<>();
 
     /**
      * Creates an unnamed Entity.
@@ -119,7 +118,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
      * Returns attribute with name <code>attributeName</code> or null if no 
attribute
      * with this name exists.
      */
-    public Attribute getAttribute(String attributeName) {
+    public T getAttribute(String attributeName) {
         return attributes.get(attributeName);
     }
 
@@ -127,7 +126,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
      * Adds new attribute to the entity, setting its parent entity to be this 
object. If
      * attribute has no name, IllegalArgumentException is thrown.
      */
-    public void addAttribute(Attribute attribute) {
+    public void addAttribute(T attribute) {
         if (attribute.getName() == null) {
             throw new IllegalArgumentException("Attempt to insert unnamed 
attribute.");
         }
@@ -135,7 +134,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
         // block overrides
 
         // TODO: change method signature to return replaced attribute and make 
sure the Modeler handles it...
-        Object existingAttribute = attributes.get(attribute.getName());
+        T existingAttribute = attributes.get(attribute.getName());
         if (existingAttribute != null) {
             if (existingAttribute == attribute) {
                 return;
@@ -167,7 +166,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
      *
      * @since 4.0
      */
-    public void updateAttribute(Attribute attribute) {
+    public void updateAttribute(T attribute) {
         removeAttribute(attribute.getName());
         addAttribute(attribute);
     }
@@ -180,14 +179,14 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
      * Returns relationship with name <code>relName</code>. Will return null 
if no
      * relationship with this name exists in the entity.
      */
-    public Relationship getRelationship(String relName) {
+    public U getRelationship(String relName) {
         return relationships.get(relName);
     }
 
     /**
      * Adds new relationship to the entity.
      */
-    public void addRelationship(Relationship relationship) {
+    public void addRelationship(U relationship) {
         if (relationship.getName() == null) {
             throw new IllegalArgumentException("Attempt to insert unnamed 
relationship.");
         }
@@ -232,7 +231,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
     /**
      * Returns an unmodifiable map of relationships sorted by name.
      */
-    public Map<String, ? extends Relationship> getRelationshipMap() {
+    public Map<String, U> getRelationshipMap() {
         // create a new instance ... earlier attempts to cache it in the 
entity caused
         // serialization issues (esp. with Hessian).
         return Collections.unmodifiableMap(relationships);
@@ -245,12 +244,12 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
      * 
      * @since 1.1
      */
-    public Relationship getAnyRelationship(Entity targetEntity) {
+    public U getAnyRelationship(E targetEntity) {
         if (getRelationships().isEmpty()) {
             return null;
         }
 
-        for (Relationship r : getRelationships()) {
+        for (U r : getRelationships()) {
             if (r.getTargetEntity() == targetEntity) {
                 return r;
             }
@@ -261,7 +260,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
     /**
      * Returns an unmodifiable collection of Relationships that exist in this 
entity.
      */
-    public Collection<? extends Relationship> getRelationships() {
+    public Collection<U> getRelationships() {
         // create a new instance ... earlier attempts to cache it in the 
entity caused
         // serialization issues (esp. with Hessian).
         return Collections.unmodifiableCollection(relationships.values());
@@ -270,7 +269,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
     /**
      * Returns an unmodifiable sorted map of entity attributes.
      */
-    public Map<String, ? extends Attribute> getAttributeMap() {
+    public Map<String, T> getAttributeMap() {
         // create a new instance ... earlier attempts to cache it in the 
entity caused
         // serialization issues (esp. with Hessian).
         return Collections.unmodifiableMap(attributes);
@@ -279,7 +278,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
     /**
      * Returns an unmodifiable collection of entity attributes.
      */
-    public Collection<? extends Attribute> getAttributes() {
+    public Collection<T> getAttributes() {
         // create a new instance ... earlier attempts to cache it in the 
entity caused
         // serialization issues (esp. with Hessian).
         return Collections.unmodifiableCollection(attributes.values());
@@ -299,12 +298,11 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
      * 
      * @since 3.0
      */
-    @SuppressWarnings("unchecked")
-    public <T extends Attribute, U extends Relationship> PathComponent<T, U> 
lastPathComponent(
+    public PathComponent<T, U> lastPathComponent(
             Expression path,
-            Map aliasMap) {
+            Map<String, String> aliasMap) {
 
-        for (PathComponent component : resolvePath(path, aliasMap)) {
+        for (PathComponent<T, U> component : resolvePath(path, aliasMap)) {
             if (component.isLast()) {
                 // resolve aliases if needed
                 return lastPathComponent(component);
@@ -314,14 +312,13 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
         return null;
     }
 
-    @SuppressWarnings("unchecked")
-    private PathComponent lastPathComponent(PathComponent<Attribute, 
Relationship> component) {
+    private PathComponent<T, U> lastPathComponent(PathComponent<T, U> 
component) {
         
         if (!component.isAlias()) {
             return component;
         }
 
-        for (PathComponent subcomponent : component.getAliasedPath()) {
+        for (PathComponent<T, U> subcomponent : component.getAliasedPath()) {
             if (subcomponent.isLast()) {
                 return lastPathComponent(subcomponent);
             }
@@ -343,10 +340,9 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
      * 
      * @since 3.0
      */
-    @SuppressWarnings("unchecked")
-    public abstract <T extends Attribute, U extends Relationship> 
Iterable<PathComponent<T, U>> resolvePath(
+    public abstract Iterable<PathComponent<T, U>> resolvePath(
             Expression pathExp,
-            Map aliasMap);
+            Map<String, String> aliasMap);
 
     /**
      * Processes expression <code>pathExp</code> and returns an Iterator of 
path
@@ -375,7 +371,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
 
         private final StringTokenizer tokens;
         private final String path;
-        private Entity currentEntity;
+        private Entity<E,T,U> currentEntity;
 
         PathIterator(String path) {
             currentEntity = Entity.this;
@@ -394,7 +390,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
             }
             
             // see if this is an attribute
-            Attribute attr = currentEntity.getAttribute(pathComp);
+            T attr = currentEntity.getAttribute(pathComp);
             if (attr != null) {
                 // do a sanity check...
                 if (tokens.hasMoreTokens()) {
@@ -404,7 +400,7 @@ public abstract class Entity implements CayenneMapEntry, 
XMLSerializable, Serial
                 return attr;
             }
 
-            Relationship rel = currentEntity.getRelationship(pathComp);
+            U rel = currentEntity.getRelationship(pathComp);
             if (rel != null) {
                 currentEntity = rel.getTargetEntity();
                 if (currentEntity != null || !tokens.hasMoreTokens()) { 
//otherwise an exception will be thrown
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjAttribute.java 
b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjAttribute.java
index e614d306b..7fbb8e270 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjAttribute.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjAttribute.java
@@ -32,7 +32,7 @@ import org.apache.cayenne.util.XMLEncoder;
 /**
  * An ObjAttribute is a mapping descriptor of a Java class property.
  */
-public class ObjAttribute extends Attribute implements ConfigurationNode {
+public class ObjAttribute extends Attribute<ObjEntity, ObjAttribute, 
ObjRelationship> implements ConfigurationNode {
 
     protected String type;
     protected boolean usedForLocking;
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java 
b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java
index 117cdcfca..a33dcbfcd 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java
@@ -23,7 +23,6 @@ import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.configuration.ConfigurationNode;
 import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
 import org.apache.cayenne.dba.TypesMapping;
-import org.apache.cayenne.di.AdhocObjectFactory;
 import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.exp.ExpressionException;
 import org.apache.cayenne.exp.ExpressionFactory;
@@ -52,7 +51,8 @@ import java.util.function.Function;
  * the information about the Java class itself, as well as its mapping to the
  * DbEntity layer.
  */
-public class ObjEntity extends Entity implements ObjEntityListener, 
ConfigurationNode {
+public class ObjEntity extends Entity<ObjEntity, ObjAttribute, ObjRelationship>
+        implements ObjEntityListener, ConfigurationNode {
 
     private static final Logger LOGGER = 
LoggerFactory.getLogger(ObjEntity.class);
 
@@ -406,7 +406,7 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
      */
     @Override
     public ObjAttribute getAttribute(String name) {
-        ObjAttribute attribute = (ObjAttribute) super.getAttribute(name);
+        ObjAttribute attribute = super.getAttribute(name);
         if (attribute != null) {
             return attribute;
         }
@@ -498,9 +498,8 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
         }
     }
 
-    @SuppressWarnings("unchecked")
     final Map<String, ObjAttribute> getAttributeMapInternal() {
-        return (Map<String, ObjAttribute>) super.getAttributeMap();
+        return super.getAttributeMap();
     }
 
     /**
@@ -539,9 +538,8 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
      * 
      * @since 1.1
      */
-    @SuppressWarnings("unchecked")
     public Collection<ObjAttribute> getDeclaredAttributes() {
-        return (Collection<ObjAttribute>) super.getAttributes();
+        return super.getAttributes();
     }
 
     /**
@@ -556,7 +554,7 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
      * @since 4.0
      */
     public ObjAttribute getDeclaredAttribute(String name) {
-        return (ObjAttribute) super.getAttribute(name);
+        return super.getAttribute(name);
     }
 
     /**
@@ -565,7 +563,7 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
      */
     @Override
     public ObjRelationship getRelationship(String name) {
-        ObjRelationship relationship = (ObjRelationship) 
super.getRelationship(name);
+        ObjRelationship relationship = super.getRelationship(name);
         if (relationship != null) {
             return relationship;
         }
@@ -581,7 +579,7 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
     @Override
     public Map<String, ObjRelationship> getRelationshipMap() {
         if (superEntityName == null) {
-            return getRelationshipMapInternal();
+            return super.getRelationshipMap();
         }
 
         Map<String, ObjRelationship> relationshipMap = new HashMap<>();
@@ -594,7 +592,7 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
      * hierarchy.
      */
     final void appendRelationships(Map<String, ObjRelationship> map) {
-        map.putAll(getRelationshipMapInternal());
+        map.putAll(super.getRelationshipMap());
 
         ObjEntity superEntity = getSuperEntity();
         if (superEntity != null) {
@@ -607,20 +605,14 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
         return getRelationshipMap().values();
     }
 
-    @SuppressWarnings("unchecked")
-    final Map<String, ObjRelationship> getRelationshipMapInternal() {
-        return (Map<String, ObjRelationship>) super.getRelationshipMap();
-    }
-
     /**
      * Returns a Collection of all relationships that belong to this ObjEntity,
      * excluding inherited attributes.
      * 
      * @since 1.1
      */
-    @SuppressWarnings("unchecked")
     public Collection<ObjRelationship> getDeclaredRelationships() {
-        return (Collection<ObjRelationship>) super.getRelationships();
+        return super.getRelationships();
     }
 
     /**
@@ -751,15 +743,6 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
         return superEntity != null && superEntity.isSubentityOf(entity);
     }
 
-    /**
-     * @since 3.0
-     */
-    @Override
-    @SuppressWarnings("unchecked")
-    public PathComponent<ObjAttribute, ObjRelationship> 
lastPathComponent(Expression path, Map aliasMap) {
-        return super.lastPathComponent(path, aliasMap);
-    }
-
     /**
      * Returns an Iterable instance over expression path components based on
      * this entity.
@@ -767,20 +750,10 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
      * @since 3.0
      */
     @Override
-    @SuppressWarnings("unchecked")
-    public Iterable<PathComponent<ObjAttribute, ObjRelationship>> 
resolvePath(final Expression pathExp,
-            final Map aliasMap) {
-
+    public Iterable<PathComponent<ObjAttribute, ObjRelationship>> 
resolvePath(Expression pathExp, Map<String, String> aliasMap) {
         if (pathExp.getType() == Expression.OBJ_PATH) {
-
-            return new Iterable<PathComponent<ObjAttribute, 
ObjRelationship>>() {
-
-                public Iterator iterator() {
-                    return new PathComponentIterator(ObjEntity.this, (String) 
pathExp.getOperand(0), aliasMap);
-                }
-            };
+            return () -> new PathComponentIterator<>(ObjEntity.this, (String) 
pathExp.getOperand(0), aliasMap);
         }
-
         throw new ExpressionException("Invalid expression type: '" + 
pathExp.expName() + "',  OBJ_PATH is expected.");
     }
 
@@ -856,8 +829,8 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
         return getDbEntity().translateToRelatedEntity(dbClone, dbPath);
     }
 
-    private PathComponentIterator createPathIterator(String path, Map<String, 
String> aliasMap) {
-        return new PathComponentIterator(ObjEntity.this, path, aliasMap);
+    private PathComponentIterator<ObjEntity, ObjAttribute, ObjRelationship> 
createPathIterator(String path, Map<String, String> aliasMap) {
+        return new PathComponentIterator<>(this, path, aliasMap);
     }
 
     /**
@@ -877,22 +850,22 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
         // something...
         // seems generally useful
 
-        String toDbPath(PathComponentIterator objectPathComponents) {
+        String toDbPath(PathComponentIterator<ObjEntity, ObjAttribute, 
ObjRelationship> objectPathComponents) {
             StringBuilder buf = new StringBuilder();
             while (objectPathComponents.hasNext()) {
-                PathComponent<Attribute, Relationship> component = 
objectPathComponents.next();
+                PathComponent<ObjAttribute, ObjRelationship> component = 
objectPathComponents.next();
 
-                Iterator<?> dbSubpath;
+                Iterator<? extends CayenneMapEntry> dbSubpath;
                 if(component.getAttribute() != null) {
-                    dbSubpath = ((ObjAttribute) 
component.getAttribute()).getDbPathIterator();
+                    dbSubpath = component.getAttribute().getDbPathIterator();
                     buildPath(dbSubpath, component, buf);
                 } else if(component.getRelationship() != null) {
-                    dbSubpath = ((ObjRelationship) 
component.getRelationship()).getDbRelationships().iterator();
+                    dbSubpath = 
component.getRelationship().getDbRelationships().iterator();
                     buildPath(dbSubpath, component, buf);
                 } else if(component.getAliasedPath() != null) {
-                    for(PathComponent<Attribute, Relationship> pathComponent : 
component.getAliasedPath()) {
+                    for(PathComponent<ObjAttribute, ObjRelationship> 
pathComponent : component.getAliasedPath()) {
                        if(pathComponent.getRelationship() != null) {
-                           dbSubpath = ((ObjRelationship) 
pathComponent.getRelationship()).getDbRelationships().iterator();
+                           dbSubpath = 
pathComponent.getRelationship().getDbRelationships().iterator();
                            buildPath(dbSubpath, pathComponent, buf);
                        }
                     }
@@ -904,7 +877,7 @@ public class ObjEntity extends Entity implements 
ObjEntityListener, Configuratio
             return buf.toString();
         }
 
-        private void buildPath(Iterator<?> dbSubpath, PathComponent<Attribute, 
Relationship> component, StringBuilder buf) {
+        private void buildPath(Iterator<?> dbSubpath, 
PathComponent<ObjAttribute, ObjRelationship> component, StringBuilder buf) {
             while (dbSubpath.hasNext()) {
                 CayenneMapEntry subComponent = (CayenneMapEntry) 
dbSubpath.next();
                 if (buf.length() > 0) {
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjRelationship.java 
b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjRelationship.java
index fd6d19c19..ee36fbf68 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjRelationship.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjRelationship.java
@@ -39,7 +39,7 @@ import org.apache.cayenne.util.XMLEncoder;
  * Describes an association between two Java classes mapped as source and 
target
  * ObjEntity. Maps to a path of DbRelationships.
  */
-public class ObjRelationship extends Relationship implements ConfigurationNode 
{
+public class ObjRelationship extends Relationship<ObjEntity, ObjAttribute, 
ObjRelationship> implements ConfigurationNode {
 
     /**
      * Denotes a default type of to-many relationship collection which is a 
Java
@@ -60,7 +60,7 @@ public class ObjRelationship extends Relationship implements 
ConfigurationNode {
      * Db-relationships path that is set but not yet parsed (turned into
      * List&lt;DbRelationship&gt;) Used during map loading
      */
-    String deferredPath;
+    volatile String deferredPath;
 
     /**
      * Stores the type of collection mapped by a to-many relationship. Null for
@@ -193,7 +193,7 @@ public class ObjRelationship extends Relationship 
implements ConfigurationNode {
             return null;
         }
 
-        Entity source = getSourceEntity();
+        ObjEntity source = getSourceEntity();
 
         for (ObjRelationship relationship : target.getRelationships()) {
 
@@ -309,7 +309,7 @@ public class ObjRelationship extends Relationship 
implements ConfigurationNode {
         // entities with qualifiers may result in filtering even existing 
target
         // rows, so
         // such relationships are optional
-        if (isQualifiedEntity((ObjEntity) getTargetEntity())) {
+        if (isQualifiedEntity(getTargetEntity())) {
             return true;
         }
 
@@ -320,11 +320,8 @@ public class ObjRelationship extends Relationship 
implements ConfigurationNode {
             if (!dbRelationship.isFromPK()) {
                 return false;
             }
-
             DbRelationship reverseRelationship = 
dbRelationship.getReverseRelationship();
-            if (reverseRelationship.isToDependentPK()) {
-                return false;
-            }
+            return !reverseRelationship.isToDependentPK();
         }
 
         return true;
@@ -565,9 +562,7 @@ public class ObjRelationship extends Relationship 
implements ConfigurationNode {
      */
     void refreshFromDeferredPath() {
         if (deferredPath != null) {
-            
             synchronized(this) {
-                
                 // check if another thread just 
                 // loaded path from deferredPath
                 if (deferredPath != null){
@@ -609,8 +604,7 @@ public class ObjRelationship extends Relationship 
implements ConfigurationNode {
                 }
                 validPath.append(pathComponent.getName());
             }
-        } catch (ExpressionException ex) {
-
+        } catch (ExpressionException ignored) {
         }
 
         return validPath.toString();
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/map/PathComponentIterator.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/map/PathComponentIterator.java
index 3d2bee8ef..9a444b094 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/map/PathComponentIterator.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/map/PathComponentIterator.java
@@ -31,16 +31,17 @@ import java.util.StringTokenizer;
 /**
  * @since 3.0
  */
-class PathComponentIterator implements Iterator<PathComponent<Attribute, 
Relationship>> {
+class PathComponentIterator<E extends Entity<E,T,U>, T extends 
Attribute<E,T,U>, U extends Relationship<E,T,U>>
+        implements Iterator<PathComponent<T, U>> {
 
     private final StringTokenizer toks;
     private final String path;
     private final Map<String, String> aliasMap;
 
     private EmbeddedAttribute embeddedAttribute;
-    private Entity currentEntity;
+    private Entity<E,T,U> currentEntity;
 
-    PathComponentIterator(Entity root, String path, Map<String, String> 
aliasMap) {
+    PathComponentIterator(Entity<E,T,U> root, String path, Map<String, String> 
aliasMap) {
         this.currentEntity = Objects.requireNonNull(root);
         this.path = Objects.requireNonNull(path);
         this.aliasMap = Objects.requireNonNull(aliasMap);
@@ -52,7 +53,7 @@ class PathComponentIterator implements 
Iterator<PathComponent<Attribute, Relatio
         return toks.hasMoreTokens();
     }
 
-    public PathComponent<Attribute, Relationship> next() {
+    public PathComponent<T, U> next() {
         String pathComp = toks.nextToken();
 
         JoinType relationshipJoinType = JoinType.INNER;
@@ -64,9 +65,10 @@ class PathComponentIterator implements 
Iterator<PathComponent<Attribute, Relatio
         }
 
         // see if this is an attribute
-        Attribute attr;
+        T attr;
         if(embeddedAttribute != null) {
-            attr = embeddedAttribute.getAttribute(pathComp);
+            // TODO: assert that this iterator is for ObjEntity
+            attr = (T)embeddedAttribute.getAttribute(pathComp);
             embeddedAttribute = null;
         } else {
             attr = currentEntity.getAttribute(pathComp);
@@ -84,13 +86,13 @@ class PathComponentIterator implements 
Iterator<PathComponent<Attribute, Relatio
             return new AttributePathComponent<>(attr);
         }
 
-        Relationship rel = currentEntity.getRelationship(pathComp);
+        U rel = currentEntity.getRelationship(pathComp);
         if (rel != null) {
             currentEntity = rel.getTargetEntity();
             return new RelationshipPathComponent<>(rel, relationshipJoinType, 
!hasNext());
         }
 
-        PathComponent<Attribute, Relationship> aliasedPathComponent = 
getAliasedPathComponent(pathComp);
+        PathComponent<T, U> aliasedPathComponent = 
getAliasedPathComponent(pathComp);
         if (aliasedPathComponent != null) {
             return aliasedPathComponent;
         }
@@ -98,7 +100,7 @@ class PathComponentIterator implements 
Iterator<PathComponent<Attribute, Relatio
         throw invalidPathException("Can't resolve path component", pathComp);
     }
 
-    private PathComponent<Attribute, Relationship> 
getAliasedPathComponent(String pathComp) {
+    private PathComponent<T, U> getAliasedPathComponent(String pathComp) {
         String aliasedPath = aliasMap.get(pathComp);
         if(aliasedPath == null) {
             return null;
@@ -115,15 +117,15 @@ class PathComponentIterator implements 
Iterator<PathComponent<Attribute, Relatio
         // the subpath, we have to fully traverse it, hence instead of lazy 
iterator
         // we might as well reuse obtained information in the 
AliasPathComponent
 
-        Iterator<PathComponent<Attribute, Relationship>> subpathIt =
-                new PathComponentIterator(currentEntity, aliasedPath, 
Collections.emptyMap());
+        Iterator<PathComponent<T, U>> subpathIt =
+                new PathComponentIterator<>(currentEntity, aliasedPath, 
Collections.emptyMap());
 
-        Collection<PathComponent<Attribute, Relationship>> parsedSubpath = new 
ArrayList<>(4);
+        Collection<PathComponent<T, U>> parsedSubpath = new ArrayList<>(4);
 
         while (subpathIt.hasNext()) {
-            PathComponent<Attribute, Relationship> subpathComponent = 
subpathIt.next();
+            PathComponent<T, U> subpathComponent = subpathIt.next();
 
-            Relationship subpathRelationship = 
subpathComponent.getRelationship();
+            U subpathRelationship = subpathComponent.getRelationship();
             if (subpathRelationship == null) {
                 throw invalidPathException(
                         "Expected a relationship in the aliased subpath. Alias 
[" + pathComp + "]",
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/map/Relationship.java 
b/cayenne-server/src/main/java/org/apache/cayenne/map/Relationship.java
index 43fca42da..428cdb285 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/Relationship.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/Relationship.java
@@ -31,11 +31,11 @@ import org.apache.cayenne.util.XMLSerializable;
  * "arcs" connecting entity "nodes". Relationships are directional, i.e. they 
have a
  * notion of source and target entity. This makes DataMap a "digraph".
  */
-public abstract class Relationship implements CayenneMapEntry, XMLSerializable,
-        Serializable {
+public abstract class Relationship<E extends Entity<E,T,U>, T extends 
Attribute<E,T,U>, U extends Relationship<E,T,U>>
+        implements CayenneMapEntry, XMLSerializable, Serializable {
 
     protected String name;
-    protected Entity sourceEntity;
+    protected Entity<E,T,U> sourceEntity;
 
     protected String targetEntityName;
     protected boolean toMany;
@@ -72,26 +72,26 @@ public abstract class Relationship implements 
CayenneMapEntry, XMLSerializable,
     /**
      * Returns relationship source entity.
      */
-    public Entity getSourceEntity() {
+    public Entity<E,T,U> getSourceEntity() {
         return sourceEntity;
     }
 
     /**
      * Sets relationship source entity.
      */
-    public void setSourceEntity(Entity sourceEntity) {
+    public void setSourceEntity(Entity<E,T,U> sourceEntity) {
         this.sourceEntity = sourceEntity;
     }
 
     /**
      * Returns a target entity of the relationship.
      */
-    public abstract Entity getTargetEntity();
+    public abstract Entity<E,T,U> getTargetEntity();
 
     /**
      * Sets relationship target entity. Internally calls 
<code>setTargetEntityName</code>.
      */
-    public void setTargetEntityName(Entity targetEntity) {
+    public void setTargetEntityName(Entity<E,?,?> targetEntity) {
         if (targetEntity != null) {
             setTargetEntityName(targetEntity.getName());
         } else {
@@ -133,7 +133,7 @@ public abstract class Relationship implements 
CayenneMapEntry, XMLSerializable,
             throw new IllegalArgumentException("Expected null or Entity, got: 
" + parent);
         }
 
-        setSourceEntity((Entity) parent);
+        setSourceEntity((Entity<E,T,U>) parent);
     }
 
     /**
@@ -142,7 +142,7 @@ public abstract class Relationship implements 
CayenneMapEntry, XMLSerializable,
      * Relationship class.
      */
     final MappingNamespace getNonNullNamespace() {
-        Entity entity = getSourceEntity();
+        Entity<E,?,?> entity = getSourceEntity();
 
         if (entity == null) {
             throw new CayenneRuntimeException("Relationship '%s' has no parent 
Entity.", getName());
@@ -180,7 +180,7 @@ public abstract class Relationship implements 
CayenneMapEntry, XMLSerializable,
      * null if no such relationship is found.
      * @since 3.1
      */
-    public abstract Relationship getReverseRelationship();
+    public abstract Relationship<E,T,U> getReverseRelationship();
     
     /**
      * Returns if relationship is mandatory
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/map/AttributeTest.java 
b/cayenne-server/src/test/java/org/apache/cayenne/map/AttributeTest.java
index 30ffbad76..2a57a2711 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/map/AttributeTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/map/AttributeTest.java
@@ -28,7 +28,7 @@ public class AttributeTest {
 
     @Test
     public void testName() throws Exception {
-        Attribute a = new MockAttribute();
+        MockAttribute a = new MockAttribute();
 
         String tstName = "tst_name";
         a.setName(tstName);
@@ -37,9 +37,9 @@ public class AttributeTest {
 
     @Test
     public void testEntity() throws Exception {
-        Attribute a = new MockAttribute();
+        MockAttribute a = new MockAttribute();
 
-        Entity tstEntity = new MockEntity();
+        MockEntity tstEntity = new MockEntity();
         a.setEntity(tstEntity);
         assertSame(tstEntity, a.getEntity());
     }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/map/EntityIT.java 
b/cayenne-server/src/test/java/org/apache/cayenne/map/EntityIT.java
index ca1445877..ef1bb0492 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/map/EntityIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/map/EntityIT.java
@@ -49,14 +49,14 @@ public class EntityIT extends ServerCase {
 
     @Test
     public void testSerializability() throws Exception {
-        Entity entity = new MockEntity("entity");
+        MockEntity entity = new MockEntity("entity");
 
-        Entity d1 = Util.cloneViaSerialization(entity);
+        MockEntity d1 = Util.cloneViaSerialization(entity);
         assertEquals(entity.getName(), d1.getName());
 
         entity.addAttribute(new MockAttribute("abc"));
         entity.addRelationship(new MockRelationship("xyz"));
-        Entity d2 = Util.cloneViaSerialization(entity);
+        MockEntity d2 = Util.cloneViaSerialization(entity);
         assertNotNull(d2.getAttribute("abc"));
 
         // test that ref collection wrappers are still working
@@ -79,7 +79,7 @@ public class EntityIT extends ServerCase {
 
     @Test
     public void testName() {
-        Entity entity = new MockEntity();
+        MockEntity entity = new MockEntity();
         String tstName = "tst_name";
         entity.setName(tstName);
         assertEquals(tstName, entity.getName());
@@ -87,8 +87,8 @@ public class EntityIT extends ServerCase {
 
     @Test
     public void testAttribute() {
-        Entity entity = new MockEntity();
-        Attribute attribute = new MockAttribute("tst_name");
+        MockEntity entity = new MockEntity();
+        MockAttribute attribute = new MockAttribute("tst_name");
 
         entity.addAttribute(attribute);
         assertSame(attribute, entity.getAttribute(attribute.getName()));
@@ -103,8 +103,8 @@ public class EntityIT extends ServerCase {
 
     @Test
     public void testRelationship() {
-        Entity entity = new MockEntity();
-        Relationship rel = new MockRelationship("tst_name");
+        MockEntity entity = new MockEntity();
+        MockRelationship rel = new MockRelationship("tst_name");
 
         entity.addRelationship(rel);
         assertSame(rel, entity.getRelationship(rel.getName()));
@@ -119,13 +119,13 @@ public class EntityIT extends ServerCase {
 
     @Test
     public void testAttributeClashWithRelationship() {
-        Entity entity = new MockEntity();
-        Relationship rel = new MockRelationship("tst_name");
+        MockEntity entity = new MockEntity();
+        MockRelationship rel = new MockRelationship("tst_name");
 
         entity.addRelationship(rel);
 
         try {
-            Attribute attribute = new MockAttribute("tst_name");
+            MockAttribute attribute = new MockAttribute("tst_name");
             entity.addAttribute(attribute);
 
             fail("Exception should have been thrown due to clashing attribute 
and relationship names.");
@@ -136,13 +136,13 @@ public class EntityIT extends ServerCase {
 
     @Test
     public void testRelationshipClashWithAttribute() {
-        Entity entity = new MockEntity();
-        Attribute attribute = new MockAttribute("tst_name");
+        MockEntity entity = new MockEntity();
+        MockAttribute attribute = new MockAttribute("tst_name");
 
         entity.addAttribute(attribute);
 
         try {
-            Relationship rel = new MockRelationship("tst_name");
+            MockRelationship rel = new MockRelationship("tst_name");
             entity.addRelationship(rel);
 
             fail("Exception should have been thrown due to clashing attribute 
and relationship names.");
@@ -205,16 +205,16 @@ public class EntityIT extends ServerCase {
 
     @Test
     public void testRemoveAttribute() {
-        Entity entity = new MockEntity();
+        MockEntity entity = new MockEntity();
 
         entity.setName("test");
-        ObjAttribute attribute1 = new ObjAttribute("a1");
-        ObjAttribute attribute2 = new ObjAttribute("a2");
+        MockAttribute attribute1 = new MockAttribute("a1");
+        MockAttribute attribute2 = new MockAttribute("a2");
 
         entity.addAttribute(attribute1);
         entity.addAttribute(attribute2);
 
-        Collection<? extends Attribute> attributes = entity.getAttributes();
+        Collection<MockAttribute> attributes = entity.getAttributes();
         assertEquals(2, attributes.size());
 
         entity.removeAttribute("a1");
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/map/MockAttribute.java 
b/cayenne-server/src/test/java/org/apache/cayenne/map/MockAttribute.java
index fda7ec5e4..32596e493 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/map/MockAttribute.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/map/MockAttribute.java
@@ -24,7 +24,7 @@ import org.apache.cayenne.util.XMLEncoder;
 
 /**
  */
-public class MockAttribute extends Attribute {
+public class MockAttribute extends Attribute<MockEntity, MockAttribute, 
MockRelationship> {
 
     public MockAttribute() {
         super();
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/map/MockEntity.java 
b/cayenne-server/src/test/java/org/apache/cayenne/map/MockEntity.java
index 94db2e725..793cff03a 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/map/MockEntity.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/map/MockEntity.java
@@ -25,11 +25,12 @@ import java.util.Map;
 import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
 import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.exp.ExpressionException;
+import org.apache.cayenne.util.CayenneMapEntry;
 import org.apache.cayenne.util.XMLEncoder;
 
 /**
  */
-public class MockEntity extends Entity {
+public class MockEntity extends Entity<MockEntity, MockAttribute, 
MockRelationship> {
 
     public MockEntity() {
         super();
@@ -47,13 +48,12 @@ public class MockEntity extends Entity {
     }
 
     @Override
-    public Iterator resolvePathComponents(Expression pathExp) throws 
ExpressionException {
+    public Iterator<CayenneMapEntry> resolvePathComponents(Expression pathExp) 
throws ExpressionException {
         return null;
     }
     
     @Override
-    public <T extends Attribute, U extends Relationship> 
Iterable<PathComponent<T, U>> resolvePath(
-            Expression pathExp, Map joinAliases) {
+    public Iterable<PathComponent<MockAttribute, MockRelationship>> 
resolvePath(Expression pathExp, Map<String, String> joinAliases) {
         return null;
     }
 
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/map/MockRelationship.java 
b/cayenne-server/src/test/java/org/apache/cayenne/map/MockRelationship.java
index ea1ac9bde..0f06e89ee 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/map/MockRelationship.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/map/MockRelationship.java
@@ -22,7 +22,7 @@ package org.apache.cayenne.map;
 import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
 import org.apache.cayenne.util.XMLEncoder;
 
-public class MockRelationship extends Relationship {
+public class MockRelationship extends Relationship<MockEntity, MockAttribute, 
MockRelationship> {
 
     public MockRelationship() {
 
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/map/RelationshipTest.java 
b/cayenne-server/src/test/java/org/apache/cayenne/map/RelationshipTest.java
index 49c55462c..b7870ece8 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/map/RelationshipTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/map/RelationshipTest.java
@@ -28,7 +28,7 @@ public class RelationshipTest {
 
     @Test
     public void testName() throws Exception {
-        Relationship rel = new MockRelationship();
+        MockRelationship rel = new MockRelationship();
 
         String tstName = "tst_name";
         rel.setName(tstName);
@@ -37,16 +37,16 @@ public class RelationshipTest {
 
     @Test
     public void testSourceEntity() {
-        Relationship rel = new MockRelationship();
-        Entity tstEntity = new MockEntity();
+        MockRelationship rel = new MockRelationship();
+        MockEntity tstEntity = new MockEntity();
         rel.setSourceEntity(tstEntity);
         assertSame(tstEntity, rel.getSourceEntity());
     }
 
     @Test
     public void testTargetEntity() {
-        Relationship rel = new MockRelationship();
-        Entity tstEntity = new MockEntity();
+        MockRelationship rel = new MockRelationship();
+        MockEntity tstEntity = new MockEntity();
         tstEntity.setName("abc");
         rel.setTargetEntityName(tstEntity);
         assertSame("abc", rel.getTargetEntityName());
@@ -54,7 +54,7 @@ public class RelationshipTest {
 
     @Test
     public void testTargetEntityName() {
-        Relationship rel = new MockRelationship();
+        MockRelationship rel = new MockRelationship();
         rel.setTargetEntityName("abc");
         assertSame("abc", rel.getTargetEntityName());
     }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
index 319a186d5..16ea15243 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjAttributeTableModel.java
@@ -22,7 +22,6 @@ package org.apache.cayenne.modeler.editor;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.dba.TypesMapping;
-import org.apache.cayenne.map.Attribute;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.EmbeddedAttribute;
@@ -68,7 +67,7 @@ public class ObjAttributeTableModel extends 
CayenneTableModel<ObjAttributeWrappe
     public static final int COMMENT = 6;
     public static final int COLUMN_COUNT = 7;
 
-    private ObjEntity entity;
+    private final ObjEntity entity;
     private DbEntity dbEntity;
     private CellEditorForAttributeTable cellEditor;
     private CayenneTable table;
@@ -80,20 +79,16 @@ public class ObjAttributeTableModel extends 
CayenneTableModel<ObjAttributeWrappe
         this.dbEntity = entity.getDbEntity();
 
         // order using local comparator
-        Collections.sort(objectList, new AttributeComparator());
+        objectList.sort(new AttributeComparator());
     }
 
     private static List<ObjAttributeWrapper> 
wrapObjAttributes(Collection<ObjAttribute> attributes) {
-        List<ObjAttributeWrapper>  wrappedAttributes = new 
ArrayList<ObjAttributeWrapper>();
+        List<ObjAttributeWrapper>  wrappedAttributes = new ArrayList<>();
         for(ObjAttribute attr : attributes) {
             wrappedAttributes.add(new ObjAttributeWrapper(attr));
         }
         return wrappedAttributes;
     }
-    
-    protected void orderList() {
-        // NOOP
-    }
 
     public CayenneTable getTable() {
         return table;
@@ -415,19 +410,19 @@ public class ObjAttributeTableModel extends 
CayenneTableModel<ObjAttributeWrappe
         return entity;
     }
 
-    final class AttributeComparator implements Comparator {
+    final class AttributeComparator implements Comparator<ObjAttributeWrapper> 
{
 
-        public int compare(Object o1, Object o2) {
-            Attribute a1 = ((ObjAttributeWrapper) o1).getValue();
-            Attribute a2 = ((ObjAttributeWrapper) o2).getValue();
+        public int compare(ObjAttributeWrapper o1, ObjAttributeWrapper o2) {
+            ObjAttribute a1 = o1.getValue();
+            ObjAttribute a2 = o2.getValue();
 
             int delta = getWeight(a1) - getWeight(a2);
-
-            return (delta != 0) ? delta : Util.nullSafeCompare(true, 
a1.getName(), a2
-                    .getName());
+            return (delta != 0)
+                    ? delta
+                    : Util.nullSafeCompare(true, a1.getName(), a2.getName());
         }
 
-        private int getWeight(Attribute a) {
+        private int getWeight(ObjAttribute a) {
             return a.getEntity() == entity ? 1 : -1;
         }
     }
@@ -449,7 +444,7 @@ public class ObjAttributeTableModel extends 
CayenneTableModel<ObjAttributeWrappe
                 break;
             case DB_ATTRIBUTE:
             case DB_ATTRIBUTE_TYPE:
-                Collections.sort(objectList, new 
ObjAttributeTableComparator(sortCol));
+                objectList.sort(new ObjAttributeTableComparator(sortCol));
                 if (!isAscent) {
                     Collections.reverse(objectList);
                 }
@@ -459,7 +454,7 @@ public class ObjAttributeTableModel extends 
CayenneTableModel<ObjAttributeWrappe
 
     private class ObjAttributeTableComparator implements 
Comparator<ObjAttributeWrapper>{
 
-        private int sortCol;
+        private final int sortCol;
 
         public ObjAttributeTableComparator(int sortCol) {
             this.sortCol = sortCol;
@@ -479,27 +474,23 @@ public class ObjAttributeTableModel extends 
CayenneTableModel<ObjAttributeWrappe
                     valToCompare2 = getDBAttribute(o2, o2.getDbAttribute());
                     break;
                 case DB_ATTRIBUTE_TYPE:
-                    valToCompare1 = getDBAttributeType(o1, o1
-                            .getDbAttribute());
-                    valToCompare2 = getDBAttributeType(o2, o2
-                            .getDbAttribute());
-                    break;
-                default:
+                    valToCompare1 = getDBAttributeType(o1, 
o1.getDbAttribute());
+                    valToCompare2 = getDBAttributeType(o2, 
o2.getDbAttribute());
                     break;
             }
-            return (valToCompare1 == null) ? -1 : (valToCompare2 == null)
-                    ? 1
-                    : valToCompare1.compareTo(valToCompare2);
+            return (valToCompare1 == null)
+                    ? -1
+                    : (valToCompare2 == null)
+                        ? 1
+                        : valToCompare1.compareTo(valToCompare2);
         }
 
         private Integer compareObjAttributes(ObjAttributeWrapper o1, 
ObjAttributeWrapper o2) {
-            if ((o1 == null && o2 == null) || o1 == o2) {
+            if (o1 == o2) {
                 return 0;
-            }
-            else if (o1 == null && o2 != null) {
+            } else if (o1 == null) {
                 return -1;
-            }
-            else if (o1 != null && o2 == null) {
+            } else if (o2 == null) {
                 return 1;
             }
             return null;
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/wrapper/ObjAttributeWrapper.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/wrapper/ObjAttributeWrapper.java
index f6f64db45..7fd3027f0 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/wrapper/ObjAttributeWrapper.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/wrapper/ObjAttributeWrapper.java
@@ -36,13 +36,13 @@ import org.apache.cayenne.validation.ValidationResult;
  */
 public class ObjAttributeWrapper implements Wrapper<ObjAttribute> {
 
-    private ObjAttribute objAttribute;
-    private ValidationResult validationResult;
+    private final ObjAttribute objAttribute;
+    private final ValidationResult validationResult;
 
-    private ObjAttributeWrapperValidator validator = new 
ObjAttributeWrapperValidator();
+    private final ObjAttributeWrapperValidator validator = new 
ObjAttributeWrapperValidator();
 
     // TODO: for now name is only wrapped attribute we validating but this
-    // can be extended to other ObjAttribute fields as well
+    //       can be extended to other ObjAttribute fields as well
     private String name;
 
     public ObjAttributeWrapper(ObjAttribute objAttribute) {
@@ -98,7 +98,7 @@ public class ObjAttributeWrapper implements 
Wrapper<ObjAttribute> {
         return objAttribute.getEntity();
     }
 
-    public void setEntity(Entity entity) {
+    public void setEntity(ObjEntity entity) {
         objAttribute.setEntity(entity);
     }
 
@@ -120,7 +120,7 @@ public class ObjAttributeWrapper implements 
Wrapper<ObjAttribute> {
     }
 
     public Class<?> getJavaClass() {
-        return objAttribute.getClass();
+        return objAttribute.getJavaClass();
     }
 
     public String getType() {
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/BaseGraphBuilder.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/BaseGraphBuilder.java
index 303ecc676..c7ef52e4d 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/BaseGraphBuilder.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/BaseGraphBuilder.java
@@ -289,7 +289,7 @@ abstract class BaseGraphBuilder implements GraphBuilder, 
DataMapListener {
     /**
      * Post (i.e. after creation on entity cell) process of the entity
      */
-    protected void postProcessEntity(Entity entity, DefaultGraphCell cell) {
+    protected void postProcessEntity(Entity<?,?,?> entity, DefaultGraphCell 
cell) {
         for (Relationship rel : entity.getRelationships()) {
             if (rel.getSourceEntity() != null && rel.getTargetEntity() != 
null) {
                 DefaultEdge edge = createRelationshipCell(rel);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/DbEntityCellMetadata.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/DbEntityCellMetadata.java
index 192377010..025bcf338 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/DbEntityCellMetadata.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/DbEntityCellMetadata.java
@@ -18,27 +18,23 @@
  ****************************************************************/
 package org.apache.cayenne.modeler.graph;
 
-import java.util.Iterator;
-
-import org.apache.cayenne.map.Attribute;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
 
 /**
  * Descriptor of DbEntity Cell
  */
-class DbEntityCellMetadata extends EntityCellMetadata {
+class DbEntityCellMetadata extends EntityCellMetadata<DbEntity, DbAttribute, 
DbRelationship> {
     DbEntityCellMetadata(GraphBuilder builder, String entityName) {
         super(builder, entityName);
     }
     
     @Override
-    public Entity fetchEntity() {
-        Iterator<DataMap> it = 
builder.getDataDomain().getDataMaps().iterator();
-        while(it.hasNext()){
-            DataMap dm = (DataMap)it.next();
-            if(dm.getDbEntity(entityName)!=null){
+    public DbEntity fetchEntity() {
+        for (DataMap dm : builder.getDataDomain().getDataMaps()) {
+            if (dm.getDbEntity(entityName) != null) {
                 return dm.getDbEntity(entityName);
             }
         }
@@ -46,7 +42,7 @@ class DbEntityCellMetadata extends EntityCellMetadata {
     }
 
     @Override
-    protected boolean isPrimary(Attribute attr) {
-        return ((DbAttribute) attr).isPrimaryKey();
+    protected boolean isPrimary(DbAttribute attr) {
+        return attr.isPrimaryKey();
     }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/EntityCellMetadata.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/EntityCellMetadata.java
index c51b75cb0..b9affa6ec 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/EntityCellMetadata.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/EntityCellMetadata.java
@@ -22,11 +22,12 @@ import java.io.Serializable;
 
 import org.apache.cayenne.map.Attribute;
 import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.Relationship;
 
 /**
  * Abstract class to describe entity's cell 
  */
-abstract class EntityCellMetadata implements Serializable {
+abstract class EntityCellMetadata<E extends Entity<E, T, U>, T extends 
Attribute<E,T,U>, U extends Relationship<E,T,U>> implements Serializable {
     GraphBuilder builder;
     
     String entityName;
@@ -45,7 +46,7 @@ abstract class EntityCellMetadata implements Serializable {
     /**
      * Resolves entity
      */
-    public abstract Entity fetchEntity();
+    public abstract Entity<E,T,U> fetchEntity();
     
     final void rebuildLabel() {
         label = createLabel();
@@ -63,15 +64,15 @@ abstract class EntityCellMetadata implements Serializable {
      * Creates label for this cell
      */
     String createLabel() {
-        Entity entity = fetchEntity();
+        Entity<E,T,U> entity = fetchEntity();
         StringBuilder label = new StringBuilder("<html><center><u><b>").
                 append(entity.getName()).append("</b></u></center>");
-        for (Attribute attr : entity.getAttributes()) {
+        for (T attr : entity.getAttributes()) {
             if (isPrimary(attr)) {
                 label.append("<br><i>").append(attr.getName()).append("</i>");
             }
         }
-        for (Attribute attr : entity.getAttributes()) {
+        for (T attr : entity.getAttributes()) {
             if (!isPrimary(attr)) {
                 label.append("<br>").append(attr.getName());
             }
@@ -82,5 +83,5 @@ abstract class EntityCellMetadata implements Serializable {
     /**
      * Returns whether attribute is "primary" and should therefore be written 
in italic
      */
-    protected abstract boolean isPrimary(Attribute attr);
+    protected abstract boolean isPrimary(T attr);
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/ObjEntityCellMetadata.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/ObjEntityCellMetadata.java
index 648ee0597..2c265532a 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/ObjEntityCellMetadata.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/ObjEntityCellMetadata.java
@@ -18,26 +18,23 @@
  ****************************************************************/
 package org.apache.cayenne.modeler.graph;
 
-import java.util.Iterator;
-
-import org.apache.cayenne.map.Attribute;
 import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
 
 /**
  * Descriptor of ObjEntity Cell
  */
-class ObjEntityCellMetadata extends EntityCellMetadata {
+class ObjEntityCellMetadata extends EntityCellMetadata<ObjEntity, 
ObjAttribute, ObjRelationship> {
     ObjEntityCellMetadata(GraphBuilder builder, String entityName) {
         super(builder, entityName);
     }
     
     @Override
-    public Entity fetchEntity() {
-        Iterator<DataMap> it = 
builder.getDataDomain().getDataMaps().iterator();
-        while(it.hasNext()){
-            DataMap dm = (DataMap)it.next();
-            if(dm.getObjEntity(entityName)!=null){
+    public ObjEntity fetchEntity() {
+        for (DataMap dm : builder.getDataDomain().getDataMaps()) {
+            if (dm.getObjEntity(entityName) != null) {
                 return dm.getObjEntity(entityName);
             }
         }
@@ -45,7 +42,7 @@ class ObjEntityCellMetadata extends EntityCellMetadata {
     }
 
     @Override
-    protected boolean isPrimary(Attribute attr) {
+    protected boolean isPrimary(ObjAttribute attr) {
         return false;
     }
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java
index 42a584af7..789a93273 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/RelationshipUndoableEdit.java
@@ -35,12 +35,12 @@ public class RelationshipUndoableEdit extends 
CayenneUndoableEdit {
 
        private static final long serialVersionUID = -1864303176024098961L;
 
-       private Relationship relationship;
-    private Relationship prevRelationship;
+       private Relationship<?,?,?> relationship;
+    private Relationship<?,?,?> prevRelationship;
     private ProjectController projectController;
     private boolean useDb;
 
-       public RelationshipUndoableEdit(Relationship relationship) {
+       public RelationshipUndoableEdit(Relationship<?,?,?> relationship) {
                this.projectController = 
Application.getInstance().getFrameController().getProjectController();
                this.relationship = relationship;
                this.useDb = relationship instanceof DbRelationship;
@@ -57,16 +57,16 @@ public class RelationshipUndoableEdit extends 
CayenneUndoableEdit {
                fireRelationshipEvent(prevRelationship, relationship);
        }
 
-       private void fireRelationshipEvent(Relationship relToFire, Relationship 
currRel) {
+       private void fireRelationshipEvent(Relationship<?,?,?> relToFire, 
Relationship<?,?,?> currRel) {
                if(useDb) {
-                       fireDbRelationshipEvent(relToFire, currRel);
+                       fireDbRelationshipEvent((DbRelationship) relToFire, 
(DbRelationship)currRel);
                } else {
-                       fireObjRelationshipEvent(relToFire, currRel);
+                       fireObjRelationshipEvent((ObjRelationship) relToFire, 
(ObjRelationship) currRel);
                }
        }
 
-       private void fireDbRelationshipEvent(Relationship relToFire, 
Relationship currRel) {
-               DbEntity dbEntity = ((DbRelationship)currRel).getSourceEntity();
+       private void fireDbRelationshipEvent(DbRelationship relToFire, 
DbRelationship currRel) {
+               DbEntity dbEntity = currRel.getSourceEntity();
                dbEntity.removeRelationship(currRel.getName());
                dbEntity.addRelationship(relToFire);
                projectController
@@ -74,8 +74,8 @@ public class RelationshipUndoableEdit extends 
CayenneUndoableEdit {
                                                new RelationshipEvent(this, 
relToFire, relToFire.getSourceEntity(), MapEvent.ADD));
        }
 
-       private void fireObjRelationshipEvent(Relationship relToFire, 
Relationship currRel) {
-               ObjEntity objEntity = ((ObjRelationship) 
currRel).getSourceEntity();
+       private void fireObjRelationshipEvent(ObjRelationship relToFire, 
ObjRelationship currRel) {
+               ObjEntity objEntity = currRel.getSourceEntity();
                objEntity.removeRelationship(currRel.getName());
                objEntity.addRelationship(relToFire);
                projectController
@@ -93,14 +93,16 @@ public class RelationshipUndoableEdit extends 
CayenneUndoableEdit {
                return "Undo Edit relationship";
        }
 
-       private Relationship copyRelationship(Relationship relationship) {
-               return useDb ? getDbRelationship(relationship) : 
getObjRelationship(relationship);
+       private Relationship<?,?,?> copyRelationship(Relationship<?,?,?> 
relationship) {
+               return useDb
+                               ? getDbRelationship((DbRelationship) 
relationship)
+                               : getObjRelationship((ObjRelationship) 
relationship);
        }
 
-       private DbRelationship getDbRelationship(Relationship dbRelationship) {
+       private DbRelationship getDbRelationship(DbRelationship dbRelationship) 
{
                DbRelationship rel = new DbRelationship();
                rel.setName(dbRelationship.getName());
-               
rel.setToDependentPK(((DbRelationship)dbRelationship).isToDependentPK());
+               rel.setToDependentPK(dbRelationship.isToDependentPK());
                rel.setToMany(dbRelationship.isToMany());
                rel.setTargetEntityName(dbRelationship.getTargetEntityName());
                rel.setSourceEntity(dbRelationship.getSourceEntity());
@@ -108,16 +110,16 @@ public class RelationshipUndoableEdit extends 
CayenneUndoableEdit {
                return rel;
        }
 
-       private ObjRelationship getObjRelationship(Relationship 
objRelationship) {
+       private ObjRelationship getObjRelationship(ObjRelationship 
objRelationship) {
                ObjRelationship rel = new ObjRelationship();
                rel.setName(objRelationship.getName());
                rel.setTargetEntityName(objRelationship.getTargetEntityName());
                rel.setSourceEntity(objRelationship.getSourceEntity());
-               
rel.setDeleteRule(((ObjRelationship)objRelationship).getDeleteRule());
-               
rel.setUsedForLocking(((ObjRelationship)objRelationship).isUsedForLocking());
-               
rel.setDbRelationshipPath(((ObjRelationship)objRelationship).getDbRelationshipPath());
-               
rel.setCollectionType(((ObjRelationship)objRelationship).getCollectionType());
-               rel.setMapKey(((ObjRelationship)objRelationship).getMapKey());
+               rel.setDeleteRule(objRelationship.getDeleteRule());
+               rel.setUsedForLocking(objRelationship.isUsedForLocking());
+               
rel.setDbRelationshipPath(objRelationship.getDbRelationshipPath());
+               rel.setCollectionType(objRelationship.getCollectionType());
+               rel.setMapKey(objRelationship.getMapKey());
                return rel;
        }
 }
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeModel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeModel.java
index 24276ddd9..fb2812217 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeModel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeModel.java
@@ -33,7 +33,6 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Vector;
 
 /**
  * Swing TreeModel for Entity attributes and relationships
@@ -41,7 +40,7 @@ import java.util.Vector;
  * @since 1.1
  */
 public class EntityTreeModel implements TreeModel {
-    protected Entity root;
+    protected Entity<?,?,?> root;
     protected Map<Object, ConfigurationNode[]> sortedChildren;
 
     /**
@@ -49,7 +48,7 @@ public class EntityTreeModel implements TreeModel {
      */
     protected EntityTreeFilter filter;
 
-    public EntityTreeModel(Entity root) {
+    public EntityTreeModel(Entity<?,?,?> root) {
         this.root = root;
         sortedChildren = new HashMap<>();
     }
@@ -92,6 +91,7 @@ public class EntityTreeModel implements TreeModel {
         // do nothing...
     }
 
+    @SuppressWarnings({"unchecked", "rawtypes"})
     private ConfigurationNode[] sortedChildren(Object node) {
         Entity entity = entityForNonLeafNode(node);
 
@@ -103,19 +103,19 @@ public class EntityTreeModel implements TreeModel {
         ConfigurationNode[] sortedForNode = sortedChildren.get(node);
 
         if (sortedForNode == null) {
-            Collection<? extends Attribute> attributes = 
entity.getAttributes();
-            Collection<? extends Relationship> relationships = 
entity.getRelationships();
+            Collection<Attribute<?,?,?>> attributes = entity.getAttributes();
+            Collection<Relationship<?,?,?>> relationships = 
entity.getRelationships();
 
             List<ConfigurationNode> nodes = new ArrayList<>();
 
             // combine two collections in an array
-            for (Attribute attr : attributes) {
+            for (Attribute<?,?,?> attr : attributes) {
                 if (filter == null || filter.attributeMatch(node, attr)) {
                     nodes.add((ConfigurationNode)attr);
                 }
             }
 
-            for (Relationship rel : relationships) {
+            for (Relationship<?,?,?> rel : relationships) {
                 if (filter == null || filter.relationshipMatch(node, rel)) {
                     nodes.add((ConfigurationNode)rel);
                 }
@@ -140,19 +140,19 @@ public class EntityTreeModel implements TreeModel {
     /**
      * Removes children cache for specified entity.
      */
-    public void invalidateChildren(Entity entity) {
+    public void invalidateChildren(Entity<?,?,?> entity) {
         sortedChildren.remove(entity);
 
-        for (Relationship rel : entity.getRelationships()) {
+        for (Relationship<?,?,?> rel : entity.getRelationships()) {
             sortedChildren.remove(rel);
         }
     }
 
-    private Entity entityForNonLeafNode(Object node) {
+    private Entity<?,?,?> entityForNonLeafNode(Object node) {
         if (node instanceof Entity) {
-            return (Entity) node;
+            return (Entity<?,?,?>) node;
         } else if (node instanceof Relationship) {
-            return ((Relationship) node).getTargetEntity();
+            return ((Relationship<?,?,?>) node).getTargetEntity();
         }
 
         String className = (node != null) ? node.getClass().getName() : "null";
diff --git 
a/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOObjEntity.java
 
b/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOObjEntity.java
index b25132415..53cba8228 100644
--- 
a/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOObjEntity.java
+++ 
b/modeler/cayenne-wocompat/src/main/java/org/apache/cayenne/wocompat/EOObjEntity.java
@@ -25,6 +25,7 @@ import org.apache.cayenne.exp.ExpressionException;
 import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.ObjRelationship;
 import org.apache.cayenne.map.Relationship;
 
 import java.util.ArrayList;
@@ -184,7 +185,7 @@ public class EOObjEntity extends ObjEntity {
 
                     buffer.append(chunk);
 
-                    Relationship r = entity.getRelationship(chunk);
+                    ObjRelationship r = entity.getRelationship(chunk);
                     if (r == null) {
                         throw new ExpressionException("Invalid path component: 
" + chunk);
                     }

Reply via email to