From 4af7fe316564142eab8c679dbd401762f984dd66 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 15 Dec 2015 13:34:36 +0100 Subject: [PATCH] DATACMNS-89 - ChainingConverter now eagerly returns values. The ChainingConverter now returns values as soon as one converter in the chain produces an instance that's compatible to the target type. This allows ResourceProcessor clients to provide a Converter to take care of the complete conversion themselves. --- .../repository/query/ResultProcessor.java | 9 +++-- .../query/ResultProcessorUnitTests.java | 36 ++++++++++++++----- 2 files changed, 34 insertions(+), 11 deletions(-) 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 2414a278b..073f0d43a 100644 --- a/src/main/java/org/springframework/data/repository/query/ResultProcessor.java +++ b/src/main/java/org/springframework/data/repository/query/ResultProcessor.java @@ -127,7 +127,7 @@ public class ResultProcessor { Assert.notNull(preparingConverter, "Preparing converter must not be null!"); - ChainingConverter converter = ChainingConverter.of(preparingConverter).and(this.converter); + ChainingConverter converter = ChainingConverter.of(type.getReturnedType(), preparingConverter).and(this.converter); if (source instanceof Page && method.isPageQuery()) { return (T) ((Page) source).map(converter); @@ -151,6 +151,7 @@ public class ResultProcessor { @RequiredArgsConstructor(staticName = "of") private static class ChainingConverter implements Converter { + private final @NonNull Class targetType; private final @NonNull Converter delegate; /** @@ -164,11 +165,13 @@ public class ResultProcessor { Assert.notNull(converter, "Converter must not be null!"); - return new ChainingConverter(new Converter() { + return new ChainingConverter(targetType, new Converter() { @Override public Object convert(Object source) { - return converter.convert(ChainingConverter.this.convert(source)); + + Object intermediate = ChainingConverter.this.convert(source); + return targetType.isInstance(intermediate) ? intermediate : converter.convert(intermediate); } }); } 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 8e046b38d..265d29f86 100644 --- a/src/test/java/org/springframework/data/repository/query/ResultProcessorUnitTests.java +++ b/src/test/java/org/springframework/data/repository/query/ResultProcessorUnitTests.java @@ -28,6 +28,7 @@ import java.util.Map; import org.junit.Test; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.convert.converter.Converter; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -61,7 +62,7 @@ public class ResultProcessorUnitTests { @Test public void createsProjectionFromProperties() throws Exception { - ResultProcessor information = getFactory("findOneProjection"); + ResultProcessor information = getProcessor("findOneProjection"); SampleProjection result = information.processResult(Arrays.asList("Matthews")); @@ -75,7 +76,7 @@ public class ResultProcessorUnitTests { @SuppressWarnings("unchecked") public void createsListOfProjectionsFormNestedLists() throws Exception { - ResultProcessor information = getFactory("findAllProjection"); + ResultProcessor information = getProcessor("findAllProjection"); List columns = Arrays.asList("Matthews"); List> source = new ArrayList>(Arrays.asList(columns)); @@ -93,7 +94,7 @@ public class ResultProcessorUnitTests { @SuppressWarnings("unchecked") public void createsListOfProjectionsFromMaps() throws Exception { - ResultProcessor information = getFactory("findAllProjection"); + ResultProcessor information = getProcessor("findAllProjection"); List> source = new ArrayList>( Arrays.asList(Collections. singletonMap("lastname", "Matthews"))); @@ -110,7 +111,7 @@ public class ResultProcessorUnitTests { @Test public void createsListOfProjectionsFromEntity() throws Exception { - ResultProcessor information = getFactory("findAllProjection"); + ResultProcessor information = getProcessor("findAllProjection"); List source = new ArrayList(Arrays.asList(new Sample("Dave", "Matthews"))); List result = information.processResult(source); @@ -125,7 +126,7 @@ public class ResultProcessorUnitTests { @Test public void createsPageOfProjectionsFromEntity() throws Exception { - ResultProcessor information = getFactory("findPageProjection", Pageable.class); + ResultProcessor information = getProcessor("findPageProjection", Pageable.class); Page source = new PageImpl(Arrays.asList(new Sample("Dave", "Matthews"))); Page result = information.processResult(source); @@ -140,7 +141,7 @@ public class ResultProcessorUnitTests { @Test public void createsDynamicProjectionFromEntity() throws Exception { - ResultProcessor information = getFactory("findOneOpenProjection"); + ResultProcessor information = getProcessor("findOneOpenProjection"); OpenProjection result = information.processResult(new Sample("Dave", "Matthews")); @@ -156,7 +157,7 @@ public class ResultProcessorUnitTests { ParameterAccessor accessor = mock(ParameterAccessor.class); - ResultProcessor factory = getFactory("findOneDynamic", Class.class); + ResultProcessor factory = getProcessor("findOneDynamic", Class.class); assertThat(factory.withDynamicProjection(null), is(factory)); assertThat(factory.withDynamicProjection(accessor), is(factory)); @@ -166,7 +167,26 @@ public class ResultProcessorUnitTests { assertThat(processor.getReturnedType().getReturnedType(), is(typeCompatibleWith(SampleProjection.class))); } - private static ResultProcessor getFactory(String methodName, Class... parameters) throws Exception { + /** + * @see DATACMNS-89 + */ + @Test + public void refrainsFromProjectingIfThePreparingConverterReturnsACompatibleInstance() throws Exception { + + ResultProcessor processor = getProcessor("findAllDtos"); + + Object result = processor.processResult(new Sample("Dave", "Matthews"), new Converter() { + + @Override + public Object convert(Object source) { + return new SampleDTO(); + } + }); + + assertThat(result, is(instanceOf(SampleDTO.class))); + } + + private static ResultProcessor getProcessor(String methodName, Class... parameters) throws Exception { return getQueryMethod(methodName, parameters).getResultProcessor(); }