Skip to content

Commit 4c97dc0

Browse files
committed
GH-2459 - Avoid overriding when mapping relationships with abstract types.
Closes #2459
1 parent 814f388 commit 4c97dc0

File tree

2 files changed

+163
-15
lines changed

2 files changed

+163
-15
lines changed

src/main/java/org/springframework/data/neo4j/core/mapping/DefaultNeo4jEntityConverter.java

+15-15
Original file line numberDiff line numberDiff line change
@@ -489,28 +489,28 @@ private AssociationHandler<Neo4jPersistentProperty> populateFrom(MapAccessor que
489489
if (willCreateNewInstance) {
490490
throw new MappingException("Cannot create a new instance of an already existing object.");
491491
}
492+
}
492493

493-
Object propertyValue = propertyAccessor.getProperty(persistentProperty);
494+
Object propertyValue = propertyAccessor.getProperty(persistentProperty);
494495

495-
boolean propertyValueNotNull = propertyValue != null;
496+
boolean propertyValueNotNull = propertyValue != null;
496497

497-
boolean populatedCollection = persistentProperty.isCollectionLike()
498-
&& propertyValueNotNull
499-
&& !((Collection<?>) propertyValue).isEmpty();
498+
boolean populatedCollection = persistentProperty.isCollectionLike()
499+
&& propertyValueNotNull
500+
&& !((Collection<?>) propertyValue).isEmpty();
500501

501-
boolean populatedMap = persistentProperty.isMap()
502-
&& propertyValueNotNull
503-
&& !((Map<?, ?>) propertyValue).isEmpty();
502+
boolean populatedMap = persistentProperty.isMap()
503+
&& propertyValueNotNull
504+
&& !((Map<?, ?>) propertyValue).isEmpty();
504505

505-
boolean populatedScalarValue = !persistentProperty.isCollectionLike()
506-
&& propertyValueNotNull;
506+
boolean populatedScalarValue = !persistentProperty.isCollectionLike() && !persistentProperty.isMap()
507+
&& propertyValueNotNull;
507508

508-
boolean propertyAlreadyPopulated = populatedCollection || populatedMap || populatedScalarValue;
509+
boolean propertyAlreadyPopulated = populatedCollection || populatedMap || populatedScalarValue;
509510

510-
// avoid unnecessary re-assignment of values
511-
if (propertyAlreadyPopulated) {
512-
return;
513-
}
511+
// avoid unnecessary re-assignment of values
512+
if (propertyAlreadyPopulated) {
513+
return;
514514
}
515515

516516
createInstanceOfRelationships(persistentProperty, queryResult, (RelationshipDescription) association, relationshipsFromResult, nodesFromResult)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright 2011-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.neo4j.integration.issues.gh2459;
17+
18+
import org.junit.jupiter.api.BeforeEach;
19+
import org.junit.jupiter.api.Test;
20+
import org.neo4j.driver.Driver;
21+
import org.neo4j.driver.Session;
22+
import org.springframework.beans.factory.annotation.Autowired;
23+
import org.springframework.context.annotation.Bean;
24+
import org.springframework.context.annotation.Configuration;
25+
import org.springframework.data.neo4j.config.AbstractNeo4jConfig;
26+
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
27+
import org.springframework.data.neo4j.core.schema.Id;
28+
import org.springframework.data.neo4j.core.schema.Node;
29+
import org.springframework.data.neo4j.core.schema.Relationship;
30+
import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager;
31+
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
32+
import org.springframework.data.neo4j.repository.Neo4jRepository;
33+
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
34+
import org.springframework.data.neo4j.test.BookmarkCapture;
35+
import org.springframework.data.neo4j.test.Neo4jExtension;
36+
import org.springframework.data.neo4j.test.Neo4jIntegrationTest;
37+
import org.springframework.transaction.PlatformTransactionManager;
38+
import org.springframework.transaction.annotation.EnableTransactionManagement;
39+
40+
import java.util.List;
41+
42+
import static org.assertj.core.api.Assertions.assertThat;
43+
44+
/**
45+
* Ensure the right mapping from a result containing a mixture of abstract and concrete classes.
46+
* reference: https://github.com/spring-projects/spring-data-neo4j/issues/2459
47+
*/
48+
@Neo4jIntegrationTest
49+
public class GH2459IT {
50+
51+
protected static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport;
52+
53+
@Autowired
54+
Driver driver;
55+
56+
@Autowired
57+
BookmarkCapture bookmarkCapture;
58+
59+
@BeforeEach
60+
void setupData() {
61+
try (Session session = driver.session(bookmarkCapture.createSessionConfig())) {
62+
session.run("MATCH (n) DETACH DELETE n").consume();
63+
session.run("" +
64+
"CREATE(po1:Boy:PetOwner {name: 'Boy1', uuid: '10'})\n" +
65+
"CREATE(a1:Dog:Animal {name: 'Dog1',uuid: '11'})\n" +
66+
"CREATE (po1)-[:hasPet]->(a1)\n" +
67+
"CREATE(a3:Cat:Animal {name: 'Cat1',uuid: '12'})\n" +
68+
"CREATE (po1)-[:hasPet]->(a3)").consume();
69+
}
70+
}
71+
72+
@Test
73+
void dontOverrideAbstractMappedData(@Autowired PetOwnerRepository repository) {
74+
PetOwner petOwner = repository.findById("10").get();
75+
assertThat(petOwner.pets).hasSize(2);
76+
}
77+
78+
interface PetOwnerRepository extends Neo4jRepository<PetOwner, String> {}
79+
80+
/**
81+
* PetOwner
82+
*/
83+
@Node("PetOwner")
84+
public static abstract class PetOwner {
85+
@Id
86+
private String uuid;
87+
@Relationship(type = "hasPet")
88+
private List<Animal> pets;
89+
}
90+
91+
/**
92+
* Boy
93+
*/
94+
@Node("Boy")
95+
public static class Boy extends PetOwner {}
96+
97+
/**
98+
* Girl
99+
*/
100+
@Node("Girl")
101+
public static class Girl extends PetOwner {}
102+
103+
/**
104+
* Animal
105+
*/
106+
@Node("Animal")
107+
public static abstract class Animal {
108+
@Id
109+
private String uuid;
110+
}
111+
112+
/**
113+
* Dog
114+
*/
115+
@Node("Dog")
116+
public static class Dog extends Animal {}
117+
118+
/**
119+
* Cat
120+
*/
121+
@Node("Cat")
122+
public static class Cat extends Animal {}
123+
124+
@Configuration
125+
@EnableTransactionManagement
126+
@EnableNeo4jRepositories(considerNestedRepositories = true)
127+
static class Config extends AbstractNeo4jConfig {
128+
129+
@Bean
130+
public BookmarkCapture bookmarkCapture() {
131+
return new BookmarkCapture();
132+
}
133+
134+
@Override
135+
public PlatformTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider) {
136+
137+
BookmarkCapture bookmarkCapture = bookmarkCapture();
138+
return new Neo4jTransactionManager(driver, databaseNameProvider,
139+
Neo4jBookmarkManager.create(bookmarkCapture));
140+
}
141+
142+
@Bean
143+
public Driver driver() {
144+
145+
return neo4jConnectionSupport.getDriver();
146+
}
147+
}
148+
}

0 commit comments

Comments
 (0)