Skip to content

Commit a469683

Browse files
DATAGRAPH-1438 - Fix NPE when creating DTO based projections on empty result sets.
1 parent 89f3f08 commit a469683

File tree

5 files changed

+38
-2
lines changed

5 files changed

+38
-2
lines changed

src/main/java/org/springframework/data/neo4j/repository/query/DtoInstantiatingConverter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ class DtoInstantiatingConverter implements Converter<EntityInstanceWithSource, O
6767
@Override
6868
public Object convert(EntityInstanceWithSource entityInstanceAndSource) {
6969

70+
if (entityInstanceAndSource == null) {
71+
return null;
72+
}
73+
7074
Object entityInstance = entityInstanceAndSource.getEntityInstance();
7175
if (targetType.isInterface() || targetType.isInstance(entityInstance)) {
7276
return entityInstance;

src/test/java/org/springframework/data/neo4j/integration/imperative/RepositoryIT.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2838,7 +2838,7 @@ class Projection extends IntegrationTestBase {
28382838
void setupData(Transaction transaction) {
28392839
id1 = transaction.run(
28402840
"CREATE (n:PersonWithAllConstructor) "
2841-
+ "SET n.name = $name, n.sameValue = $sameValue, n.first_name = $firstName " + "RETURN id(n)",
2841+
+ "SET n.name = $name, n.sameValue = $sameValue, n.nullable = 'something', n.first_name = $firstName " + "RETURN id(n)",
28422842
Values.parameters("name", TEST_PERSON1_NAME, "sameValue", TEST_PERSON_SAMEVALUE, "firstName",
28432843
TEST_PERSON1_FIRST_NAME))
28442844
.next().get(0).asLong();
@@ -2867,6 +2867,21 @@ void mapsDtoProjectionWithDerivedFinderMethod(@Autowired PersonRepository reposi
28672867
.first().isEqualTo(TEST_PERSON1_FIRST_NAME);
28682868
}
28692869

2870+
@Test // DATAGRAPH-1438
2871+
void mapsOptionalDtoProjectionWithDerivedFinderMethod(@Autowired PersonRepository repository) {
2872+
2873+
assertThat(repository.findOneByFirstName(TEST_PERSON1_FIRST_NAME))
2874+
.map(DtoPersonProjection::getFirstName)
2875+
.hasValue(TEST_PERSON1_FIRST_NAME);
2876+
assertThat(repository.findOneByFirstName("foobar"))
2877+
.isEmpty();
2878+
2879+
assertThat(repository.findOneByNullable("something")).isNotNull()
2880+
.extracting(DtoPersonProjection::getFirstName)
2881+
.isEqualTo(TEST_PERSON1_FIRST_NAME);
2882+
assertThat(repository.findOneByNullable("foobar")).isNull();
2883+
}
2884+
28702885
@Test
28712886
void mapsInterfaceProjectionWithDerivedFinderMethodWithMultipleResults(@Autowired PersonRepository repository) {
28722887
assertThat(repository.findBySameValue(TEST_PERSON_SAMEVALUE)).hasSize(2);
@@ -2897,7 +2912,7 @@ void mapsInterfaceProjectionWithCustomQueryAndNodeReturnWithMultipleResults(
28972912
}
28982913

28992914
@Test
2900-
void mapsInterfaceProjectionWithCustomQueryAndNodeReturn2(@Autowired PersonRepository repository) {
2915+
void mapDtoProjectionWithCustomQueryAndNodeReturn(@Autowired PersonRepository repository) {
29012916

29022917
List<DtoPersonProjectionContainingAdditionalFields> projectedPeople = repository
29032918
.findAllDtoProjectionsWithAdditionalProperties(TEST_PERSON1_NAME);

src/test/java/org/springframework/data/neo4j/integration/imperative/repositories/PersonRepository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,10 @@ Optional<PersonWithAllConstructor> getOptionalPersonViaNamedQuery(@Param("part1"
259259

260260
List<DtoPersonProjection> findByFirstName(String firstName);
261261

262+
Optional<DtoPersonProjection> findOneByFirstName(String firstName);
263+
264+
DtoPersonProjection findOneByNullable(String nullable);
265+
262266
@Query(""
263267
+ "MATCH (n:PersonWithAllConstructor) where n.name = $name "
264268
+ "WITH n MATCH(m:PersonWithAllConstructor) WHERE id(n) <> id(m) "

src/test/java/org/springframework/data/neo4j/integration/reactive/ReactiveRepositoryIT.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
2020
import static org.assertj.core.api.Assertions.tuple;
2121

22+
import org.springframework.data.neo4j.integration.shared.common.DtoPersonProjection;
2223
import org.springframework.data.neo4j.integration.shared.common.SimplePerson;
2324
import org.springframework.data.neo4j.integration.shared.common.ThingWithFixedGeneratedId;
2425
import reactor.core.publisher.Flux;
@@ -2144,6 +2145,16 @@ void mapsInterfaceProjectionWithCustomQueryAndNodeReturnWithMultipleResults(
21442145
StepVerifier.create(repository.loadAllProjectionsWithNodeReturn()).expectNextCount(2).verifyComplete();
21452146
}
21462147

2148+
@Test // DATAGRAPH-1438
2149+
void mapsOptionalDtoProjectionWithDerivedFinderMethod(@Autowired ReactivePersonRepository repository) {
2150+
2151+
StepVerifier.create(repository.findOneByFirstName(TEST_PERSON1_FIRST_NAME).map(DtoPersonProjection::getFirstName))
2152+
.expectNext(TEST_PERSON1_FIRST_NAME)
2153+
.verifyComplete();
2154+
2155+
StepVerifier.create(repository.findOneByFirstName("foobar").map(DtoPersonProjection::getFirstName))
2156+
.verifyComplete();
2157+
}
21472158
}
21482159

21492160
@Nested

src/test/java/org/springframework/data/neo4j/integration/reactive/repositories/ReactivePersonRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,6 @@ public interface ReactivePersonRepository extends ReactiveNeo4jRepository<Person
8080

8181
@Query("MATCH (n:PersonWithAllConstructor) return n")
8282
Flux<PersonProjection> loadAllProjectionsWithNodeReturn();
83+
84+
Mono<DtoPersonProjection> findOneByFirstName(String firstName);
8385
}

0 commit comments

Comments
 (0)