You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/02/22 11:06:10 UTC
cayenne git commit: CAY-2244 Using iterate() with ColumnSelect causes
a ClassCastException
Repository: cayenne
Updated Branches:
refs/heads/master cd83358e7 -> 7b90a4879
CAY-2244 Using iterate() with ColumnSelect causes a ClassCastException
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/7b90a487
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/7b90a487
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/7b90a487
Branch: refs/heads/master
Commit: 7b90a487997c05ade6db6ce199d1aafe66212122
Parents: cd83358
Author: Nikita Timofeev <st...@gmail.com>
Authored: Wed Feb 22 14:05:11 2017 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Wed Feb 22 14:05:11 2017 +0300
----------------------------------------------------------------------
.../org/apache/cayenne/access/DataContext.java | 121 ++++++++++++-------
.../cayenne/query/ObjectSelect_RunIT.java | 57 +++++++++
2 files changed, 131 insertions(+), 47 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/7b90a487/cayenne-server/src/main/java/org/apache/cayenne/access/DataContext.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataContext.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataContext.java
index cc0a65e..264a7e8 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataContext.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataContext.java
@@ -800,59 +800,35 @@ public class DataContext extends BaseContext {
@SuppressWarnings("unchecked")
@Override
- public <T> ResultIterator<T> iterator(Select<T> query) {
- final ResultIterator<DataRow> rows = performIteratedQuery(query);
+ public <T> ResultIterator<T> iterator(final Select<T> query) {
+ final ResultIterator<?> rows = performIteratedQuery(query);
+ final QueryMetadata md = query.getMetaData(getEntityResolver());
- QueryMetadata md = query.getMetaData(getEntityResolver());
- if (md.isFetchingDataRows()) {
+ if (md.isFetchingDataRows() || isObjectArrayResult(md)) {
+ // no need to convert result
return (ResultIterator<T>) rows;
} else {
-
// this is a bit optimized version of 'objectFromDataRow' with
// resolver cached for reuse... still the rest is pretty suboptimal
- ClassDescriptor descriptor = md.getClassDescriptor();
- final ObjectResolver resolver = new ObjectResolver(this, descriptor, true);
- return new ResultIterator<T>() {
-
- @Override
- public Iterator<T> iterator() {
- return new ResultIteratorIterator<T>(this);
- }
-
- @Override
- public List<T> allRows() {
- List<T> list = new ArrayList<>();
-
- while (hasNextRow()) {
- list.add(nextRow());
- }
-
- return list;
- }
-
- @Override
- public boolean hasNextRow() {
- return rows.hasNextRow();
- }
-
- @Override
- public T nextRow() {
- DataRow row = rows.nextRow();
- List<T> objects = (List<T>) resolver
- .synchronizedObjectsFromDataRows(Collections.singletonList(row));
- return (T) objects.get(0);
- }
+ final ObjectResolver resolver = new ObjectResolver(this, md.getClassDescriptor(), true);
+ return new DataRowResultIterator(rows, resolver);
+ }
+ }
- @Override
- public void skipRow() {
- rows.skipRow();
- }
+ /**
+ * This method repeats logic of DataDomainQueryAction.interceptObjectConversion() method.
+ * The difference is that iterator(or batchIterator) doesn't support "mixed" results.
+ */
+ private boolean isObjectArrayResult(QueryMetadata md) {
+ List<Object> resultMapping = md.getResultSetMapping();
+ if(resultMapping == null) {
+ return false;
+ }
- @Override
- public void close() {
- rows.close();
- }
- };
+ if (md.isSingleResultSetMapping()) {
+ return !(resultMapping.get(0) instanceof EntityResultSegment);
+ } else {
+ return true;
}
}
@@ -1142,7 +1118,7 @@ public class DataContext extends BaseContext {
}
/**
- * An internal version of {@link #localObject(Object)} that operates on
+ * An internal version of {@link #localObject(Persistent)} that operates on
* ObjectId instead of Persistent, and wouldn't attempt to look up an object
* in the parent channel.
*
@@ -1218,4 +1194,55 @@ public class DataContext extends BaseContext {
this.transactionFactory = transactionFactory;
}
+ /**
+ * ResultIterator that can convert DataRow to Persistent object on the fly.
+ */
+ static class DataRowResultIterator<T> implements ResultIterator<T> {
+
+ final ResultIterator<?> rows;
+ ObjectResolver resolver;
+
+ DataRowResultIterator(ResultIterator<?> rows, ObjectResolver resolver) {
+ this.rows = rows;
+ this.resolver = resolver;
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return new ResultIteratorIterator<>(this);
+ }
+
+ @Override
+ public List<T> allRows() {
+ List<T> list = new ArrayList<>();
+ while (hasNextRow()) {
+ list.add(nextRow());
+ }
+ return list;
+ }
+
+ @Override
+ public boolean hasNextRow() {
+ return rows.hasNextRow();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public T nextRow() {
+ DataRow row = (DataRow) rows.nextRow();
+ List<T> objects = (List<T>) resolver.synchronizedObjectsFromDataRows(Collections.singletonList(row));
+ return objects.get(0);
+ }
+
+ @Override
+ public void skipRow() {
+ rows.skipRow();
+ }
+
+ @Override
+ public void close() {
+ rows.close();
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/7b90a487/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_RunIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_RunIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_RunIT.java
index eb4095d..32dd23e 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_RunIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_RunIT.java
@@ -290,4 +290,61 @@ public class ObjectSelect_RunIT extends ServerCase {
assertNotNull(a);
assertEquals("ng1 artist1", a);
}
+
+ @Test
+ public void test_ColumnSelect_IterationSingleColumn() throws Exception {
+ ColumnSelect<String> columnSelect = ObjectSelect.query(Artist.class).column(Artist.ARTIST_NAME);
+
+ final int[] count = new int[1];
+ columnSelect.iterate(context, new ResultIteratorCallback<String>() {
+ @Override
+ public void next(String object) {
+ count[0]++;
+ assertTrue(object.startsWith("artist"));
+ }
+ });
+
+ assertEquals(20, count[0]);
+ }
+
+ @Test
+ public void test_ColumnSelect_BatchIterationSingleColumn() throws Exception {
+ ColumnSelect<String> columnSelect = ObjectSelect.query(Artist.class).column(Artist.ARTIST_NAME);
+
+ try(ResultBatchIterator<String> it = columnSelect.batchIterator(context, 10)) {
+ List<String> next = it.next();
+ assertEquals(10, next.size());
+ assertTrue(next.get(0).startsWith("artist"));
+ }
+ }
+
+ @Test
+ public void test_ColumnSelect_IterationMultiColumns() throws Exception {
+ ColumnSelect<Object[]> columnSelect = ObjectSelect.query(Artist.class).columns(Artist.ARTIST_NAME, Artist.DATE_OF_BIRTH);
+
+ final int[] count = new int[1];
+ columnSelect.iterate(context, new ResultIteratorCallback<Object[]>() {
+ @Override
+ public void next(Object[] object) {
+ count[0]++;
+ assertTrue(object[0] instanceof String);
+ assertTrue(object[1] instanceof java.util.Date);
+ }
+ });
+
+ assertEquals(20, count[0]);
+ }
+
+ @Test
+ public void test_ColumnSelect_BatchIterationMultiColumns() throws Exception {
+ ColumnSelect<Object[]> columnSelect = ObjectSelect.query(Artist.class).columns(Artist.ARTIST_NAME, Artist.DATE_OF_BIRTH);
+
+ try(ResultBatchIterator<Object[]> it = columnSelect.batchIterator(context, 10)) {
+ List<Object[]> next = it.next();
+ assertEquals(10, next.size());
+ assertTrue(next.get(0)[0] instanceof String);
+ assertTrue(next.get(0)[1] instanceof java.util.Date);
+ }
+ }
+
}