Browse Source

DATACMNS-859, DATACMNS-860 - Improvements to ResourceProcessor.

ResourceProcessor supports Streams now and adds a map(…) step to apply projections.

Also, the ProjectingConverter falls back to use a default ConversionService instance to make use of the object mapping functionality implemented in ObjectToObjectConverter, i.e. the ability to just map an object returned from the store to a DTO in case that latter exposes a constructor or factory methods taking the source instance as parameter.

Related tickets: DATAJPA-903.
pull/157/merge
Oliver Gierke 10 years ago
parent
commit
bdc61a044f
  1. 29
      src/main/java/org/springframework/data/repository/query/ResultProcessor.java
  2. 51
      src/test/java/org/springframework/data/repository/query/ResultProcessorUnitTests.java

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

@ -23,11 +23,16 @@ import java.util.Collection; @@ -23,11 +23,16 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
import org.springframework.core.CollectionFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.domain.Slice;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.util.ReflectionUtils;
import org.springframework.util.Assert;
/**
@ -127,7 +132,8 @@ public class ResultProcessor { @@ -127,7 +132,8 @@ public class ResultProcessor {
Assert.notNull(preparingConverter, "Preparing converter must not be null!");
ChainingConverter converter = ChainingConverter.of(type.getReturnedType(), preparingConverter).and(this.converter);
final ChainingConverter converter = ChainingConverter.of(type.getReturnedType(), preparingConverter)
.and(this.converter);
if (source instanceof Slice && method.isPageQuery() || method.isSliceQuery()) {
return (T) ((Slice<?>) source).map(converter);
@ -145,6 +151,17 @@ public class ResultProcessor { @@ -145,6 +151,17 @@ public class ResultProcessor {
return (T) target;
}
if (ReflectionUtils.isJava8StreamType(source.getClass()) && method.isStreamQuery()) {
return (T) ((Stream<Object>) source).map(new Function<Object, T>() {
@Override
public T apply(Object t) {
return (T) (type.isInstance(t) ? t : converter.convert(t));
}
});
}
return (T) converter.convert(source);
}
@ -211,6 +228,7 @@ public class ResultProcessor { @@ -211,6 +228,7 @@ public class ResultProcessor {
private final @NonNull ReturnedType type;
private final @NonNull ProjectionFactory factory;
private final ConversionService conversionService = new DefaultConversionService();
/*
* (non-Javadoc)
@ -218,7 +236,14 @@ public class ResultProcessor { @@ -218,7 +236,14 @@ public class ResultProcessor {
*/
@Override
public Object convert(Object source) {
return factory.createProjection(type.getReturnedType(), getProjectionTarget(source));
Class<?> targetType = type.getReturnedType();
if (targetType.isInterface()) {
return factory.createProjection(targetType, getProjectionTarget(source));
}
return conversionService.convert(source, targetType);
}
private Object getProjectionTarget(Object source) {

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

@ -25,6 +25,8 @@ import java.util.Arrays; @@ -25,6 +25,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
@ -183,11 +185,11 @@ public class ResultProcessorUnitTests { @@ -183,11 +185,11 @@ public class ResultProcessorUnitTests {
@Override
public Object convert(Object source) {
return new SampleDTO();
return new SampleDto();
}
});
assertThat(result, is(instanceOf(SampleDTO.class)));
assertThat(result, is(instanceOf(SampleDto.class)));
}
/**
@ -215,6 +217,34 @@ public class ResultProcessorUnitTests { @@ -215,6 +217,34 @@ public class ResultProcessorUnitTests {
assertThat(content.get(0), is(instanceOf(SampleProjection.class)));
}
/**
* @see DATACMNS-859
*/
@Test
public void supportsStreamAsReturnWrapper() throws Exception {
Stream<Sample> samples = Arrays.asList(new Sample("Dave", "Matthews")).stream();
Object result = getProcessor("findStreamProjection").processResult(samples);
assertThat(result, is(instanceOf(Stream.class)));
List<?> content = ((Stream<?>) result).collect(Collectors.toList());
assertThat(content, is(not(empty())));
assertThat(content.get(0), is(instanceOf(SampleProjection.class)));
}
/**
* @see DATACMNS-860
*/
@Test
public void supportsWrappingDto() throws Exception {
Object result = getProcessor("findOneWrappingDto").processResult(new Sample("Dave", "Matthews"));
assertThat(result, is(instanceOf(WrappingDto.class)));
}
private static ResultProcessor getProcessor(String methodName, Class<?>... parameters) throws Exception {
return getQueryMethod(methodName, parameters).getResultProcessor();
}
@ -230,13 +260,15 @@ public class ResultProcessorUnitTests { @@ -230,13 +260,15 @@ public class ResultProcessorUnitTests {
List<Sample> findAll();
List<SampleDTO> findAllDtos();
List<SampleDto> findAllDtos();
List<SampleProjection> findAllProjection();
Sample findOne();
SampleDTO findOneDto();
SampleDto findOneDto();
WrappingDto findOneWrappingDto();
SampleProjection findOneProjection();
@ -247,6 +279,8 @@ public class ResultProcessorUnitTests { @@ -247,6 +279,8 @@ public class ResultProcessorUnitTests {
Slice<SampleProjection> findSliceProjection(Pageable pageable);
<T> T findOneDynamic(Class<T> type);
Stream<SampleProjection> findStreamProjection();
}
static class Sample {
@ -258,10 +292,15 @@ public class ResultProcessorUnitTests { @@ -258,10 +292,15 @@ public class ResultProcessorUnitTests {
}
}
static class SampleDTO {}
static class SampleDto {}
interface SampleProjection {
@lombok.Value
// Needs to be public until https://jira.spring.io/browse/SPR-14304 is resolved
public static class WrappingDto {
Sample sample;
}
interface SampleProjection {
String getLastname();
}

Loading…
Cancel
Save