From 024f1ae8bd16004ccc2c4afde4f7c2ab7c221a9e Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 26 Sep 2016 15:01:14 +0200 Subject: [PATCH] DATACMNS-921 - ResultProcessor now gracefully falls back to approximate collections if necessary. When handling collection results, we now create an approximate collection in case the creation of the exact same collection fails. --- .../repository/query/ResultProcessor.java | 18 +++++++++++++++- .../query/ResultProcessorUnitTests.java | 21 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/data/repository/query/ResultProcessor.java b/src/main/java/org/springframework/data/repository/query/ResultProcessor.java index e65eaf3ce..3cdbb2b4e 100644 --- a/src/main/java/org/springframework/data/repository/query/ResultProcessor.java +++ b/src/main/java/org/springframework/data/repository/query/ResultProcessor.java @@ -143,7 +143,7 @@ public class ResultProcessor { if (source instanceof Collection && method.isCollectionQuery()) { Collection collection = (Collection) source; - Collection target = CollectionFactory.createCollection(collection.getClass(), collection.size()); + Collection target = createCollectionFor(collection); for (Object columns : collection) { target.add(type.isInstance(columns) ? columns : converter.convert(columns)); @@ -159,6 +159,22 @@ public class ResultProcessor { return (T) converter.convert(source); } + /** + * Creates a new {@link Collection} for the given source. Will try to create an instance of the source collection's + * type first falling back to creating an approximate collection if the former fails. + * + * @param source must not be {@literal null}. + * @return + */ + private static Collection createCollectionFor(Collection source) { + + try { + return CollectionFactory.createCollection(source.getClass(), source.size()); + } catch (RuntimeException o_O) { + return CollectionFactory.createApproximateCollection(source, source.size()); + } + } + @RequiredArgsConstructor(staticName = "of") private static class ChainingConverter implements Converter { diff --git a/src/test/java/org/springframework/data/repository/query/ResultProcessorUnitTests.java b/src/test/java/org/springframework/data/repository/query/ResultProcessorUnitTests.java index d832e9a5d..450172e87 100644 --- a/src/test/java/org/springframework/data/repository/query/ResultProcessorUnitTests.java +++ b/src/test/java/org/springframework/data/repository/query/ResultProcessorUnitTests.java @@ -245,6 +245,20 @@ public class ResultProcessorUnitTests { assertThat(result, is(instanceOf(WrappingDto.class))); } + /** + * @see DATACMNS-921 + */ + @Test + public void fallsBackToApproximateCollectionIfNecessary() throws Exception { + + ResultProcessor processor = getProcessor("findAllProjection"); + + SpecialList specialList = new SpecialList(new Object()); + specialList.add(new Sample("Dave", "Matthews")); + + processor.processResult(specialList); + } + private static ResultProcessor getProcessor(String methodName, Class... parameters) throws Exception { return getQueryMethod(methodName, parameters).getResultProcessor(); } @@ -311,4 +325,11 @@ public class ResultProcessorUnitTests { @Value("#{target.firstname + ' ' + target.lastname}") String getFullName(); } + + static class SpecialList extends ArrayList { + + private static final long serialVersionUID = -6539525376878522158L; + + public SpecialList(Object dummy) {} + } }