Skip to content

Commit 4d8625e

Browse files
committed
GH-2459 - Avoid overriding when mapping relationships with abstract types.
Closes #2459
1 parent 3512c6a commit 4d8625e

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
@@ -510,28 +510,28 @@ private AssociationHandler<Neo4jPersistentProperty> populateFrom(MapAccessor que
510510
if (willCreateNewInstance) {
511511
throw new MappingException("Cannot create a new instance of an already existing object.");
512512
}
513+
}
513514

514-
Object propertyValue = propertyAccessor.getProperty(persistentProperty);
515+
Object propertyValue = propertyAccessor.getProperty(persistentProperty);
515516

516-
boolean propertyValueNotNull = propertyValue != null;
517+
boolean propertyValueNotNull = propertyValue != null;
517518

518-
boolean populatedCollection = persistentProperty.isCollectionLike()
519-
&& propertyValueNotNull
520-
&& !((Collection<?>) propertyValue).isEmpty();
519+
boolean populatedCollection = persistentProperty.isCollectionLike()
520+
&& propertyValueNotNull
521+
&& !((Collection<?>) propertyValue).isEmpty();
521522

522-
boolean populatedMap = persistentProperty.isMap()
523-
&& propertyValueNotNull
524-
&& !((Map<?, ?>) propertyValue).isEmpty();
523+
boolean populatedMap = persistentProperty.isMap()
524+
&& propertyValueNotNull
525+
&& !((Map<?, ?>) propertyValue).isEmpty();
525526

526-
boolean populatedScalarValue = !persistentProperty.isCollectionLike()
527-
&& propertyValueNotNull;
527+
boolean populatedScalarValue = !persistentProperty.isCollectionLike() && !persistentProperty.isMap()
528+
&& propertyValueNotNull;
528529

529-
boolean propertyAlreadyPopulated = populatedCollection || populatedMap || populatedScalarValue;
530+
boolean propertyAlreadyPopulated = populatedCollection || populatedMap || populatedScalarValue;
530531

531-
// avoid unnecessary re-assignment of values
532-
if (propertyAlreadyPopulated) {
533-
return;
534-
}
532+
// avoid unnecessary re-assignment of values
533+
if (propertyAlreadyPopulated) {
534+
return;
535535
}
536536

537537
createInstanceOfRelationships(persistentProperty, queryResult, (RelationshipDescription) association, relationshipsFromResult, nodesFromResult, null)
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)