Skip to content

Commit e5aeae9

Browse files
committed
Defer PersistentEntity lookup until actual DTO conversion.
We now lazily instantiate DtoInstantiatingConverter to defer the entity lookup if needed. Closes #612
1 parent 69f1f1e commit e5aeae9

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryExecution.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.data.relational.repository.query.DtoInstantiatingConverter;
3030
import org.springframework.data.repository.query.ResultProcessor;
3131
import org.springframework.data.repository.query.ReturnedType;
32+
import org.springframework.data.util.Lazy;
3233
import org.springframework.data.util.ReflectionUtils;
3334
import org.springframework.r2dbc.core.FetchSpec;
3435
import org.springframework.util.ClassUtils;
@@ -73,13 +74,16 @@ final class ResultProcessingConverter implements Converter<Object, Object> {
7374
private final ResultProcessor processor;
7475
private final MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> mappingContext;
7576
private final EntityInstantiators instantiators;
77+
private final Lazy<DtoInstantiatingConverter> converter;
7678

7779
ResultProcessingConverter(ResultProcessor processor,
7880
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> mappingContext,
7981
EntityInstantiators instantiators) {
8082
this.processor = processor;
8183
this.mappingContext = mappingContext;
8284
this.instantiators = instantiators;
85+
this.converter = Lazy.of(() -> new DtoInstantiatingConverter(processor.getReturnedType().getReturnedType(),
86+
this.mappingContext, this.instantiators));
8387
}
8488

8589
/* (non-Javadoc)
@@ -109,10 +113,7 @@ public Object convert(Object source) {
109113
}
110114
}
111115

112-
Converter<Object, Object> converter = new DtoInstantiatingConverter(returnedType.getReturnedType(),
113-
this.mappingContext, this.instantiators);
114-
115-
return this.processor.processResult(source, converter);
116+
return this.processor.processResult(source, it -> this.converter.get().convert(it));
116117
}
117118
}
118119
}

src/test/java/org/springframework/data/r2dbc/repository/query/StringBasedR2dbcQueryUnitTests.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,15 @@
1919
import static org.mockito.ArgumentMatchers.*;
2020
import static org.mockito.Mockito.*;
2121

22+
import io.r2dbc.spi.test.MockColumnMetadata;
23+
import io.r2dbc.spi.test.MockResult;
24+
import io.r2dbc.spi.test.MockRow;
25+
import io.r2dbc.spi.test.MockRowMetadata;
26+
import reactor.core.publisher.Flux;
27+
import reactor.test.StepVerifier;
28+
2229
import java.lang.reflect.Method;
30+
import java.time.LocalDate;
2331

2432
import org.junit.jupiter.api.BeforeEach;
2533
import org.junit.jupiter.api.Test;
@@ -38,6 +46,7 @@
3846
import org.springframework.data.r2dbc.dialect.PostgresDialect;
3947
import org.springframework.data.r2dbc.mapping.R2dbcMappingContext;
4048
import org.springframework.data.r2dbc.repository.Query;
49+
import org.springframework.data.r2dbc.testing.StatementRecorder;
4150
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
4251
import org.springframework.data.repository.Repository;
4352
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -274,6 +283,29 @@ void usesDtoTypeForDtoResultMapping() {
274283
assertThat(query.resolveResultType(query.getQueryMethod().getResultProcessor())).isEqualTo(PersonDto.class);
275284
}
276285

286+
@Test // gh-612
287+
void selectsSimpleType() {
288+
289+
MockRowMetadata metadata = MockRowMetadata.builder()
290+
.columnMetadata(MockColumnMetadata.builder().name("date").build()).build();
291+
LocalDate value = LocalDate.now();
292+
MockResult result = MockResult.builder().rowMetadata(metadata)
293+
.row(MockRow.builder().identified(0, LocalDate.class, value).build()).build();
294+
295+
StatementRecorder recorder = StatementRecorder.newInstance();
296+
recorder.addStubbing(s -> s.equals("SELECT MAX(DATE)"), result);
297+
298+
databaseClient = DatabaseClient.builder() //
299+
.connectionFactory(recorder) //
300+
.bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory()).build();
301+
302+
StringBasedR2dbcQuery query = getQueryMethod("findAllLocalDates");
303+
304+
Flux<Object> flux = (Flux) query.execute(new Object[0]);
305+
306+
flux.as(StepVerifier::create).expectNext(value).verifyComplete();
307+
}
308+
277309
private StringBasedR2dbcQuery getQueryMethod(String name, Class<?>... args) {
278310

279311
Method method = ReflectionUtils.findMethod(SampleRepository.class, name, args);
@@ -328,6 +360,9 @@ private interface SampleRepository extends Repository<Person, String> {
328360

329361
@Query("SELECT * FROM person")
330362
PersonProjection findAsInterfaceProjection();
363+
364+
@Query("SELECT MAX(DATE)")
365+
Flux<LocalDate> findAllLocalDates();
331366
}
332367

333368
static class PersonDto {

0 commit comments

Comments
 (0)