Skip to content

Commit 6efee93

Browse files
committed
GH-2289 - Improved check for observe detection.
1 parent e25b138 commit 6efee93

File tree

3 files changed

+75
-10
lines changed

3 files changed

+75
-10
lines changed

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

+10-9
Original file line numberDiff line numberDiff line change
@@ -143,32 +143,33 @@ protected Association<Neo4jPersistentProperty> createAssociation() {
143143
}
144144
}
145145

146-
Relationship outgoingRelationship = this.findAnnotation(Relationship.class);
146+
Relationship relationship = this.findAnnotation(Relationship.class);
147147

148148
String type;
149-
if (outgoingRelationship != null && StringUtils.hasText(outgoingRelationship.type())) {
150-
type = outgoingRelationship.type();
149+
if (relationship != null && StringUtils.hasText(relationship.type())) {
150+
type = relationship.type();
151151
} else {
152152
type = deriveRelationshipType(this.getName());
153153
}
154154

155-
Relationship.Direction direction = Relationship.Direction.OUTGOING;
156-
if (outgoingRelationship != null) {
157-
direction = outgoingRelationship.direction();
158-
}
155+
Relationship.Direction direction = relationship != null
156+
? relationship.direction()
157+
: Relationship.Direction.OUTGOING;
159158

160159
// Try to determine if there is a relationship definition that expresses logically the same relationship
161160
// on the other end.
162161
Optional<RelationshipDescription> obverseRelationshipDescription = obverseOwner.getRelationships().stream()
163-
.filter(rel -> rel.getType().equals(type) && rel.getTarget().equals(this.getOwner())).findFirst();
162+
.filter(rel -> rel.getType().equals(type)
163+
&& rel.getTarget().equals(this.getOwner())
164+
&& rel.getDirection() == direction.inverse()).findFirst();
164165

165166
DefaultRelationshipDescription relationshipDescription = new DefaultRelationshipDescription(this,
166167
obverseRelationshipDescription.orElse(null), type, dynamicAssociation, (NodeDescription<?>) getOwner(),
167168
this.getName(), obverseOwner, direction, relationshipPropertiesClass);
168169

169170
// Update the previous found, if any, relationship with the newly created one as its counterpart.
170171
obverseRelationshipDescription
171-
.ifPresent(relationship -> relationship.setRelationshipObverse(relationshipDescription));
172+
.ifPresent(observeRelationship -> observeRelationship.setRelationshipObverse(relationshipDescription));
172173

173174
return relationshipDescription;
174175
}

src/main/java/org/springframework/data/neo4j/core/schema/Relationship.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ enum Direction {
5353
/**
5454
* Describes an incoming relationship.
5555
*/
56-
INCOMING
56+
INCOMING;
57+
58+
public Direction inverse() {
59+
return this == OUTGOING ? INCOMING : OUTGOING;
60+
}
5761
}
5862

5963
/**

src/test/java/org/springframework/data/neo4j/core/mapping/DefaultNeo4jPersistentEntityTest.java

+60
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.junit.jupiter.params.ParameterizedTest;
3131
import org.junit.jupiter.params.provider.ValueSource;
3232
import org.springframework.data.annotation.Transient;
33+
import org.springframework.data.mapping.AssociationHandler;
3334
import org.springframework.data.mapping.MappingException;
3435
import org.springframework.data.neo4j.core.schema.DynamicLabels;
3536
import org.springframework.data.neo4j.core.schema.GeneratedValue;
@@ -129,6 +130,26 @@ void doesFailOnRelationshipPropertiesWithMissingTargetNode() {
129130
.getPersistentEntity(EntityWithInCorrectRelationshipProperties.class))
130131
.withMessageContaining("Missing @TargetNode declaration in");
131132
}
133+
134+
@Test // DATAGRAPH-2289
135+
void correctlyFindRelationshipObverse() {
136+
Neo4jMappingContext neo4jMappingContext = new Neo4jMappingContext();
137+
Neo4jPersistentEntity<?> persistentEntity = neo4jMappingContext.getPersistentEntity(EntityWithBidirectionalRelationship.class);
138+
persistentEntity.doWithAssociations((AssociationHandler<Neo4jPersistentProperty>) a -> {
139+
RelationshipDescription rd = (RelationshipDescription) a;
140+
assertThat(rd.getRelationshipObverse()).isNotNull();
141+
});
142+
}
143+
144+
@Test // DATAGRAPH-2289
145+
void correctlyFindRelationshipObverseWithRelationshipProperties() {
146+
Neo4jMappingContext neo4jMappingContext = new Neo4jMappingContext();
147+
Neo4jPersistentEntity<?> persistentEntity = neo4jMappingContext.getPersistentEntity(EntityWithBidirectionalRelationshipProperties.class);
148+
persistentEntity.doWithAssociations((AssociationHandler<Neo4jPersistentProperty>) a -> {
149+
RelationshipDescription rd = (RelationshipDescription) a;
150+
assertThat(rd.getRelationshipObverse()).isNotNull();
151+
});
152+
}
132153
}
133154

134155
@Nested
@@ -491,4 +512,43 @@ static class HasNoTargetNodeRelationshipProperties {
491512
@Id @GeneratedValue
492513
private Long id;
493514
}
515+
516+
@Node
517+
static class EntityWithBidirectionalRelationship {
518+
519+
@Id @GeneratedValue
520+
private Long id;
521+
522+
@Relationship("KNOWS")
523+
List<EntityWithBidirectionalRelationship> knows;
524+
525+
@Relationship(type = "KNOWS" , direction = Relationship.Direction.INCOMING)
526+
List<EntityWithBidirectionalRelationship> knownBy;
527+
528+
}
529+
530+
@Node
531+
static class EntityWithBidirectionalRelationshipProperties {
532+
533+
@Id @GeneratedValue
534+
private Long id;
535+
536+
@Relationship("KNOWS")
537+
List<BidirectionalRelationshipProperties> knows;
538+
539+
@Relationship(type = "KNOWS" , direction = Relationship.Direction.INCOMING)
540+
List<BidirectionalRelationshipProperties> knownBy;
541+
542+
}
543+
544+
@RelationshipProperties
545+
static class BidirectionalRelationshipProperties {
546+
547+
@Id @GeneratedValue
548+
private Long id;
549+
550+
@TargetNode
551+
EntityWithBidirectionalRelationshipProperties target;
552+
}
553+
494554
}

0 commit comments

Comments
 (0)