cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aadamc...@apache.org
Subject [09/12] cayenne git commit: CAY-2026 Java 7
Date Sat, 12 Sep 2015 10:41:12 GMT
http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/ObjectResolver.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/ObjectResolver.java b/cayenne-server/src/main/java/org/apache/cayenne/access/ObjectResolver.java
index a9db1da..1090e4a 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/ObjectResolver.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/ObjectResolver.java
@@ -45,239 +45,218 @@ import org.apache.cayenne.reflect.ClassDescriptor;
  */
 class ObjectResolver {
 
-    DataContext context;
-    ClassDescriptor descriptor;
-    Collection<DbAttribute> primaryKey;
-
-    boolean refreshObjects;
-    DataRowStore cache;
-    DescriptorResolutionStrategy descriptorResolutionStrategy;
-
-    ObjectResolver(DataContext context, ClassDescriptor descriptor, boolean refresh) {
-
-        // sanity check
-        if (descriptor == null || descriptor.getEntity() == null) {
-            throw new CayenneRuntimeException(
-                    "Set up Object entity or use rowFetchingQuery");
-        }
-
-        DbEntity dbEntity = descriptor.getEntity().getDbEntity();
-        if (dbEntity == null) {
-            throw new CayenneRuntimeException("ObjEntity '"
-                    + descriptor.getEntity().getName()
-                    + "' has no DbEntity.");
-        }
-
-        this.primaryKey = dbEntity.getPrimaryKeys();
-        if (primaryKey.size() == 0) {
-            throw new CayenneRuntimeException("Won't be able to create ObjectId for '"
-                    + descriptor.getEntity().getName()
-                    + "'. Reason: DbEntity '"
-                    + dbEntity.getName()
-                    + "' has no Primary Key defined.");
-        }
-
-        this.context = context;
-        this.cache = context.getObjectStore().getDataRowCache();
-        this.refreshObjects = refresh;
-        this.descriptor = descriptor;
-
-        this.descriptorResolutionStrategy = descriptor.hasSubclasses()
-                ? new InheritanceStrategy()
-                : new NoInheritanceStrategy();
-    }
-
-    PrefetchProcessorNode synchronizedRootResultNodeFromDataRows(
-            List<? extends DataRow> rows) {
-        PrefetchProcessorNode rootNode = new PrefetchProcessorNode(null, null);
-        rootNode.setObjects(synchronizedObjectsFromDataRows(rows));
-        return rootNode;
-    }
-
-    /**
-     * Properly synchronized version of 'objectsFromDataRows'.
-     */
-    List<Persistent> synchronizedObjectsFromDataRows(List<? extends DataRow> rows) {
-        synchronized (context.getObjectStore()) {
-            return objectsFromDataRows(rows);
-        }
-    }
-
-    /**
-     * Converts rows to objects.
-     * <p>
-     * Synchronization note. This method requires EXTERNAL synchronization on ObjectStore
-     * and DataRowStore.
-     * </p>
-     */
-    List<Persistent> objectsFromDataRows(List<? extends DataRow> rows) {
-        if (rows == null || rows.size() == 0) {
-            return new ArrayList<Persistent>(1);
-        }
-
-        List<Persistent> results = new ArrayList<Persistent>(rows.size());
-        for (DataRow row : rows) {
-            // nulls are possible here since 3.0 for soem varieties of EJBQL
-            results.add(objectFromDataRow(row));
-        }
-
-        // now deal with snapshots
-        cache.snapshotsUpdatedForObjects(results, rows, refreshObjects);
-        return results;
-    }
-
-    Persistent objectFromDataRow(DataRow row) {
-        // determine entity to use
-        ClassDescriptor classDescriptor = descriptorResolutionStrategy
-                .descriptorForRow(row);
-
-        // not using DataRow.createObjectId for performance reasons - ObjectResolver
-        // has all needed metadata already cached.
-        ObjectId anId = createObjectId(row, classDescriptor.getEntity(), null);
-        return objectFromDataRow(row, anId, classDescriptor);
-    }
-
-    Persistent objectFromDataRow(
-            DataRow row,
-            ObjectId anId,
-            ClassDescriptor classDescriptor) {
-
-        // this condition is valid - see comments on 'createObjectId' for details
-        if (anId == null) {
-            return null;
-        }
-
-        // this will create a HOLLOW object if it is not registered yet
-        Persistent object = context.findOrCreateObject(anId);
-
-        // deal with object state
-        int state = object.getPersistenceState();
-        switch (state) {
-            case PersistenceState.COMMITTED:
-            case PersistenceState.MODIFIED:
-            case PersistenceState.DELETED:
-                // process the above only if refresh is requested...
-                if (refreshObjects) {
-                    DataRowUtils.mergeObjectWithSnapshot(
-                            context,
-                            classDescriptor,
-                            object,
-                            row);
-
-                    if (object instanceof DataObject) {
-                        ((DataObject) object).setSnapshotVersion(row.getVersion());
-                    }
-                }
-                break;
-            case PersistenceState.HOLLOW:
-                if (!refreshObjects) {
-                    DataRow cachedRow = cache.getCachedSnapshot(anId);
-                    if (cachedRow != null) {
-                        row = cachedRow;
-                    }
-                }
-                DataRowUtils.mergeObjectWithSnapshot(
-                        context,
-                        classDescriptor,
-                        object,
-                        row);
-                if (object instanceof DataObject) {
-                    ((DataObject) object).setSnapshotVersion(row.getVersion());
-                }
-                break;
-            default:
-                break;
-        }
-
-        return object;
-    }
-
-    ObjEntity getEntity() {
-        return descriptor.getEntity();
-    }
-
-    ClassDescriptor getDescriptor() {
-        return descriptor;
-    }
-
-    EntityResolver getEntityResolver() {
-        return context.getEntityResolver();
-    }
-
-    ObjectContext getContext() {
-        return context;
-    }
-
-    ObjectId createObjectId(DataRow dataRow, ObjEntity objEntity, String namePrefix) {
-
-        Collection<DbAttribute> pk = objEntity == this.descriptor.getEntity()
-                ? this.primaryKey
-                : objEntity.getDbEntity().getPrimaryKeys();
-
-        boolean prefix = namePrefix != null && namePrefix.length() > 0;
-
-        // ... handle special case - PK.size == 1
-        // use some not-so-significant optimizations...
-
-        if (pk.size() == 1) {
-            DbAttribute attribute = pk.iterator().next();
-
-            String key = (prefix) ? namePrefix + attribute.getName() : attribute
-                    .getName();
-
-            Object val = dataRow.get(key);
-
-            // this is possible when processing left outer joint prefetches
-            if (val == null) {
-                return null;
-            }
-
-            // PUT without a prefix
-            return new ObjectId(objEntity.getName(), attribute.getName(), val);
-        }
-
-        // ... handle generic case - PK.size > 1
-
-        Map<String, Object> idMap = new HashMap<String, Object>(pk.size() * 2);
-        for (final DbAttribute attribute : pk) {
-
-            String key = (prefix) ? namePrefix + attribute.getName() : attribute
-                    .getName();
-
-            Object val = dataRow.get(key);
-
-            // this is possible when processing left outer joint prefetches
-            if (val == null) {
-                return null;
-            }
-
-            // PUT without a prefix
-            idMap.put(attribute.getName(), val);
-        }
-
-        return new ObjectId(objEntity.getName(), idMap);
-    }
-
-    interface DescriptorResolutionStrategy {
-
-        ClassDescriptor descriptorForRow(DataRow row);
-    }
+	DataContext context;
+	ClassDescriptor descriptor;
+	Collection<DbAttribute> primaryKey;
+
+	boolean refreshObjects;
+	DataRowStore cache;
+	DescriptorResolutionStrategy descriptorResolutionStrategy;
+
+	ObjectResolver(DataContext context, ClassDescriptor descriptor, boolean refresh) {
+
+		// sanity check
+		if (descriptor == null || descriptor.getEntity() == null) {
+			throw new CayenneRuntimeException("Set up Object entity or use rowFetchingQuery");
+		}
+
+		DbEntity dbEntity = descriptor.getEntity().getDbEntity();
+		if (dbEntity == null) {
+			throw new CayenneRuntimeException("ObjEntity '" + descriptor.getEntity().getName() + "' has no DbEntity.");
+		}
+
+		this.primaryKey = dbEntity.getPrimaryKeys();
+		if (primaryKey.size() == 0) {
+			throw new CayenneRuntimeException("Won't be able to create ObjectId for '"
+					+ descriptor.getEntity().getName() + "'. Reason: DbEntity '" + dbEntity.getName()
+					+ "' has no Primary Key defined.");
+		}
+
+		this.context = context;
+		this.cache = context.getObjectStore().getDataRowCache();
+		this.refreshObjects = refresh;
+		this.descriptor = descriptor;
+
+		this.descriptorResolutionStrategy = descriptor.hasSubclasses() ? new InheritanceStrategy()
+				: new NoInheritanceStrategy();
+	}
+
+	PrefetchProcessorNode synchronizedRootResultNodeFromDataRows(List<? extends DataRow> rows) {
+		PrefetchProcessorNode rootNode = new PrefetchProcessorNode(null, null);
+		rootNode.setObjects(synchronizedObjectsFromDataRows(rows));
+		return rootNode;
+	}
+
+	/**
+	 * Properly synchronized version of 'objectsFromDataRows'.
+	 */
+	List<Persistent> synchronizedObjectsFromDataRows(List<? extends DataRow> rows) {
+		synchronized (context.getObjectStore()) {
+			return objectsFromDataRows(rows);
+		}
+	}
+
+	/**
+	 * Converts rows to objects.
+	 * <p>
+	 * Synchronization note. This method requires EXTERNAL synchronization on
+	 * ObjectStore and DataRowStore.
+	 * </p>
+	 */
+	List<Persistent> objectsFromDataRows(List<? extends DataRow> rows) {
+		if (rows == null || rows.size() == 0) {
+			return new ArrayList<Persistent>(1);
+		}
+
+		List<Persistent> results = new ArrayList<Persistent>(rows.size());
+		for (DataRow row : rows) {
+			// nulls are possible here since 3.0 for soem varieties of EJBQL
+			results.add(objectFromDataRow(row));
+		}
+
+		// now deal with snapshots
+		cache.snapshotsUpdatedForObjects(results, rows, refreshObjects);
+		return results;
+	}
+
+	Persistent objectFromDataRow(DataRow row) {
+		// determine entity to use
+		ClassDescriptor classDescriptor = descriptorResolutionStrategy.descriptorForRow(row);
+
+		// not using DataRow.createObjectId for performance reasons -
+		// ObjectResolver
+		// has all needed metadata already cached.
+		ObjectId anId = createObjectId(row, classDescriptor.getEntity(), null);
+		return objectFromDataRow(row, anId, classDescriptor);
+	}
+
+	Persistent objectFromDataRow(DataRow row, ObjectId anId, ClassDescriptor classDescriptor) {
+
+		// this condition is valid - see comments on 'createObjectId' for
+		// details
+		if (anId == null) {
+			return null;
+		}
+
+		// this will create a HOLLOW object if it is not registered yet
+		Persistent object = context.findOrCreateObject(anId);
+
+		// deal with object state
+		int state = object.getPersistenceState();
+		switch (state) {
+		case PersistenceState.COMMITTED:
+		case PersistenceState.MODIFIED:
+		case PersistenceState.DELETED:
+			// process the above only if refresh is requested...
+			if (refreshObjects) {
+				DataRowUtils.mergeObjectWithSnapshot(context, classDescriptor, object, row);
+
+				if (object instanceof DataObject) {
+					((DataObject) object).setSnapshotVersion(row.getVersion());
+				}
+			}
+			break;
+		case PersistenceState.HOLLOW:
+			if (!refreshObjects) {
+				DataRow cachedRow = cache.getCachedSnapshot(anId);
+				if (cachedRow != null) {
+					row = cachedRow;
+				}
+			}
+			DataRowUtils.mergeObjectWithSnapshot(context, classDescriptor, object, row);
+			if (object instanceof DataObject) {
+				((DataObject) object).setSnapshotVersion(row.getVersion());
+			}
+			break;
+		default:
+			break;
+		}
+
+		return object;
+	}
+
+	ObjEntity getEntity() {
+		return descriptor.getEntity();
+	}
+
+	ClassDescriptor getDescriptor() {
+		return descriptor;
+	}
+
+	EntityResolver getEntityResolver() {
+		return context.getEntityResolver();
+	}
+
+	ObjectContext getContext() {
+		return context;
+	}
+
+	ObjectId createObjectId(DataRow dataRow, ObjEntity objEntity, String namePrefix) {
+
+		Collection<DbAttribute> pk = objEntity == this.descriptor.getEntity() ? this.primaryKey : objEntity
+				.getDbEntity().getPrimaryKeys();
+
+		boolean prefix = namePrefix != null && namePrefix.length() > 0;
+
+		// ... handle special case - PK.size == 1
+		// use some not-so-significant optimizations...
+
+		if (pk.size() == 1) {
+			DbAttribute attribute = pk.iterator().next();
+
+			String key = (prefix) ? namePrefix + attribute.getName() : attribute.getName();
+
+			Object val = dataRow.get(key);
+
+			// this is possible when processing left outer joint prefetches
+			if (val == null) {
+				return null;
+			}
 
-    class NoInheritanceStrategy implements DescriptorResolutionStrategy {
-
-        public final ClassDescriptor descriptorForRow(DataRow row) {
-            return descriptor;
-        }
-    }
+			// PUT without a prefix
+			return new ObjectId(objEntity.getName(), attribute.getName(), val);
+		}
 
-    class InheritanceStrategy implements DescriptorResolutionStrategy {
+		// ... handle generic case - PK.size > 1
 
-        public final ClassDescriptor descriptorForRow(DataRow row) {
-            String entityName = row.getEntityName();
+		Map<String, Object> idMap = new HashMap<>(pk.size() * 2);
+		for (final DbAttribute attribute : pk) {
 
-            // null probably means that inheritance qualifiers are messed up
-            return (entityName != null) ? context.getEntityResolver().getClassDescriptor(
-                    entityName) : descriptor;
-        }
-    }
+			String key = (prefix) ? namePrefix + attribute.getName() : attribute.getName();
+
+			Object val = dataRow.get(key);
+
+			// this is possible when processing left outer joint prefetches
+			if (val == null) {
+				return null;
+			}
+
+			// PUT without a prefix
+			idMap.put(attribute.getName(), val);
+		}
+
+		return new ObjectId(objEntity.getName(), idMap);
+	}
+
+	interface DescriptorResolutionStrategy {
+
+		ClassDescriptor descriptorForRow(DataRow row);
+	}
+
+	class NoInheritanceStrategy implements DescriptorResolutionStrategy {
+
+		public final ClassDescriptor descriptorForRow(DataRow row) {
+			return descriptor;
+		}
+	}
+
+	class InheritanceStrategy implements DescriptorResolutionStrategy {
+
+		public final ClassDescriptor descriptorForRow(DataRow row) {
+			String entityName = row.getEntityName();
+
+			// null probably means that inheritance qualifiers are messed up
+			return (entityName != null) ? context.getEntityResolver().getClassDescriptor(entityName) : descriptor;
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/dbsync/CreateIfNoSchemaStrategy.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/dbsync/CreateIfNoSchemaStrategy.java b/cayenne-server/src/main/java/org/apache/cayenne/access/dbsync/CreateIfNoSchemaStrategy.java
index 3a7675f..2d72493 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/dbsync/CreateIfNoSchemaStrategy.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/dbsync/CreateIfNoSchemaStrategy.java
@@ -88,7 +88,7 @@ public class CreateIfNoSchemaStrategy extends BaseSchemaUpdateStrategy {
 	 */
 	protected Map<String, Boolean> getNameTablesInDB(DataNode dataNode) throws SQLException {
 		String tableLabel = dataNode.getAdapter().tableTypeForTable();
-		Map<String, Boolean> nameTables = new HashMap<String, Boolean>();
+		Map<String, Boolean> nameTables = new HashMap<>();
 
 		try (Connection con = dataNode.getDataSource().getConnection();) {
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/dbsync/SchemaAnalyzer.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/dbsync/SchemaAnalyzer.java b/cayenne-server/src/main/java/org/apache/cayenne/access/dbsync/SchemaAnalyzer.java
index 86f29c8..4cd6b56 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/dbsync/SchemaAnalyzer.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/dbsync/SchemaAnalyzer.java
@@ -45,11 +45,11 @@ class SchemaAnalyzer {
 
 	SchemaAnalyzer() {
 		errorMessage = null;
-		mapTableInDB = new HashMap<String, String>();
-		tableNoInDB = new ArrayList<String>();
-		nameSchemaMap = new HashMap<String, Collection<String>>();
-		schemaNameMap = new HashMap<String, Collection<String>>();
-		entityTables = new HashMap<Map<String, String>, Collection<DbAttribute>>();
+		mapTableInDB = new HashMap<>();
+		tableNoInDB = new ArrayList<>();
+		nameSchemaMap = new HashMap<>();
+		schemaNameMap = new HashMap<>();
+		entityTables = new HashMap<>();
 	}
 
 	public List<String> getTableNoInDB() {
@@ -64,7 +64,7 @@ class SchemaAnalyzer {
 			String name = map.getKey();
 
 			try (ResultSet rs = md.getColumns(null, schema, name, null);) {
-				Map<String, String> schemaName = new HashMap<String, String>();
+				Map<String, String> schemaName = new HashMap<>();
 				schemaName.put(name, schema);
 				Collection<DbAttribute> atribute = entityTables.get(schemaName);
 				if (atribute == null) {
@@ -151,7 +151,7 @@ class SchemaAnalyzer {
 					tableNoInDB.add(name);
 				}
 			}
-			Map<String, String> schemaName = new HashMap<String, String>();
+			Map<String, String> schemaName = new HashMap<>();
 			schemaName.put(name, schema);
 			entityTables.put(schemaName, atributes);
 		}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java
index 6e07506..8f83ccc 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/DistinctResultIterator.java
@@ -164,7 +164,7 @@ public class DistinctResultIterator<T> implements ResultIterator<T> {
             // TODO: this can be optimized by creating an array with id keys
             // to avoid iterating over default entity attributes...
 
-            Map<String, Object> id = new HashMap<String, Object>();
+            Map<String, Object> id = new HashMap<>();
             for (final DbAttribute pk : defaultEntity.getPrimaryKeys()) {
                 id.put(pk.getName(), next.get(pk.getName()));
             }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/RowDescriptorBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/RowDescriptorBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/RowDescriptorBuilder.java
index 14375b7..86c1fb7 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/RowDescriptorBuilder.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/RowDescriptorBuilder.java
@@ -223,7 +223,7 @@ public class RowDescriptorBuilder {
     public RowDescriptorBuilder overrideColumnType(String columnName, String type) {
 
         if (typeOverrides == null) {
-            typeOverrides = new HashMap<String, String>();
+            typeOverrides = new HashMap<>();
         }
 
         typeOverrides.put(columnName, type);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java
index 36fd8a9..3391094 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/reader/DefaultRowReaderFactory.java
@@ -45,162 +45,162 @@ import org.apache.cayenne.reflect.ClassDescriptor;
  */
 public class DefaultRowReaderFactory implements RowReaderFactory {
 
-    @Override
-    public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata queryMetadata, DbAdapter adapter,
-            Map<ObjAttribute, ColumnDescriptor> attributeOverrides) {
-
-        PostprocessorFactory postProcessorFactory = new PostprocessorFactory(descriptor, queryMetadata,
-                adapter.getExtendedTypes(), attributeOverrides);
-
-        List<Object> rsMapping = queryMetadata.getResultSetMapping();
-        if (rsMapping == null) {
-            return createFullRowReader(descriptor, queryMetadata, postProcessorFactory);
-        }
-
-        int resultWidth = rsMapping.size();
-        if (resultWidth == 0) {
-            throw new CayenneRuntimeException("Empty result descriptor");
-        } else if (resultWidth == 1) {
-
-            Object segment = rsMapping.get(0);
-
-            if (segment instanceof EntityResultSegment) {
-                return createEntityRowReader(descriptor, queryMetadata, (EntityResultSegment) segment,
-                        postProcessorFactory);
-            } else {
-                return new ScalarRowReader<Object>(descriptor, (ScalarResultSegment) segment);
-            }
-        } else {
-            CompoundRowReader reader = new CompoundRowReader(resultWidth);
-
-            for (int i = 0; i < resultWidth; i++) {
-                Object segment = rsMapping.get(i);
-
-                if (segment instanceof EntityResultSegment) {
-                    reader.addRowReader(
-                            i,
-                            createEntityRowReader(descriptor, queryMetadata, (EntityResultSegment) segment,
-                                    postProcessorFactory));
-                } else {
-                    reader.addRowReader(i, new ScalarRowReader<Object>(descriptor, (ScalarResultSegment) segment));
-                }
-            }
-
-            return reader;
-        }
-    }
-
-    private RowReader<?> createEntityRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
-            EntityResultSegment resultMetadata, PostprocessorFactory postProcessorFactory) {
-
-        if (queryMetadata.getPageSize() > 0) {
-            return new IdRowReader<Object>(descriptor, queryMetadata, postProcessorFactory.get());
-        } else if (resultMetadata.getClassDescriptor() != null && resultMetadata.getClassDescriptor().hasSubclasses()) {
-            return new InheritanceAwareEntityRowReader(descriptor, resultMetadata, postProcessorFactory.get());
-        } else {
-            return new EntityRowReader(descriptor, resultMetadata, postProcessorFactory.get());
-        }
-    }
-
-    private RowReader<?> createFullRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
-            PostprocessorFactory postProcessorFactory) {
-
-        if (queryMetadata.getPageSize() > 0) {
-            return new IdRowReader<Object>(descriptor, queryMetadata, postProcessorFactory.get());
-        } else if (queryMetadata.getClassDescriptor() != null && queryMetadata.getClassDescriptor().hasSubclasses()) {
-            return new InheritanceAwareRowReader(descriptor, queryMetadata, postProcessorFactory.get());
-        } else {
-            return new FullRowReader(descriptor, queryMetadata, postProcessorFactory.get());
-        }
-    }
-
-    private class PostprocessorFactory {
-
-        private QueryMetadata queryMetadata;
-        private ExtendedTypeMap extendedTypes;
-        private Map<ObjAttribute, ColumnDescriptor> attributeOverrides;
-        private RowDescriptor rowDescriptor;
-
-        private boolean created;
-        private DataRowPostProcessor postProcessor;
-
-        PostprocessorFactory(RowDescriptor rowDescriptor, QueryMetadata queryMetadata, ExtendedTypeMap extendedTypes,
-                Map<ObjAttribute, ColumnDescriptor> attributeOverrides) {
-            this.rowDescriptor = rowDescriptor;
-            this.extendedTypes = extendedTypes;
-            this.attributeOverrides = attributeOverrides;
-            this.queryMetadata = queryMetadata;
-        }
-
-        DataRowPostProcessor get() {
-
-            if (!created) {
-                postProcessor = create();
-                created = true;
-            }
-
-            return postProcessor;
-        }
-
-        private DataRowPostProcessor create() {
-
-            if (attributeOverrides.isEmpty()) {
-                return null;
-            }
-
-            ColumnDescriptor[] columns = rowDescriptor.getColumns();
-
-            Map<String, Collection<ColumnOverride>> columnOverrides = new HashMap<String, Collection<ColumnOverride>>(2);
-
-            for (Entry<ObjAttribute, ColumnDescriptor> entry : attributeOverrides.entrySet()) {
-
-                ObjAttribute attribute = entry.getKey();
-                Entity entity = attribute.getEntity();
-
-                String key = null;
-                int jdbcType = TypesMapping.NOT_DEFINED;
-                int index = -1;
-                for (int i = 0; i < columns.length; i++) {
-                    if (columns[i] == entry.getValue()) {
-
-                        // if attribute type is the same as column, there is no
-                        // conflict
-                        if (!attribute.getType().equals(columns[i].getJavaClass())) {
-                            // note that JDBC index is "1" based
-                            index = i + 1;
-                            jdbcType = columns[i].getJdbcType();
-                            key = columns[i].getDataRowKey();
-                        }
-
-                        break;
-                    }
-                }
-
-                if (index < 1) {
-                    continue;
-                }
-
-                ExtendedType converter = extendedTypes.getRegisteredType(attribute.getType());
-
-                Collection<ColumnOverride> overrides = columnOverrides.get(entity.getName());
+	@Override
+	public RowReader<?> rowReader(RowDescriptor descriptor, QueryMetadata queryMetadata, DbAdapter adapter,
+			Map<ObjAttribute, ColumnDescriptor> attributeOverrides) {
+
+		PostprocessorFactory postProcessorFactory = new PostprocessorFactory(descriptor, queryMetadata,
+				adapter.getExtendedTypes(), attributeOverrides);
+
+		List<Object> rsMapping = queryMetadata.getResultSetMapping();
+		if (rsMapping == null) {
+			return createFullRowReader(descriptor, queryMetadata, postProcessorFactory);
+		}
+
+		int resultWidth = rsMapping.size();
+		if (resultWidth == 0) {
+			throw new CayenneRuntimeException("Empty result descriptor");
+		} else if (resultWidth == 1) {
+
+			Object segment = rsMapping.get(0);
+
+			if (segment instanceof EntityResultSegment) {
+				return createEntityRowReader(descriptor, queryMetadata, (EntityResultSegment) segment,
+						postProcessorFactory);
+			} else {
+				return new ScalarRowReader<Object>(descriptor, (ScalarResultSegment) segment);
+			}
+		} else {
+			CompoundRowReader reader = new CompoundRowReader(resultWidth);
+
+			for (int i = 0; i < resultWidth; i++) {
+				Object segment = rsMapping.get(i);
+
+				if (segment instanceof EntityResultSegment) {
+					reader.addRowReader(
+							i,
+							createEntityRowReader(descriptor, queryMetadata, (EntityResultSegment) segment,
+									postProcessorFactory));
+				} else {
+					reader.addRowReader(i, new ScalarRowReader<Object>(descriptor, (ScalarResultSegment) segment));
+				}
+			}
+
+			return reader;
+		}
+	}
+
+	private RowReader<?> createEntityRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
+			EntityResultSegment resultMetadata, PostprocessorFactory postProcessorFactory) {
+
+		if (queryMetadata.getPageSize() > 0) {
+			return new IdRowReader<Object>(descriptor, queryMetadata, postProcessorFactory.get());
+		} else if (resultMetadata.getClassDescriptor() != null && resultMetadata.getClassDescriptor().hasSubclasses()) {
+			return new InheritanceAwareEntityRowReader(descriptor, resultMetadata, postProcessorFactory.get());
+		} else {
+			return new EntityRowReader(descriptor, resultMetadata, postProcessorFactory.get());
+		}
+	}
+
+	private RowReader<?> createFullRowReader(RowDescriptor descriptor, QueryMetadata queryMetadata,
+			PostprocessorFactory postProcessorFactory) {
+
+		if (queryMetadata.getPageSize() > 0) {
+			return new IdRowReader<Object>(descriptor, queryMetadata, postProcessorFactory.get());
+		} else if (queryMetadata.getClassDescriptor() != null && queryMetadata.getClassDescriptor().hasSubclasses()) {
+			return new InheritanceAwareRowReader(descriptor, queryMetadata, postProcessorFactory.get());
+		} else {
+			return new FullRowReader(descriptor, queryMetadata, postProcessorFactory.get());
+		}
+	}
+
+	private class PostprocessorFactory {
+
+		private QueryMetadata queryMetadata;
+		private ExtendedTypeMap extendedTypes;
+		private Map<ObjAttribute, ColumnDescriptor> attributeOverrides;
+		private RowDescriptor rowDescriptor;
+
+		private boolean created;
+		private DataRowPostProcessor postProcessor;
+
+		PostprocessorFactory(RowDescriptor rowDescriptor, QueryMetadata queryMetadata, ExtendedTypeMap extendedTypes,
+				Map<ObjAttribute, ColumnDescriptor> attributeOverrides) {
+			this.rowDescriptor = rowDescriptor;
+			this.extendedTypes = extendedTypes;
+			this.attributeOverrides = attributeOverrides;
+			this.queryMetadata = queryMetadata;
+		}
+
+		DataRowPostProcessor get() {
+
+			if (!created) {
+				postProcessor = create();
+				created = true;
+			}
+
+			return postProcessor;
+		}
+
+		private DataRowPostProcessor create() {
+
+			if (attributeOverrides.isEmpty()) {
+				return null;
+			}
+
+			ColumnDescriptor[] columns = rowDescriptor.getColumns();
+
+			Map<String, Collection<ColumnOverride>> columnOverrides = new HashMap<>(2);
+
+			for (Entry<ObjAttribute, ColumnDescriptor> entry : attributeOverrides.entrySet()) {
+
+				ObjAttribute attribute = entry.getKey();
+				Entity entity = attribute.getEntity();
+
+				String key = null;
+				int jdbcType = TypesMapping.NOT_DEFINED;
+				int index = -1;
+				for (int i = 0; i < columns.length; i++) {
+					if (columns[i] == entry.getValue()) {
+
+						// if attribute type is the same as column, there is no
+						// conflict
+						if (!attribute.getType().equals(columns[i].getJavaClass())) {
+							// note that JDBC index is "1" based
+							index = i + 1;
+							jdbcType = columns[i].getJdbcType();
+							key = columns[i].getDataRowKey();
+						}
+
+						break;
+					}
+				}
+
+				if (index < 1) {
+					continue;
+				}
+
+				ExtendedType converter = extendedTypes.getRegisteredType(attribute.getType());
+
+				Collection<ColumnOverride> overrides = columnOverrides.get(entity.getName());
 
-                if (overrides == null) {
-                    overrides = new ArrayList<ColumnOverride>(3);
-                    columnOverrides.put(entity.getName(), overrides);
-                }
+				if (overrides == null) {
+					overrides = new ArrayList<ColumnOverride>(3);
+					columnOverrides.put(entity.getName(), overrides);
+				}
 
-                overrides.add(new ColumnOverride(index, key, converter, jdbcType));
-            }
+				overrides.add(new ColumnOverride(index, key, converter, jdbcType));
+			}
 
-            // inject null post-processor
-            if (columnOverrides.isEmpty()) {
-                return null;
-            }
+			// inject null post-processor
+			if (columnOverrides.isEmpty()) {
+				return null;
+			}
 
-            ClassDescriptor rootDescriptor = queryMetadata.getClassDescriptor();
+			ClassDescriptor rootDescriptor = queryMetadata.getClassDescriptor();
 
-            return new DataRowPostProcessor(rootDescriptor, columnOverrides);
-        }
-    }
+			return new DataRowPostProcessor(rootDescriptor, columnOverrides);
+		}
+	}
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesPerSchemaLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesPerSchemaLoader.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesPerSchemaLoader.java
index 769255f..058494e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesPerSchemaLoader.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesPerSchemaLoader.java
@@ -18,16 +18,21 @@
  ****************************************************************/
 package org.apache.cayenne.access.loader;
 
-import org.apache.cayenne.access.loader.filters.PatternFilter;
-import org.apache.cayenne.access.loader.filters.TableFilter;
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.map.DbAttribute;
-
 import java.sql.DatabaseMetaData;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
-import java.util.*;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cayenne.access.loader.filters.PatternFilter;
+import org.apache.cayenne.access.loader.filters.TableFilter;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.map.DbAttribute;
 
 /**
  * Load all attributes for schema and return it for each table
@@ -46,7 +51,7 @@ public class DbAttributesPerSchemaLoader extends DbAttributesBaseLoader {
 	}
 
 	private Map<String, List<DbAttribute>> loadDbAttributes() throws SQLException {
-		Map<String, List<DbAttribute>> attributes = new HashMap<String, List<DbAttribute>>();
+		Map<String, List<DbAttribute>> attributes = new HashMap<>();
 
 		try (ResultSet rs = getMetaData().getColumns(getCatalog(), getSchema(), "%", "%");) {
 			Set<String> columns = new HashSet<String>();
@@ -114,7 +119,7 @@ public class DbAttributesPerSchemaLoader extends DbAttributesBaseLoader {
 				attributes = loadDbAttributes();
 			} catch (SQLException e) {
 				LOGGER.error(e);
-				attributes = new HashMap<String, List<DbAttribute>>();
+				attributes = new HashMap<>();
 			}
 		}
 		return attributes;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DefaultJdbc2JavaTypeMapper.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DefaultJdbc2JavaTypeMapper.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DefaultJdbc2JavaTypeMapper.java
index 9380050..de9e02d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DefaultJdbc2JavaTypeMapper.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/mapper/DefaultJdbc2JavaTypeMapper.java
@@ -36,252 +36,247 @@ import java.util.TreeSet;
  */
 public class DefaultJdbc2JavaTypeMapper implements Jdbc2JavaTypeMapper {
 
-    // Never use "-1" or any other normal integer, since there
-    // is a big chance it is being reserved in java.sql.Types
-    public static final int NOT_DEFINED = Integer.MAX_VALUE;
-
-    // char constants for Java data types
-    public static final String JAVA_LONG = "java.lang.Long";
-    public static final String JAVA_BYTES = "byte[]";
-    public static final String JAVA_BOOLEAN = "java.lang.Boolean";
-    public static final String JAVA_STRING = "java.lang.String";
-    public static final String JAVA_SQLDATE = "java.sql.Date";
-    public static final String JAVA_UTILDATE = "java.util.Date";
-    public static final String JAVA_BIGDECIMAL = "java.math.BigDecimal";
-    public static final String JAVA_DOUBLE = "java.lang.Double";
-    public static final String JAVA_FLOAT = "java.lang.Float";
-    public static final String JAVA_INTEGER = "java.lang.Integer";
-    public static final String JAVA_SHORT = "java.lang.Short";
-    public static final String JAVA_BYTE = "java.lang.Byte";
-    public static final String JAVA_TIME = "java.sql.Time";
-    public static final String JAVA_TIMESTAMP = "java.sql.Timestamp";
-    public static final String JAVA_BLOB = "java.sql.Blob";
-
-    /**
-     * Keys: java class names, Values: SQL int type definitions from java.sql.Types
-     */
-    private final Map<String, Integer> javaSqlEnum = new HashMap<String, Integer>();
-
-    private final Map<DbType, String> mapping = new HashMap<DbType, String>();
-    private final SortedSet<DbType> dbTypes = new TreeSet<DbType>();
-
-    private Map<String, String> classToPrimitive;
-
-    {
-        add(Types.BIGINT, JAVA_LONG);
-        add(Types.BINARY, JAVA_BYTES);
-        add(Types.BIT, JAVA_BOOLEAN);
-        add(Types.BOOLEAN, JAVA_BOOLEAN);
-        add(Types.BLOB, JAVA_BYTES);
-        add(Types.CLOB, JAVA_STRING);
-        add(Types.NCLOB, JAVA_STRING);
-        add(Types.SQLXML, JAVA_STRING);
-        add(Types.CHAR, JAVA_STRING);
-        add(Types.NCHAR, JAVA_STRING);
-        add(Types.DATE, JAVA_UTILDATE);
-        add(Types.DECIMAL, JAVA_BIGDECIMAL);
-        add(Types.DOUBLE, JAVA_DOUBLE);
-        add(Types.FLOAT, JAVA_FLOAT);
-        add(Types.INTEGER, JAVA_INTEGER);
-        add(Types.LONGVARCHAR, JAVA_STRING);
-        add(Types.LONGNVARCHAR, JAVA_STRING);
-        add(Types.LONGVARBINARY, JAVA_BYTES);
-        add(Types.NUMERIC, JAVA_BIGDECIMAL);
-        add(Types.REAL, JAVA_FLOAT);
-        add(Types.SMALLINT, JAVA_SHORT);
-        add(Types.TINYINT, JAVA_SHORT);
-        add(Types.TIME, JAVA_UTILDATE);
-        add(Types.TIMESTAMP, JAVA_UTILDATE);
-        add(Types.VARBINARY, JAVA_BYTES);
-        add(Types.VARCHAR, JAVA_STRING);
-        add(Types.NVARCHAR, JAVA_STRING);
-
-        javaSqlEnum.put(JAVA_LONG, Types.BIGINT);
-        javaSqlEnum.put(JAVA_BYTES, Types.BINARY);
-        javaSqlEnum.put(JAVA_BOOLEAN, Types.BIT);
-        javaSqlEnum.put(JAVA_STRING, Types.VARCHAR);
-        javaSqlEnum.put(JAVA_SQLDATE, Types.DATE);
-        javaSqlEnum.put(JAVA_UTILDATE, Types.DATE);
-        javaSqlEnum.put(JAVA_TIMESTAMP, Types.TIMESTAMP);
-        javaSqlEnum.put(JAVA_BIGDECIMAL, Types.DECIMAL);
-        javaSqlEnum.put(JAVA_DOUBLE, Types.DOUBLE);
-        javaSqlEnum.put(JAVA_FLOAT, Types.FLOAT);
-        javaSqlEnum.put(JAVA_INTEGER, Types.INTEGER);
-        javaSqlEnum.put(JAVA_SHORT, Types.SMALLINT);
-        javaSqlEnum.put(JAVA_BYTE, Types.SMALLINT);
-        javaSqlEnum.put(JAVA_TIME, Types.TIME);
-        javaSqlEnum.put(JAVA_TIMESTAMP, Types.TIMESTAMP);
-
-        // add primitives
-        javaSqlEnum.put("byte", Types.TINYINT);
-        javaSqlEnum.put("int", Types.INTEGER);
-        javaSqlEnum.put("short", Types.SMALLINT);
-        javaSqlEnum.put("char", Types.CHAR);
-        javaSqlEnum.put("double", Types.DOUBLE);
-        javaSqlEnum.put("long", Types.BIGINT);
-        javaSqlEnum.put("float", Types.FLOAT);
-        javaSqlEnum.put("boolean", Types.BIT);
-
-        classToPrimitive = new HashMap<String, String>();
-        classToPrimitive.put(Byte.class.getName(), "byte");
-        classToPrimitive.put(Long.class.getName(), "long");
-        classToPrimitive.put(Double.class.getName(), "double");
-        classToPrimitive.put(Boolean.class.getName(), "boolean");
-        classToPrimitive.put(Float.class.getName(), "float");
-        classToPrimitive.put(Short.class.getName(), "short");
-        classToPrimitive.put(Integer.class.getName(), "int");
-    }
-
-    private Boolean usePrimitives;
-
-
-    /**
-     * Returns default java.sql.Types type by the Java type name.
-     *
-     * @param className Fully qualified Java Class name.
-     * @return The SQL type or NOT_DEFINED if no type found.
-     */
-    public int getJdbcTypeByJava(DbAttribute attribute, String className) {
-        if (className == null) {
-            return NOT_DEFINED;
-        }
-
-        Integer type = javaSqlEnum.get(className);
-        if (type != null) {
-            return type;
-        }
-
-        // try to load a Java class - some nonstandard mappings may work
-        try {
-            return getSqlTypeByJava(attribute, Util.getJavaClass(className));
-        } catch (Throwable th) {
-            return NOT_DEFINED;
-        }
-    }
-
-
-    public void add(int jdbcType, String java) {
-        add(new DbType(TypesMapping.getSqlNameByType(jdbcType)), java);
-    }
-
-    @Override
-    public void add(DbType type, String java) {
-        mapping.put(type, java);
-        dbTypes.add(type);
-    }
-
-    /**
-     * Guesses a default JDBC type for the Java class.
-     *
-     * @since 1.1
-     */
-    protected int getSqlTypeByJava(DbAttribute attribute, Class<?> javaClass) {
-        if (javaClass == null) {
-            return NOT_DEFINED;
-        }
-
-        // check standard mapping of class and superclasses
-        Class<?> aClass = javaClass;
-        while (aClass != null) {
-
-            String name;
-
-            if (aClass.isArray()) {
-                name = aClass.getComponentType().getName() + "[]";
-            }  else {
-                name = aClass.getName();
-            }
-
-            Object type = javaSqlEnum.get(name);
-            if (type != null) {
-                return ((Number) type).intValue();
-            }
-
-            aClass = aClass.getSuperclass();
-        }
-
-        // check non-standard JDBC types that are still supported by JPA
-        if (javaClass.isArray()) {
-
-            Class<?> elementType = javaClass.getComponentType();
-            if (Character.class.isAssignableFrom(elementType)
-                    || Character.TYPE.isAssignableFrom(elementType)) {
-                return Types.VARCHAR;
-            }
-            else if (Byte.class.isAssignableFrom(elementType)
-                    || Byte.TYPE.isAssignableFrom(elementType)) {
-                return Types.VARBINARY;
-            }
-        }
-
-        if (Calendar.class.isAssignableFrom(javaClass)) {
-            return Types.TIMESTAMP;
-        }
-
-        if (BigInteger.class.isAssignableFrom(javaClass)) {
-            return Types.BIGINT;
-        }
-
-        if (Serializable.class.isAssignableFrom(javaClass)) {
-            // serializable check should be the last one when all other mapping attempts failed
-            return Types.VARBINARY;
-        }
-
-        return NOT_DEFINED;
-    }
-
-    /**
-     * Get the corresponding Java type by its java.sql.Types counterpart. Note that this
-     * method should be used as a last resort, with explicit mapping provided by user used
-     * as a first choice, as it can only guess how to map certain types, such as NUMERIC,
-     * etc.
-     *
-     * @return Fully qualified Java type name or null if not found.
-     */
-    @Override
-    public String getJavaByJdbcType(DbAttribute attribute, int type) {
-        String jdbcType = TypesMapping.getSqlNameByType(type);
-        DbType dbType;
-        if (attribute != null) {
-            dbType = new DbType(
-                    jdbcType,
-                    attribute.getMaxLength(),
-                    attribute.getAttributePrecision(),
-                    attribute.getScale(),
-                    attribute.isMandatory());
-        } else {
-            dbType = new DbType(jdbcType);
-        }
-
-        String typeName = getJavaByJdbcType(dbType);
-
-        if (usePrimitives != null && usePrimitives) {
-            String primitive = classToPrimitive.get(typeName);
-            if (primitive != null) {
-                return primitive;
-            }
-        }
-
-        return typeName;
-    }
-
-    public String getJavaByJdbcType(DbType type) {
-        for (DbType t : dbTypes) {
-            if (t.isCover(type)) {
-                // because dbTypes sorted by specificity we will take first and the most specific matching
-                // that applicable for attribute
-                return mapping.get(t);
-            }
-        }
-
-        return null;
-    }
-
-    public Boolean getUsePrimitives() {
-        return usePrimitives;
-    }
-
-    public void setUsePrimitives(Boolean usePrimitives) {
-        this.usePrimitives = usePrimitives;
-    }
+	// Never use "-1" or any other normal integer, since there
+	// is a big chance it is being reserved in java.sql.Types
+	public static final int NOT_DEFINED = Integer.MAX_VALUE;
+
+	// char constants for Java data types
+	public static final String JAVA_LONG = "java.lang.Long";
+	public static final String JAVA_BYTES = "byte[]";
+	public static final String JAVA_BOOLEAN = "java.lang.Boolean";
+	public static final String JAVA_STRING = "java.lang.String";
+	public static final String JAVA_SQLDATE = "java.sql.Date";
+	public static final String JAVA_UTILDATE = "java.util.Date";
+	public static final String JAVA_BIGDECIMAL = "java.math.BigDecimal";
+	public static final String JAVA_DOUBLE = "java.lang.Double";
+	public static final String JAVA_FLOAT = "java.lang.Float";
+	public static final String JAVA_INTEGER = "java.lang.Integer";
+	public static final String JAVA_SHORT = "java.lang.Short";
+	public static final String JAVA_BYTE = "java.lang.Byte";
+	public static final String JAVA_TIME = "java.sql.Time";
+	public static final String JAVA_TIMESTAMP = "java.sql.Timestamp";
+	public static final String JAVA_BLOB = "java.sql.Blob";
+
+	/**
+	 * Keys: java class names, Values: SQL int type definitions from
+	 * java.sql.Types
+	 */
+	private final Map<String, Integer> javaSqlEnum = new HashMap<>();
+
+	private final Map<DbType, String> mapping = new HashMap<>();
+	private final SortedSet<DbType> dbTypes = new TreeSet<>();
+
+	private Map<String, String> classToPrimitive;
+
+	{
+		add(Types.BIGINT, JAVA_LONG);
+		add(Types.BINARY, JAVA_BYTES);
+		add(Types.BIT, JAVA_BOOLEAN);
+		add(Types.BOOLEAN, JAVA_BOOLEAN);
+		add(Types.BLOB, JAVA_BYTES);
+		add(Types.CLOB, JAVA_STRING);
+		add(Types.NCLOB, JAVA_STRING);
+		add(Types.SQLXML, JAVA_STRING);
+		add(Types.CHAR, JAVA_STRING);
+		add(Types.NCHAR, JAVA_STRING);
+		add(Types.DATE, JAVA_UTILDATE);
+		add(Types.DECIMAL, JAVA_BIGDECIMAL);
+		add(Types.DOUBLE, JAVA_DOUBLE);
+		add(Types.FLOAT, JAVA_FLOAT);
+		add(Types.INTEGER, JAVA_INTEGER);
+		add(Types.LONGVARCHAR, JAVA_STRING);
+		add(Types.LONGNVARCHAR, JAVA_STRING);
+		add(Types.LONGVARBINARY, JAVA_BYTES);
+		add(Types.NUMERIC, JAVA_BIGDECIMAL);
+		add(Types.REAL, JAVA_FLOAT);
+		add(Types.SMALLINT, JAVA_SHORT);
+		add(Types.TINYINT, JAVA_SHORT);
+		add(Types.TIME, JAVA_UTILDATE);
+		add(Types.TIMESTAMP, JAVA_UTILDATE);
+		add(Types.VARBINARY, JAVA_BYTES);
+		add(Types.VARCHAR, JAVA_STRING);
+		add(Types.NVARCHAR, JAVA_STRING);
+
+		javaSqlEnum.put(JAVA_LONG, Types.BIGINT);
+		javaSqlEnum.put(JAVA_BYTES, Types.BINARY);
+		javaSqlEnum.put(JAVA_BOOLEAN, Types.BIT);
+		javaSqlEnum.put(JAVA_STRING, Types.VARCHAR);
+		javaSqlEnum.put(JAVA_SQLDATE, Types.DATE);
+		javaSqlEnum.put(JAVA_UTILDATE, Types.DATE);
+		javaSqlEnum.put(JAVA_TIMESTAMP, Types.TIMESTAMP);
+		javaSqlEnum.put(JAVA_BIGDECIMAL, Types.DECIMAL);
+		javaSqlEnum.put(JAVA_DOUBLE, Types.DOUBLE);
+		javaSqlEnum.put(JAVA_FLOAT, Types.FLOAT);
+		javaSqlEnum.put(JAVA_INTEGER, Types.INTEGER);
+		javaSqlEnum.put(JAVA_SHORT, Types.SMALLINT);
+		javaSqlEnum.put(JAVA_BYTE, Types.SMALLINT);
+		javaSqlEnum.put(JAVA_TIME, Types.TIME);
+		javaSqlEnum.put(JAVA_TIMESTAMP, Types.TIMESTAMP);
+
+		// add primitives
+		javaSqlEnum.put("byte", Types.TINYINT);
+		javaSqlEnum.put("int", Types.INTEGER);
+		javaSqlEnum.put("short", Types.SMALLINT);
+		javaSqlEnum.put("char", Types.CHAR);
+		javaSqlEnum.put("double", Types.DOUBLE);
+		javaSqlEnum.put("long", Types.BIGINT);
+		javaSqlEnum.put("float", Types.FLOAT);
+		javaSqlEnum.put("boolean", Types.BIT);
+
+		classToPrimitive = new HashMap<>();
+		classToPrimitive.put(Byte.class.getName(), "byte");
+		classToPrimitive.put(Long.class.getName(), "long");
+		classToPrimitive.put(Double.class.getName(), "double");
+		classToPrimitive.put(Boolean.class.getName(), "boolean");
+		classToPrimitive.put(Float.class.getName(), "float");
+		classToPrimitive.put(Short.class.getName(), "short");
+		classToPrimitive.put(Integer.class.getName(), "int");
+	}
+
+	private Boolean usePrimitives;
+
+	/**
+	 * Returns default java.sql.Types type by the Java type name.
+	 *
+	 * @param className
+	 *            Fully qualified Java Class name.
+	 * @return The SQL type or NOT_DEFINED if no type found.
+	 */
+	public int getJdbcTypeByJava(DbAttribute attribute, String className) {
+		if (className == null) {
+			return NOT_DEFINED;
+		}
+
+		Integer type = javaSqlEnum.get(className);
+		if (type != null) {
+			return type;
+		}
+
+		// try to load a Java class - some nonstandard mappings may work
+		try {
+			return getSqlTypeByJava(attribute, Util.getJavaClass(className));
+		} catch (Throwable th) {
+			return NOT_DEFINED;
+		}
+	}
+
+	public void add(int jdbcType, String java) {
+		add(new DbType(TypesMapping.getSqlNameByType(jdbcType)), java);
+	}
+
+	@Override
+	public void add(DbType type, String java) {
+		mapping.put(type, java);
+		dbTypes.add(type);
+	}
+
+	/**
+	 * Guesses a default JDBC type for the Java class.
+	 *
+	 * @since 1.1
+	 */
+	protected int getSqlTypeByJava(DbAttribute attribute, Class<?> javaClass) {
+		if (javaClass == null) {
+			return NOT_DEFINED;
+		}
+
+		// check standard mapping of class and superclasses
+		Class<?> aClass = javaClass;
+		while (aClass != null) {
+
+			String name;
+
+			if (aClass.isArray()) {
+				name = aClass.getComponentType().getName() + "[]";
+			} else {
+				name = aClass.getName();
+			}
+
+			Object type = javaSqlEnum.get(name);
+			if (type != null) {
+				return ((Number) type).intValue();
+			}
+
+			aClass = aClass.getSuperclass();
+		}
+
+		// check non-standard JDBC types that are still supported by JPA
+		if (javaClass.isArray()) {
+
+			Class<?> elementType = javaClass.getComponentType();
+			if (Character.class.isAssignableFrom(elementType) || Character.TYPE.isAssignableFrom(elementType)) {
+				return Types.VARCHAR;
+			} else if (Byte.class.isAssignableFrom(elementType) || Byte.TYPE.isAssignableFrom(elementType)) {
+				return Types.VARBINARY;
+			}
+		}
+
+		if (Calendar.class.isAssignableFrom(javaClass)) {
+			return Types.TIMESTAMP;
+		}
+
+		if (BigInteger.class.isAssignableFrom(javaClass)) {
+			return Types.BIGINT;
+		}
+
+		if (Serializable.class.isAssignableFrom(javaClass)) {
+			// serializable check should be the last one when all other mapping
+			// attempts failed
+			return Types.VARBINARY;
+		}
+
+		return NOT_DEFINED;
+	}
+
+	/**
+	 * Get the corresponding Java type by its java.sql.Types counterpart. Note
+	 * that this method should be used as a last resort, with explicit mapping
+	 * provided by user used as a first choice, as it can only guess how to map
+	 * certain types, such as NUMERIC, etc.
+	 *
+	 * @return Fully qualified Java type name or null if not found.
+	 */
+	@Override
+	public String getJavaByJdbcType(DbAttribute attribute, int type) {
+		String jdbcType = TypesMapping.getSqlNameByType(type);
+		DbType dbType;
+		if (attribute != null) {
+			dbType = new DbType(jdbcType, attribute.getMaxLength(), attribute.getAttributePrecision(),
+					attribute.getScale(), attribute.isMandatory());
+		} else {
+			dbType = new DbType(jdbcType);
+		}
+
+		String typeName = getJavaByJdbcType(dbType);
+
+		if (usePrimitives != null && usePrimitives) {
+			String primitive = classToPrimitive.get(typeName);
+			if (primitive != null) {
+				return primitive;
+			}
+		}
+
+		return typeName;
+	}
+
+	public String getJavaByJdbcType(DbType type) {
+		for (DbType t : dbTypes) {
+			if (t.isCover(type)) {
+				// because dbTypes sorted by specificity we will take first and
+				// the most specific matching
+				// that applicable for attribute
+				return mapping.get(t);
+			}
+		}
+
+		return null;
+	}
+
+	public Boolean getUsePrimitives() {
+		return usePrimitives;
+	}
+
+	public void setUsePrimitives(Boolean usePrimitives) {
+		this.usePrimitives = usePrimitives;
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLDbPathTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLDbPathTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLDbPathTranslator.java
index 74e0865..8f1038c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLDbPathTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLDbPathTranslator.java
@@ -35,204 +35,204 @@ import org.apache.cayenne.reflect.ClassDescriptor;
 
 public abstract class EJBQLDbPathTranslator extends EJBQLBaseVisitor {
 
-    private EJBQLTranslationContext context;
-    protected DbEntity currentEntity;
-    private String lastPathComponent;
-    protected String lastAlias;
-    protected String idPath;
-    protected String joinMarker;
-    private String fullPath;
-    private boolean usingAliases;
-
-    public EJBQLDbPathTranslator(EJBQLTranslationContext context) {
-        super(true);
-        this.context = context;
-        this.usingAliases = true;
-    }
-
-    protected abstract void appendMultiColumnPath(EJBQLMultiColumnOperand operand);
-
-    @Override
-    public boolean visitDbPath(EJBQLExpression expression, int finishedChildIndex) {
-        if (finishedChildIndex > 0) {
-
-            if (finishedChildIndex + 1 < expression.getChildrenCount()) {
-                processIntermediatePathComponent();
-            } else {
-                processLastPathComponent();
-            }
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean visitIdentifier(EJBQLExpression expression) {
-
-        // expression id is always rooted in an ObjEntity, even for DbPath...
-        ClassDescriptor descriptor = context.getEntityDescriptor(expression.getText());
-        if (descriptor == null) {
-            throw new EJBQLException("Invalid identification variable: " + expression.getText());
-        }
-
-        this.currentEntity = descriptor.getEntity().getDbEntity();
-        this.idPath = expression.getText();
-        this.joinMarker = EJBQLJoinAppender.makeJoinTailMarker(idPath);
-        this.fullPath = idPath;
-        return true;
-    }
-
-    @Override
-    public boolean visitIdentificationVariable(EJBQLExpression expression) {
-
-        // TODO: andrus 6/11/2007 - if the path ends with relationship, the last
-        // join will
-        // get lost...
-        if (lastPathComponent != null) {
-            resolveJoin(true);
-        }
-
-        this.lastPathComponent = expression.getText();
-        return true;
-    }
-
-    private void resolveJoin(boolean inner) {
-
-        EJBQLJoinAppender joinAppender = context.getTranslatorFactory().getJoinAppender(context);
-
-        // TODO: andrus 1/6/2007 - conflict with object path naming... maybe
-        // 'registerReusableJoin' should normalize everything to a db path?
-        String newPath = idPath + '.' + lastPathComponent;
-        String oldPath = joinAppender.registerReusableJoin(idPath, lastPathComponent, newPath);
-
-        this.fullPath = fullPath + '.' + lastPathComponent;
-
-        if (oldPath != null) {
-            this.idPath = oldPath;
-            this.lastAlias = context.getTableAlias(oldPath,
-                    context.getQuotingStrategy().quotedFullyQualifiedName(currentEntity));
-        } else {
-
-            // register join
-            if (inner) {
-                joinAppender.appendInnerJoin(joinMarker, new EJBQLTableId(idPath), new EJBQLTableId(fullPath));
-                this.lastAlias = context.getTableAlias(fullPath,
-                        context.getQuotingStrategy().quotedFullyQualifiedName(currentEntity));
-            } else {
-                joinAppender.appendOuterJoin(joinMarker, new EJBQLTableId(idPath), new EJBQLTableId(fullPath));
-
-                Relationship lastRelationship = currentEntity.getRelationship(lastPathComponent);
-                DbEntity targetEntity = (DbEntity) lastRelationship.getTargetEntity();
-
-                this.lastAlias = context.getTableAlias(fullPath,
-                        context.getQuotingStrategy().quotedFullyQualifiedName(targetEntity));
-            }
-
-            this.idPath = newPath;
-        }
-    }
-
-    private void processIntermediatePathComponent() {
-        DbRelationship relationship = currentEntity.getRelationship(lastPathComponent);
-        if (relationship == null) {
-            throw new EJBQLException("Unknown relationship '" + lastPathComponent + "' for entity '"
-                    + currentEntity.getName() + "'");
-        }
-
-        this.currentEntity = (DbEntity) relationship.getTargetEntity();
-    }
-
-    private void processLastPathComponent() {
-
-        DbAttribute attribute = currentEntity.getAttribute(lastPathComponent);
-
-        if (attribute != null) {
-            processTerminatingAttribute(attribute);
-            return;
-        }
-
-        DbRelationship relationship = currentEntity.getRelationship(lastPathComponent);
-        if (relationship != null) {
-            processTerminatingRelationship(relationship);
-            return;
-        }
-
-        throw new IllegalStateException("Invalid path component: " + lastPathComponent);
-    }
-
-    protected void processTerminatingAttribute(DbAttribute attribute) {
-
-        DbEntity table = (DbEntity) attribute.getEntity();
-
-        if (isUsingAliases()) {
-            String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
-                    .getQuotingStrategy().quotedFullyQualifiedName(table));
-            context.append(' ').append(alias).append('.').append(context.getQuotingStrategy().quotedName(attribute));
-        } else {
-            context.append(' ').append(context.getQuotingStrategy().quotedName(attribute));
-        }
-    }
-
-    private void processTerminatingRelationship(DbRelationship relationship) {
-
-        if (relationship.isToMany()) {
-
-            // use an outer join for to-many matches
-            resolveJoin(false);
-
-            DbEntity table = (DbEntity) relationship.getTargetEntity();
+	private EJBQLTranslationContext context;
+	protected DbEntity currentEntity;
+	private String lastPathComponent;
+	protected String lastAlias;
+	protected String idPath;
+	protected String joinMarker;
+	private String fullPath;
+	private boolean usingAliases;
+
+	public EJBQLDbPathTranslator(EJBQLTranslationContext context) {
+		super(true);
+		this.context = context;
+		this.usingAliases = true;
+	}
+
+	protected abstract void appendMultiColumnPath(EJBQLMultiColumnOperand operand);
+
+	@Override
+	public boolean visitDbPath(EJBQLExpression expression, int finishedChildIndex) {
+		if (finishedChildIndex > 0) {
+
+			if (finishedChildIndex + 1 < expression.getChildrenCount()) {
+				processIntermediatePathComponent();
+			} else {
+				processLastPathComponent();
+			}
+		}
+
+		return true;
+	}
+
+	@Override
+	public boolean visitIdentifier(EJBQLExpression expression) {
+
+		// expression id is always rooted in an ObjEntity, even for DbPath...
+		ClassDescriptor descriptor = context.getEntityDescriptor(expression.getText());
+		if (descriptor == null) {
+			throw new EJBQLException("Invalid identification variable: " + expression.getText());
+		}
+
+		this.currentEntity = descriptor.getEntity().getDbEntity();
+		this.idPath = expression.getText();
+		this.joinMarker = EJBQLJoinAppender.makeJoinTailMarker(idPath);
+		this.fullPath = idPath;
+		return true;
+	}
+
+	@Override
+	public boolean visitIdentificationVariable(EJBQLExpression expression) {
+
+		// TODO: andrus 6/11/2007 - if the path ends with relationship, the last
+		// join will
+		// get lost...
+		if (lastPathComponent != null) {
+			resolveJoin(true);
+		}
+
+		this.lastPathComponent = expression.getText();
+		return true;
+	}
+
+	private void resolveJoin(boolean inner) {
+
+		EJBQLJoinAppender joinAppender = context.getTranslatorFactory().getJoinAppender(context);
+
+		// TODO: andrus 1/6/2007 - conflict with object path naming... maybe
+		// 'registerReusableJoin' should normalize everything to a db path?
+		String newPath = idPath + '.' + lastPathComponent;
+		String oldPath = joinAppender.registerReusableJoin(idPath, lastPathComponent, newPath);
+
+		this.fullPath = fullPath + '.' + lastPathComponent;
+
+		if (oldPath != null) {
+			this.idPath = oldPath;
+			this.lastAlias = context.getTableAlias(oldPath,
+					context.getQuotingStrategy().quotedFullyQualifiedName(currentEntity));
+		} else {
+
+			// register join
+			if (inner) {
+				joinAppender.appendInnerJoin(joinMarker, new EJBQLTableId(idPath), new EJBQLTableId(fullPath));
+				this.lastAlias = context.getTableAlias(fullPath,
+						context.getQuotingStrategy().quotedFullyQualifiedName(currentEntity));
+			} else {
+				joinAppender.appendOuterJoin(joinMarker, new EJBQLTableId(idPath), new EJBQLTableId(fullPath));
+
+				Relationship lastRelationship = currentEntity.getRelationship(lastPathComponent);
+				DbEntity targetEntity = (DbEntity) lastRelationship.getTargetEntity();
+
+				this.lastAlias = context.getTableAlias(fullPath,
+						context.getQuotingStrategy().quotedFullyQualifiedName(targetEntity));
+			}
+
+			this.idPath = newPath;
+		}
+	}
+
+	private void processIntermediatePathComponent() {
+		DbRelationship relationship = currentEntity.getRelationship(lastPathComponent);
+		if (relationship == null) {
+			throw new EJBQLException("Unknown relationship '" + lastPathComponent + "' for entity '"
+					+ currentEntity.getName() + "'");
+		}
+
+		this.currentEntity = (DbEntity) relationship.getTargetEntity();
+	}
+
+	private void processLastPathComponent() {
+
+		DbAttribute attribute = currentEntity.getAttribute(lastPathComponent);
+
+		if (attribute != null) {
+			processTerminatingAttribute(attribute);
+			return;
+		}
+
+		DbRelationship relationship = currentEntity.getRelationship(lastPathComponent);
+		if (relationship != null) {
+			processTerminatingRelationship(relationship);
+			return;
+		}
+
+		throw new IllegalStateException("Invalid path component: " + lastPathComponent);
+	}
+
+	protected void processTerminatingAttribute(DbAttribute attribute) {
+
+		DbEntity table = (DbEntity) attribute.getEntity();
+
+		if (isUsingAliases()) {
+			String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
+					.getQuotingStrategy().quotedFullyQualifiedName(table));
+			context.append(' ').append(alias).append('.').append(context.getQuotingStrategy().quotedName(attribute));
+		} else {
+			context.append(' ').append(context.getQuotingStrategy().quotedName(attribute));
+		}
+	}
+
+	private void processTerminatingRelationship(DbRelationship relationship) {
+
+		if (relationship.isToMany()) {
+
+			// use an outer join for to-many matches
+			resolveJoin(false);
+
+			DbEntity table = (DbEntity) relationship.getTargetEntity();
 
-            String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
-                    .getQuotingStrategy().quotedFullyQualifiedName(table));
+			String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
+					.getQuotingStrategy().quotedFullyQualifiedName(table));
 
-            Collection<DbAttribute> pks = table.getPrimaryKeys();
-
-            if (pks.size() == 1) {
-                DbAttribute pk = pks.iterator().next();
-                context.append(' ');
-                if (isUsingAliases()) {
-                    context.append(alias).append('.');
-                }
-                context.append(context.getQuotingStrategy().quotedName(pk));
-            } else {
-                throw new EJBQLException("Multi-column PK to-many matches are not yet supported.");
-            }
-        } else {
-            // match FK against the target object
-
-            DbEntity table = (DbEntity) relationship.getSourceEntity();
-
-            String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
-                    .getQuotingStrategy().quotedFullyQualifiedName(table));
+			Collection<DbAttribute> pks = table.getPrimaryKeys();
+
+			if (pks.size() == 1) {
+				DbAttribute pk = pks.iterator().next();
+				context.append(' ');
+				if (isUsingAliases()) {
+					context.append(alias).append('.');
+				}
+				context.append(context.getQuotingStrategy().quotedName(pk));
+			} else {
+				throw new EJBQLException("Multi-column PK to-many matches are not yet supported.");
+			}
+		} else {
+			// match FK against the target object
+
+			DbEntity table = (DbEntity) relationship.getSourceEntity();
+
+			String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
+					.getQuotingStrategy().quotedFullyQualifiedName(table));
 
-            List<DbJoin> joins = relationship.getJoins();
-
-            if (joins.size() == 1) {
-                DbJoin join = joins.get(0);
-                context.append(' ');
-                if (isUsingAliases()) {
-                    context.append(alias).append('.');
-                }
-                context.append(context.getQuotingStrategy().quotedName(join.getSource()));
-            } else {
-                Map<String, String> multiColumnMatch = new HashMap<String, String>(joins.size() + 2);
+			List<DbJoin> joins = relationship.getJoins();
+
+			if (joins.size() == 1) {
+				DbJoin join = joins.get(0);
+				context.append(' ');
+				if (isUsingAliases()) {
+					context.append(alias).append('.');
+				}
+				context.append(context.getQuotingStrategy().quotedName(join.getSource()));
+			} else {
+				Map<String, String> multiColumnMatch = new HashMap<>(joins.size() + 2);
 
-                for (DbJoin join : joins) {
-                    String column = isUsingAliases() ? alias + "." + join.getSourceName() : join.getSourceName();
+				for (DbJoin join : joins) {
+					String column = isUsingAliases() ? alias + "." + join.getSourceName() : join.getSourceName();
 
-                    multiColumnMatch.put(join.getTargetName(), column);
-                }
+					multiColumnMatch.put(join.getTargetName(), column);
+				}
 
-                appendMultiColumnPath(EJBQLMultiColumnOperand.getPathOperand(context, multiColumnMatch));
-            }
-        }
-    }
+				appendMultiColumnPath(EJBQLMultiColumnOperand.getPathOperand(context, multiColumnMatch));
+			}
+		}
+	}
 
-    public boolean isUsingAliases() {
-        return usingAliases;
-    }
+	public boolean isUsingAliases() {
+		return usingAliases;
+	}
 
-    public void setUsingAliases(boolean usingAliases) {
-        this.usingAliases = usingAliases;
-    }
+	public void setUsingAliases(boolean usingAliases) {
+		this.usingAliases = usingAliases;
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLJoinAppender.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLJoinAppender.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLJoinAppender.java
index 1393bcc..b09aac9 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLJoinAppender.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLJoinAppender.java
@@ -69,7 +69,7 @@ public class EJBQLJoinAppender {
             String targetId) {
 
         if (reusableJoins == null) {
-            reusableJoins = new HashMap<String, String>();
+            reusableJoins = new HashMap<>();
         }
 
         String key = sourceIdPath + ":" + relationship;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/13d0da53/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLPathTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLPathTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLPathTranslator.java
index a5a165a..c7342d9 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLPathTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/ejbql/EJBQLPathTranslator.java
@@ -45,260 +45,260 @@ import org.apache.cayenne.reflect.ClassDescriptor;
  */
 public abstract class EJBQLPathTranslator extends EJBQLBaseVisitor {
 
-    private EJBQLTranslationContext context;
-    protected ObjEntity currentEntity;
-    protected String lastPathComponent;
-    protected String lastAlias;
-    protected String idPath;
-    protected String joinMarker;
-    protected String fullPath;
-    private boolean usingAliases;
-
-    public EJBQLPathTranslator(EJBQLTranslationContext context) {
-        super(true);
-        this.context = context;
-        this.usingAliases = true;
-    }
-
-    protected abstract void appendMultiColumnPath(EJBQLMultiColumnOperand operand);
-
-    @Override
-    public boolean visitPath(EJBQLExpression expression, int finishedChildIndex) {
-
-        if (finishedChildIndex > 0) {
-
-            if (finishedChildIndex + 1 < expression.getChildrenCount()) {
-                processIntermediatePathComponent();
-            } else {
-                processLastPathComponent();
-            }
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean visitIdentifier(EJBQLExpression expression) {
-        ClassDescriptor descriptor = context.getEntityDescriptor(expression.getText());
-        if (descriptor == null) {
-            throw new EJBQLException("Invalid identification variable: " + expression.getText());
-        }
-
-        this.currentEntity = descriptor.getEntity();
-        this.idPath = expression.getText();
-        this.joinMarker = EJBQLJoinAppender.makeJoinTailMarker(idPath);
-        this.fullPath = idPath;
-        return true;
-    }
-
-    @Override
-    public boolean visitIdentificationVariable(EJBQLExpression expression) {
-
-        // TODO: andrus 6/11/2007 - if the path ends with relationship, the last
-        // join will
-        // get lost...
-        if (lastPathComponent != null) {
-            resolveJoin(true);
-        }
-
-        this.lastPathComponent = expression.getText();
-        return true;
-    }
-
-    protected void resolveJoin(boolean inner) {
-
-        EJBQLJoinAppender joinAppender = context.getTranslatorFactory().getJoinAppender(context);
-
-        String newPath = idPath + '.' + lastPathComponent;
-        String oldPath = joinAppender.registerReusableJoin(idPath, lastPathComponent, newPath);
-
-        this.fullPath = fullPath + '.' + lastPathComponent;
-
-        if (oldPath != null) {
-            this.idPath = oldPath;
-            Relationship lastRelationship = currentEntity.getRelationship(lastPathComponent);
-            if (lastRelationship != null) {
-                ObjEntity targetEntity = (ObjEntity) lastRelationship.getTargetEntity();
-
-                this.lastAlias = context.getTableAlias(fullPath,
-                        context.getQuotingStrategy().quotedFullyQualifiedName(targetEntity.getDbEntity()));
-            } else {
-                String tableName = context.getQuotingStrategy().quotedFullyQualifiedName(currentEntity.getDbEntity());
-                this.lastAlias = context.getTableAlias(oldPath, tableName);
-            }
-        } else {
-            Relationship lastRelationship = currentEntity.getRelationship(lastPathComponent);
-
-            ObjEntity targetEntity = null;
-            if (lastRelationship != null) {
-                targetEntity = (ObjEntity) lastRelationship.getTargetEntity();
-            } else {
-                targetEntity = currentEntity;
-            }
-
-            // register join
-            if (inner) {
-                joinAppender.appendInnerJoin(joinMarker, new EJBQLTableId(idPath), new EJBQLTableId(fullPath));
-            } else {
-                joinAppender.appendOuterJoin(joinMarker, new EJBQLTableId(idPath), new EJBQLTableId(fullPath));
-
-            }
-
-            this.lastAlias = context.getTableAlias(fullPath,
-                    context.getQuotingStrategy().quotedFullyQualifiedName(targetEntity.getDbEntity()));
-
-            this.idPath = newPath;
-        }
-    }
-
-    protected void processIntermediatePathComponent() {
-        ObjRelationship relationship = currentEntity.getRelationship(lastPathComponent);
-        if (relationship == null) {
-            throw new EJBQLException("Unknown relationship '" + lastPathComponent + "' for entity '"
-                    + currentEntity.getName() + "'");
-        }
-
-        this.currentEntity = (ObjEntity) relationship.getTargetEntity();
-    }
-
-    protected void processLastPathComponent() {
-
-        ObjAttribute attribute = currentEntity.getAttribute(lastPathComponent);
-
-        if (attribute != null) {
-            processTerminatingAttribute(attribute);
-            return;
-        }
-
-        ObjRelationship relationship = currentEntity.getRelationship(lastPathComponent);
-        if (relationship != null) {
-            processTerminatingRelationship(relationship);
-            return;
-        }
-
-        throw new IllegalStateException("Invalid path component: " + lastPathComponent);
-    }
-
-    protected void processTerminatingAttribute(ObjAttribute attribute) {
-
-        DbEntity table = null;
-        Iterator<?> it = attribute.getDbPathIterator();
-        while (it.hasNext()) {
-            Object pathComponent = it.next();
-            if (pathComponent instanceof DbAttribute) {
-                table = (DbEntity) ((DbAttribute) pathComponent).getEntity();
-            }
-        }
-
-        if (isUsingAliases()) {
-            String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
-                    .getQuotingStrategy().quotedFullyQualifiedName(table));
-            context.append(' ').append(alias).append('.')
-                    .append(context.getQuotingStrategy().quotedName(attribute.getDbAttribute()));
-        } else {
-            context.append(' ').append(context.getQuotingStrategy().quotedName(attribute.getDbAttribute()));
-        }
-    }
-
-    protected void processTerminatingRelationship(ObjRelationship relationship) {
-
-        if (relationship.isSourceIndependentFromTargetChange()) {
-
-            // (andrus) use an outer join for to-many matches.. This is somewhat
-            // different
-            // from traditional Cayenne SelectQuery, as EJBQL spec does not
-            // allow regular
-            // path matches done against to-many relationships, and instead
-            // provides
-            // MEMBER OF and IS EMPTY operators. Outer join is needed for IS
-            // EMPTY... I
-            // guess MEMBER OF could've been done with an inner join though..
-            resolveJoin(false);
-
-            DbRelationship dbRelationship = chooseDbRelationship(relationship);
-            DbEntity table = (DbEntity) dbRelationship.getTargetEntity();
-
-            String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
-                    .getQuotingStrategy().quotedFullyQualifiedName(table));
-
-            Collection<DbAttribute> pks = table.getPrimaryKeys();
-
-            if (pks.size() == 1) {
-                DbAttribute pk = pks.iterator().next();
-                context.append(' ');
-                if (isUsingAliases()) {
-                    context.append(alias).append('.');
-                }
-                context.append(context.getQuotingStrategy().quotedName(pk));
-            } else {
-                throw new EJBQLException("Multi-column PK to-many matches are not yet supported.");
-            }
-
-        } else {
-            // match FK against the target object
-
-            DbRelationship dbRelationship = chooseDbRelationship(relationship);
-            DbEntity table = (DbEntity) dbRelationship.getSourceEntity();
-
-            String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
-                    .getQuotingStrategy().quotedFullyQualifiedName(table));
-
-            List<DbJoin> joins = dbRelationship.getJoins();
-
-            if (joins.size() == 1) {
-                DbJoin join = joins.get(0);
-                context.append(' ');
-                if (isUsingAliases()) {
-                    context.append(alias).append('.');
-                }
-                context.append(context.getQuotingStrategy().quotedName(join.getSource()));
-            } else {
-                Map<String, String> multiColumnMatch = new HashMap<String, String>(joins.size() + 2);
-
-                for (DbJoin join : joins) {
-                    String column = isUsingAliases() ? alias + "." + join.getSourceName() : join.getSourceName();
-
-                    multiColumnMatch.put(join.getTargetName(), column);
-                }
-
-                appendMultiColumnPath(EJBQLMultiColumnOperand.getPathOperand(context, multiColumnMatch));
-            }
-        }
-    }
-
-    /**
-     * Checks if the object relationship is flattened and then chooses the
-     * corresponding db relationship. The last in idPath if isFlattened and the
-     * first in list otherwise.
-     * 
-     * @param relationship
-     *            the object relationship
-     * 
-     * @return {@link DbRelationship}
-     */
-    protected DbRelationship chooseDbRelationship(ObjRelationship relationship) {
-
-        List<DbRelationship> dbRelationships = relationship.getDbRelationships();
-        String dbRelationshipPath = relationship.getDbRelationshipPath();
-
-        if (dbRelationshipPath.contains(".")) {
-            String dbRelName = dbRelationshipPath.substring(dbRelationshipPath.lastIndexOf(".") + 1);
-            for (DbRelationship dbR : dbRelationships) {
-                if (dbR.getName().equals(dbRelName)) {
-                    return dbR;
-                }
-
-            }
-        }
-        return relationship.getDbRelationships().get(0);
-
-    }
-
-    public boolean isUsingAliases() {
-        return usingAliases;
-    }
-
-    public void setUsingAliases(boolean usingAliases) {
-        this.usingAliases = usingAliases;
-    }
+	private EJBQLTranslationContext context;
+	protected ObjEntity currentEntity;
+	protected String lastPathComponent;
+	protected String lastAlias;
+	protected String idPath;
+	protected String joinMarker;
+	protected String fullPath;
+	private boolean usingAliases;
+
+	public EJBQLPathTranslator(EJBQLTranslationContext context) {
+		super(true);
+		this.context = context;
+		this.usingAliases = true;
+	}
+
+	protected abstract void appendMultiColumnPath(EJBQLMultiColumnOperand operand);
+
+	@Override
+	public boolean visitPath(EJBQLExpression expression, int finishedChildIndex) {
+
+		if (finishedChildIndex > 0) {
+
+			if (finishedChildIndex + 1 < expression.getChildrenCount()) {
+				processIntermediatePathComponent();
+			} else {
+				processLastPathComponent();
+			}
+		}
+
+		return true;
+	}
+
+	@Override
+	public boolean visitIdentifier(EJBQLExpression expression) {
+		ClassDescriptor descriptor = context.getEntityDescriptor(expression.getText());
+		if (descriptor == null) {
+			throw new EJBQLException("Invalid identification variable: " + expression.getText());
+		}
+
+		this.currentEntity = descriptor.getEntity();
+		this.idPath = expression.getText();
+		this.joinMarker = EJBQLJoinAppender.makeJoinTailMarker(idPath);
+		this.fullPath = idPath;
+		return true;
+	}
+
+	@Override
+	public boolean visitIdentificationVariable(EJBQLExpression expression) {
+
+		// TODO: andrus 6/11/2007 - if the path ends with relationship, the last
+		// join will
+		// get lost...
+		if (lastPathComponent != null) {
+			resolveJoin(true);
+		}
+
+		this.lastPathComponent = expression.getText();
+		return true;
+	}
+
+	protected void resolveJoin(boolean inner) {
+
+		EJBQLJoinAppender joinAppender = context.getTranslatorFactory().getJoinAppender(context);
+
+		String newPath = idPath + '.' + lastPathComponent;
+		String oldPath = joinAppender.registerReusableJoin(idPath, lastPathComponent, newPath);
+
+		this.fullPath = fullPath + '.' + lastPathComponent;
+
+		if (oldPath != null) {
+			this.idPath = oldPath;
+			Relationship lastRelationship = currentEntity.getRelationship(lastPathComponent);
+			if (lastRelationship != null) {
+				ObjEntity targetEntity = (ObjEntity) lastRelationship.getTargetEntity();
+
+				this.lastAlias = context.getTableAlias(fullPath,
+						context.getQuotingStrategy().quotedFullyQualifiedName(targetEntity.getDbEntity()));
+			} else {
+				String tableName = context.getQuotingStrategy().quotedFullyQualifiedName(currentEntity.getDbEntity());
+				this.lastAlias = context.getTableAlias(oldPath, tableName);
+			}
+		} else {
+			Relationship lastRelationship = currentEntity.getRelationship(lastPathComponent);
+
+			ObjEntity targetEntity = null;
+			if (lastRelationship != null) {
+				targetEntity = (ObjEntity) lastRelationship.getTargetEntity();
+			} else {
+				targetEntity = currentEntity;
+			}
+
+			// register join
+			if (inner) {
+				joinAppender.appendInnerJoin(joinMarker, new EJBQLTableId(idPath), new EJBQLTableId(fullPath));
+			} else {
+				joinAppender.appendOuterJoin(joinMarker, new EJBQLTableId(idPath), new EJBQLTableId(fullPath));
+
+			}
+
+			this.lastAlias = context.getTableAlias(fullPath,
+					context.getQuotingStrategy().quotedFullyQualifiedName(targetEntity.getDbEntity()));
+
+			this.idPath = newPath;
+		}
+	}
+
+	protected void processIntermediatePathComponent() {
+		ObjRelationship relationship = currentEntity.getRelationship(lastPathComponent);
+		if (relationship == null) {
+			throw new EJBQLException("Unknown relationship '" + lastPathComponent + "' for entity '"
+					+ currentEntity.getName() + "'");
+		}
+
+		this.currentEntity = (ObjEntity) relationship.getTargetEntity();
+	}
+
+	protected void processLastPathComponent() {
+
+		ObjAttribute attribute = currentEntity.getAttribute(lastPathComponent);
+
+		if (attribute != null) {
+			processTerminatingAttribute(attribute);
+			return;
+		}
+
+		ObjRelationship relationship = currentEntity.getRelationship(lastPathComponent);
+		if (relationship != null) {
+			processTerminatingRelationship(relationship);
+			return;
+		}
+
+		throw new IllegalStateException("Invalid path component: " + lastPathComponent);
+	}
+
+	protected void processTerminatingAttribute(ObjAttribute attribute) {
+
+		DbEntity table = null;
+		Iterator<?> it = attribute.getDbPathIterator();
+		while (it.hasNext()) {
+			Object pathComponent = it.next();
+			if (pathComponent instanceof DbAttribute) {
+				table = (DbEntity) ((DbAttribute) pathComponent).getEntity();
+			}
+		}
+
+		if (isUsingAliases()) {
+			String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
+					.getQuotingStrategy().quotedFullyQualifiedName(table));
+			context.append(' ').append(alias).append('.')
+					.append(context.getQuotingStrategy().quotedName(attribute.getDbAttribute()));
+		} else {
+			context.append(' ').append(context.getQuotingStrategy().quotedName(attribute.getDbAttribute()));
+		}
+	}
+
+	protected void processTerminatingRelationship(ObjRelationship relationship) {
+
+		if (relationship.isSourceIndependentFromTargetChange()) {
+
+			// (andrus) use an outer join for to-many matches.. This is somewhat
+			// different
+			// from traditional Cayenne SelectQuery, as EJBQL spec does not
+			// allow regular
+			// path matches done against to-many relationships, and instead
+			// provides
+			// MEMBER OF and IS EMPTY operators. Outer join is needed for IS
+			// EMPTY... I
+			// guess MEMBER OF could've been done with an inner join though..
+			resolveJoin(false);
+
+			DbRelationship dbRelationship = chooseDbRelationship(relationship);
+			DbEntity table = (DbEntity) dbRelationship.getTargetEntity();
+
+			String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
+					.getQuotingStrategy().quotedFullyQualifiedName(table));
+
+			Collection<DbAttribute> pks = table.getPrimaryKeys();
+
+			if (pks.size() == 1) {
+				DbAttribute pk = pks.iterator().next();
+				context.append(' ');
+				if (isUsingAliases()) {
+					context.append(alias).append('.');
+				}
+				context.append(context.getQuotingStrategy().quotedName(pk));
+			} else {
+				throw new EJBQLException("Multi-column PK to-many matches are not yet supported.");
+			}
+
+		} else {
+			// match FK against the target object
+
+			DbRelationship dbRelationship = chooseDbRelationship(relationship);
+			DbEntity table = (DbEntity) dbRelationship.getSourceEntity();
+
+			String alias = this.lastAlias != null ? lastAlias : context.getTableAlias(idPath, context
+					.getQuotingStrategy().quotedFullyQualifiedName(table));
+
+			List<DbJoin> joins = dbRelationship.getJoins();
+
+			if (joins.size() == 1) {
+				DbJoin join = joins.get(0);
+				context.append(' ');
+				if (isUsingAliases()) {
+					context.append(alias).append('.');
+				}
+				context.append(context.getQuotingStrategy().quotedName(join.getSource()));
+			} else {
+				Map<String, String> multiColumnMatch = new HashMap<>(joins.size() + 2);
+
+				for (DbJoin join : joins) {
+					String column = isUsingAliases() ? alias + "." + join.getSourceName() : join.getSourceName();
+
+					multiColumnMatch.put(join.getTargetName(), column);
+				}
+
+				appendMultiColumnPath(EJBQLMultiColumnOperand.getPathOperand(context, multiColumnMatch));
+			}
+		}
+	}
+
+	/**
+	 * Checks if the object relationship is flattened and then chooses the
+	 * corresponding db relationship. The last in idPath if isFlattened and the
+	 * first in list otherwise.
+	 * 
+	 * @param relationship
+	 *            the object relationship
+	 * 
+	 * @return {@link DbRelationship}
+	 */
+	protected DbRelationship chooseDbRelationship(ObjRelationship relationship) {
+
+		List<DbRelationship> dbRelationships = relationship.getDbRelationships();
+		String dbRelationshipPath = relationship.getDbRelationshipPath();
+
+		if (dbRelationshipPath.contains(".")) {
+			String dbRelName = dbRelationshipPath.substring(dbRelationshipPath.lastIndexOf(".") + 1);
+			for (DbRelationship dbR : dbRelationships) {
+				if (dbR.getName().equals(dbRelName)) {
+					return dbR;
+				}
+
+			}
+		}
+		return relationship.getDbRelationships().get(0);
+
+	}
+
+	public boolean isUsingAliases() {
+		return usingAliases;
+	}
+
+	public void setUsingAliases(boolean usingAliases) {
+		this.usingAliases = usingAliases;
+	}
 }


Mime
View raw message