Skip to content

Commit 4af7fe3

Browse files
committed
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.
1 parent dbe79f8 commit 4af7fe3

File tree

2 files changed

+34
-11
lines changed

2 files changed

+34
-11
lines changed

src/main/java/org/springframework/data/repository/query/ResultProcessor.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public <T> T processResult(Object source, Converter<Object, Object> preparingCon
127127

128128
Assert.notNull(preparingConverter, "Preparing converter must not be null!");
129129

130-
ChainingConverter converter = ChainingConverter.of(preparingConverter).and(this.converter);
130+
ChainingConverter converter = ChainingConverter.of(type.getReturnedType(), preparingConverter).and(this.converter);
131131

132132
if (source instanceof Page && method.isPageQuery()) {
133133
return (T) ((Page<?>) source).map(converter);
@@ -151,6 +151,7 @@ public <T> T processResult(Object source, Converter<Object, Object> preparingCon
151151
@RequiredArgsConstructor(staticName = "of")
152152
private static class ChainingConverter implements Converter<Object, Object> {
153153

154+
private final @NonNull Class<?> targetType;
154155
private final @NonNull Converter<Object, Object> delegate;
155156

156157
/**
@@ -164,11 +165,13 @@ public ChainingConverter and(final Converter<Object, Object> converter) {
164165

165166
Assert.notNull(converter, "Converter must not be null!");
166167

167-
return new ChainingConverter(new Converter<Object, Object>() {
168+
return new ChainingConverter(targetType, new Converter<Object, Object>() {
168169

169170
@Override
170171
public Object convert(Object source) {
171-
return converter.convert(ChainingConverter.this.convert(source));
172+
173+
Object intermediate = ChainingConverter.this.convert(source);
174+
return targetType.isInstance(intermediate) ? intermediate : converter.convert(intermediate);
172175
}
173176
});
174177
}

src/test/java/org/springframework/data/repository/query/ResultProcessorUnitTests.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import org.junit.Test;
3030
import org.springframework.beans.factory.annotation.Value;
31+
import org.springframework.core.convert.converter.Converter;
3132
import org.springframework.data.domain.Page;
3233
import org.springframework.data.domain.PageImpl;
3334
import org.springframework.data.domain.Pageable;
@@ -61,7 +62,7 @@ public void leavesNonProjectingResultUntouched() throws Exception {
6162
@Test
6263
public void createsProjectionFromProperties() throws Exception {
6364

64-
ResultProcessor information = getFactory("findOneProjection");
65+
ResultProcessor information = getProcessor("findOneProjection");
6566

6667
SampleProjection result = information.processResult(Arrays.asList("Matthews"));
6768

@@ -75,7 +76,7 @@ public void createsProjectionFromProperties() throws Exception {
7576
@SuppressWarnings("unchecked")
7677
public void createsListOfProjectionsFormNestedLists() throws Exception {
7778

78-
ResultProcessor information = getFactory("findAllProjection");
79+
ResultProcessor information = getProcessor("findAllProjection");
7980

8081
List<String> columns = Arrays.asList("Matthews");
8182
List<List<String>> source = new ArrayList<List<String>>(Arrays.asList(columns));
@@ -93,7 +94,7 @@ public void createsListOfProjectionsFormNestedLists() throws Exception {
9394
@SuppressWarnings("unchecked")
9495
public void createsListOfProjectionsFromMaps() throws Exception {
9596

96-
ResultProcessor information = getFactory("findAllProjection");
97+
ResultProcessor information = getProcessor("findAllProjection");
9798

9899
List<Map<String, Object>> source = new ArrayList<Map<String, Object>>(
99100
Arrays.asList(Collections.<String, Object> singletonMap("lastname", "Matthews")));
@@ -110,7 +111,7 @@ public void createsListOfProjectionsFromMaps() throws Exception {
110111
@Test
111112
public void createsListOfProjectionsFromEntity() throws Exception {
112113

113-
ResultProcessor information = getFactory("findAllProjection");
114+
ResultProcessor information = getProcessor("findAllProjection");
114115

115116
List<Sample> source = new ArrayList<Sample>(Arrays.asList(new Sample("Dave", "Matthews")));
116117
List<SampleProjection> result = information.processResult(source);
@@ -125,7 +126,7 @@ public void createsListOfProjectionsFromEntity() throws Exception {
125126
@Test
126127
public void createsPageOfProjectionsFromEntity() throws Exception {
127128

128-
ResultProcessor information = getFactory("findPageProjection", Pageable.class);
129+
ResultProcessor information = getProcessor("findPageProjection", Pageable.class);
129130

130131
Page<Sample> source = new PageImpl<Sample>(Arrays.asList(new Sample("Dave", "Matthews")));
131132
Page<SampleProjection> result = information.processResult(source);
@@ -140,7 +141,7 @@ public void createsPageOfProjectionsFromEntity() throws Exception {
140141
@Test
141142
public void createsDynamicProjectionFromEntity() throws Exception {
142143

143-
ResultProcessor information = getFactory("findOneOpenProjection");
144+
ResultProcessor information = getProcessor("findOneOpenProjection");
144145

145146
OpenProjection result = information.processResult(new Sample("Dave", "Matthews"));
146147

@@ -156,7 +157,7 @@ public void findsDynamicProjection() throws Exception {
156157

157158
ParameterAccessor accessor = mock(ParameterAccessor.class);
158159

159-
ResultProcessor factory = getFactory("findOneDynamic", Class.class);
160+
ResultProcessor factory = getProcessor("findOneDynamic", Class.class);
160161
assertThat(factory.withDynamicProjection(null), is(factory));
161162
assertThat(factory.withDynamicProjection(accessor), is(factory));
162163

@@ -166,7 +167,26 @@ public void findsDynamicProjection() throws Exception {
166167
assertThat(processor.getReturnedType().getReturnedType(), is(typeCompatibleWith(SampleProjection.class)));
167168
}
168169

169-
private static ResultProcessor getFactory(String methodName, Class<?>... parameters) throws Exception {
170+
/**
171+
* @see DATACMNS-89
172+
*/
173+
@Test
174+
public void refrainsFromProjectingIfThePreparingConverterReturnsACompatibleInstance() throws Exception {
175+
176+
ResultProcessor processor = getProcessor("findAllDtos");
177+
178+
Object result = processor.processResult(new Sample("Dave", "Matthews"), new Converter<Object, Object>() {
179+
180+
@Override
181+
public Object convert(Object source) {
182+
return new SampleDTO();
183+
}
184+
});
185+
186+
assertThat(result, is(instanceOf(SampleDTO.class)));
187+
}
188+
189+
private static ResultProcessor getProcessor(String methodName, Class<?>... parameters) throws Exception {
170190
return getQueryMethod(methodName, parameters).getResultProcessor();
171191
}
172192

0 commit comments

Comments
 (0)