#582 - Adopt to changes in Spring Data Neo4j 6.0.
This commit is contained in:
committed by
Mark Paluch
parent
740522ea07
commit
f1ffd424f7
@@ -21,17 +21,10 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.neo4j</groupId>
|
<groupId>org.neo4j.test</groupId>
|
||||||
<artifactId>neo4j-ogm-embedded-driver</artifactId>
|
<artifactId>neo4j-harness</artifactId>
|
||||||
<version>${neo4j-ogm.version}</version>
|
<version>3.5.18</version> <!-- We can switch this to 4.x when the examples are build with JDK 11. -->
|
||||||
<scope>runtime</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.neo4j</groupId>
|
|
||||||
<artifactId>neo4j</artifactId>
|
|
||||||
<version>3.1.0</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -16,17 +16,13 @@
|
|||||||
|
|
||||||
package example.springdata.neo4j;
|
package example.springdata.neo4j;
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
import java.util.HashMap;
|
||||||
import lombok.Getter;
|
import java.util.Map;
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import org.springframework.data.neo4j.core.schema.GeneratedValue;
|
||||||
import java.util.Set;
|
import org.springframework.data.neo4j.core.schema.Id;
|
||||||
|
import org.springframework.data.neo4j.core.schema.Node;
|
||||||
import org.neo4j.ogm.annotation.GeneratedValue;
|
import org.springframework.data.neo4j.core.schema.Relationship;
|
||||||
import org.neo4j.ogm.annotation.Id;
|
|
||||||
import org.neo4j.ogm.annotation.NodeEntity;
|
|
||||||
import org.neo4j.ogm.annotation.Relationship;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Actor node entity.
|
* An Actor node entity.
|
||||||
@@ -35,14 +31,12 @@ import org.neo4j.ogm.annotation.Relationship;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Michael J. Simons
|
* @author Michael J. Simons
|
||||||
*/
|
*/
|
||||||
@NodeEntity(label = "Actor")
|
@Node
|
||||||
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
|
|
||||||
@Getter
|
|
||||||
public class Actor {
|
public class Actor {
|
||||||
|
|
||||||
private @Id @GeneratedValue Long id;
|
private @Id @GeneratedValue Long id;
|
||||||
private String name;
|
private final String name;
|
||||||
private @Relationship(type = "ACTED_IN") Set<Role> roles = new HashSet<>();
|
private @Relationship(type = "ACTED_IN") Map<Movie, Roles> roles = new HashMap<>();
|
||||||
|
|
||||||
public Actor(String name) {
|
public Actor(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -50,9 +44,30 @@ public class Actor {
|
|||||||
|
|
||||||
public void actedIn(Movie movie, String roleName) {
|
public void actedIn(Movie movie, String roleName) {
|
||||||
|
|
||||||
Role role = new Role(this, roleName, movie);
|
Roles movieRoles = this.roles.computeIfAbsent(movie, m -> new Roles());
|
||||||
|
movieRoles.addRole(roleName);
|
||||||
|
movie.getActors().put(this, movieRoles);
|
||||||
|
}
|
||||||
|
|
||||||
roles.add(role);
|
public Long getId() {
|
||||||
movie.getRoles().add(role);
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Movie, Roles> getRoles() {
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoles(Map<Movie, Roles> roles) {
|
||||||
|
this.roles = roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String toString() {
|
||||||
|
return "Actor{" +
|
||||||
|
"name='" + name + '\'' +
|
||||||
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package example.springdata.neo4j;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.data.neo4j.repository.Neo4jRepository;
|
import org.springframework.data.neo4j.repository.Neo4jRepository;
|
||||||
|
import org.springframework.data.neo4j.repository.query.Query;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Neo4jRepository} for {@link Actor actors}.
|
* {@link Neo4jRepository} for {@link Actor actors}.
|
||||||
@@ -28,11 +29,11 @@ import org.springframework.data.neo4j.repository.Neo4jRepository;
|
|||||||
public interface ActorRepository extends Neo4jRepository<Actor, Long> {
|
public interface ActorRepository extends Neo4jRepository<Actor, Long> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nested property from select from roles -> movie -> title, where this here represents the start node in a
|
* Custom query to navigate over relationships with properties.
|
||||||
* relationship and movie the end node.
|
|
||||||
*
|
*
|
||||||
* @param title
|
* @param title
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@Query("MATCH (a:Actor) - [r:ACTED_IN] -> (m:Movie {title: $title}) RETURN a, collect(r), collect(m)")
|
||||||
List<Actor> findAllByRolesMovieTitle(String title);
|
List<Actor> findAllByRolesMovieTitle(String title);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2018 the original author or authors.
|
* Copyright 2015-2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,17 +16,14 @@
|
|||||||
|
|
||||||
package example.springdata.neo4j;
|
package example.springdata.neo4j;
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
import java.util.HashMap;
|
||||||
import lombok.Getter;
|
import java.util.Map;
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import org.springframework.data.neo4j.core.schema.GeneratedValue;
|
||||||
import java.util.Set;
|
import org.springframework.data.neo4j.core.schema.Id;
|
||||||
|
import org.springframework.data.neo4j.core.schema.Node;
|
||||||
import org.neo4j.ogm.annotation.GeneratedValue;
|
import org.springframework.data.neo4j.core.schema.Relationship;
|
||||||
import org.neo4j.ogm.annotation.Id;
|
import org.springframework.data.neo4j.core.schema.Relationship.Direction;
|
||||||
import org.neo4j.ogm.annotation.NodeEntity;
|
|
||||||
import org.neo4j.ogm.annotation.Relationship;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Movie node entity.
|
* A Movie node entity.
|
||||||
@@ -35,16 +32,38 @@ import org.neo4j.ogm.annotation.Relationship;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Michael J. Simons
|
* @author Michael J. Simons
|
||||||
*/
|
*/
|
||||||
@NodeEntity(label = "Movie")
|
@Node
|
||||||
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
|
|
||||||
@Getter
|
|
||||||
public class Movie {
|
public class Movie {
|
||||||
|
|
||||||
private @Id @GeneratedValue Long id;
|
private @Id @GeneratedValue Long id;
|
||||||
private String title;
|
|
||||||
private @Relationship(type = "ACTED_IN", direction = "INCOMING") Set<Role> roles = new HashSet<>();
|
private final String title;
|
||||||
|
private @Relationship(type = "ACTED_IN", direction = Direction.INCOMING)
|
||||||
|
Map<Actor, Roles> actors = new HashMap<>();
|
||||||
|
|
||||||
public Movie(String title) {
|
public Movie(String title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Actor, Roles> getActors() {
|
||||||
|
return actors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActors(Map<Actor, Roles> actors) {
|
||||||
|
this.actors = actors;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String toString() {
|
||||||
|
return "Movie{" +
|
||||||
|
"title='" + title + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2018 the original author or authors.
|
* Copyright 2015-2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,15 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.neo4j;
|
package example.springdata.neo4j;
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
import java.util.ArrayList;
|
||||||
import lombok.Getter;
|
import java.util.Collections;
|
||||||
import lombok.NoArgsConstructor;
|
import java.util.List;
|
||||||
|
|
||||||
import org.neo4j.ogm.annotation.EndNode;
|
import org.springframework.data.annotation.PersistenceConstructor;
|
||||||
import org.neo4j.ogm.annotation.GeneratedValue;
|
import org.springframework.data.neo4j.core.schema.RelationshipProperties;
|
||||||
import org.neo4j.ogm.annotation.Id;
|
|
||||||
import org.neo4j.ogm.annotation.RelationshipEntity;
|
|
||||||
import org.neo4j.ogm.annotation.StartNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Role relationship entity between an actor and movie.
|
* A Role relationship entity between an actor and movie.
|
||||||
@@ -31,19 +28,27 @@ import org.neo4j.ogm.annotation.StartNode;
|
|||||||
* @author Luanne Misquitta
|
* @author Luanne Misquitta
|
||||||
* @author Michael J. Simons
|
* @author Michael J. Simons
|
||||||
*/
|
*/
|
||||||
@RelationshipEntity(type = "ACTED_IN")
|
@RelationshipProperties
|
||||||
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
|
public class Roles {
|
||||||
@Getter
|
|
||||||
public class Role {
|
|
||||||
|
|
||||||
private @Id @GeneratedValue Long id;
|
private final List<String> roles;
|
||||||
private @StartNode Actor actor;
|
|
||||||
private String role;
|
|
||||||
private @EndNode Movie movie;
|
|
||||||
|
|
||||||
Role(Actor actor, String role, Movie movie) {
|
public Roles() {
|
||||||
this.actor = actor;
|
this(Collections.emptyList());
|
||||||
this.role = role;
|
}
|
||||||
this.movie = movie;
|
|
||||||
|
@PersistenceConstructor
|
||||||
|
public Roles(List<String> roles) {
|
||||||
|
this.roles = new ArrayList<>(roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getRoles() {
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRole(String role) {
|
||||||
|
if (!this.roles.contains(role)) {
|
||||||
|
roles.add(role);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2018 the original author or authors.
|
* Copyright 2015-2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,21 +15,17 @@
|
|||||||
*/
|
*/
|
||||||
package example.springdata.neo4j;
|
package example.springdata.neo4j;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.Assume.*;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.Test;
|
import org.neo4j.harness.ServerControls;
|
||||||
import org.junit.runner.RunWith;
|
import org.neo4j.harness.TestServerBuilders;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.SpringBootVersion;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.data.util.Version;
|
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.DynamicPropertySource;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple integration test demonstrating the use of the ActorRepository
|
* Simple integration test demonstrating the use of the ActorRepository
|
||||||
@@ -38,18 +34,36 @@ import org.springframework.util.ClassUtils;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Michael J. Simons
|
* @author Michael J. Simons
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
@Transactional
|
class ActorRepositoryIntegrationTest {
|
||||||
public class ActorRepositoryIntegrationTest {
|
|
||||||
|
private static final ServerControls neo4j = TestServerBuilders
|
||||||
|
.newInProcessBuilder().newServer();
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void stopNeo4j() {
|
||||||
|
|
||||||
|
if (neo4j != null) {
|
||||||
|
neo4j.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DynamicPropertySource
|
||||||
|
static void neo4jProperties(DynamicPropertyRegistry registry) {
|
||||||
|
|
||||||
|
registry.add("spring.neo4j.uri", neo4j::boltURI);
|
||||||
|
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
|
||||||
|
registry.add("spring.neo4j.authentication.password", () -> "password");
|
||||||
|
}
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
static class ExampleConfig {}
|
static class ExampleConfig {
|
||||||
|
}
|
||||||
|
|
||||||
@Autowired ActorRepository actorRepository;
|
@Autowired ActorRepository actorRepository;
|
||||||
|
|
||||||
@Test // #131
|
@Test // #131
|
||||||
public void shouldBeAbleToSaveAndLoadActor() {
|
void shouldBeAbleToSaveAndLoadActor() {
|
||||||
|
|
||||||
Movie goblet = new Movie("Harry Potter and the Goblet of Fire");
|
Movie goblet = new Movie("Harry Potter and the Goblet of Fire");
|
||||||
|
|
||||||
@@ -60,15 +74,14 @@ public class ActorRepositoryIntegrationTest {
|
|||||||
|
|
||||||
assertThat(actorRepository.findById(daniel.getId())).hasValueSatisfying(actor -> {
|
assertThat(actorRepository.findById(daniel.getId())).hasValueSatisfying(actor -> {
|
||||||
assertThat(actor.getName()).isEqualTo(daniel.getName());
|
assertThat(actor.getName()).isEqualTo(daniel.getName());
|
||||||
assertThat(actor.getRoles()).hasSize(1).first()
|
assertThat(actor.getRoles()).hasSize(1)
|
||||||
.satisfies(role -> assertThat(role.getRole()).isEqualTo("Harry Potter"));
|
.satisfies(roles -> assertThat(roles.values()).flatExtracting(Roles::getRoles).hasSize(1).first()
|
||||||
|
.isEqualTo("Harry Potter"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // #386
|
@Test // #386
|
||||||
public void shouldBeAbleToHandleNestedProperties() {
|
void shouldBeAbleToHandleNestedProperties() {
|
||||||
|
|
||||||
assumeTrue(thatSupportForNestedPropertiesIsAvailable());
|
|
||||||
|
|
||||||
Movie theParentTrap = new Movie("The Parent Trap");
|
Movie theParentTrap = new Movie("The Parent Trap");
|
||||||
Movie iKnowWhoKilledMe = new Movie("I Know Who Killed Me");
|
Movie iKnowWhoKilledMe = new Movie("I Know Who Killed Me");
|
||||||
@@ -86,26 +99,16 @@ public class ActorRepositoryIntegrationTest {
|
|||||||
actorRepository.save(nealMcDonough);
|
actorRepository.save(nealMcDonough);
|
||||||
|
|
||||||
assertThat(actorRepository.findAllByRolesMovieTitle(iKnowWhoKilledMe.getTitle())).hasSize(2)
|
assertThat(actorRepository.findAllByRolesMovieTitle(iKnowWhoKilledMe.getTitle())).hasSize(2)
|
||||||
.extracting(Actor::getName).contains(lindsayLohan.getName(), nealMcDonough.getName());
|
.satisfies(actors -> assertThat(actors).extracting(Actor::getName)
|
||||||
}
|
.contains(lindsayLohan.getName(), nealMcDonough.getName()))
|
||||||
|
.allSatisfy(actor -> {
|
||||||
private static boolean thatSupportForNestedPropertiesIsAvailable() {
|
if (actor.getName().equals(nealMcDonough.getName())) {
|
||||||
|
assertThat(actor.getRoles())
|
||||||
Version minVersion = Version.parse("2.0.5");
|
.allSatisfy((m, r) -> assertThat(r.getRoles()).containsOnly("Daniel Fleming"));
|
||||||
|
} else if (actor.getName().equals(lindsayLohan.getName())) {
|
||||||
return Optional.ofNullable(SpringBootVersion.getVersion()).map(Version::parse) //
|
assertThat(actor.getRoles())
|
||||||
.map(v -> v.isGreaterThanOrEqualTo(minVersion)) //
|
.allSatisfy((m, r) -> assertThat(r.getRoles()).containsOnly("Aubrey Fleming", "Dakota Moss"));
|
||||||
.orElseGet(ActorRepositoryIntegrationTest::fallBackToVersionSpecificClasses);
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
private static boolean fallBackToVersionSpecificClasses() {
|
|
||||||
|
|
||||||
ClassLoader usedClassLoader = ActorRepositoryIntegrationTest.class.getClassLoader();
|
|
||||||
|
|
||||||
String fqnBoot210Class = "org.springframework.boot.autoconfigure.insight.InsightsProperties";
|
|
||||||
String fqnBoot205Class = "org.springframework.boot.autoconfigure.security.servlet.RequestMatcherProvider";
|
|
||||||
|
|
||||||
return ClassUtils.isPresent(fqnBoot210Class, usedClassLoader) //
|
|
||||||
|| ClassUtils.isPresent(fqnBoot205Class, usedClassLoader);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@@ -26,7 +26,7 @@
|
|||||||
<module>map</module>
|
<module>map</module>
|
||||||
<module>mongodb</module>
|
<module>mongodb</module>
|
||||||
<module>multi-store</module>
|
<module>multi-store</module>
|
||||||
<!-- <module>neo4j</module> -->
|
<module>neo4j</module>
|
||||||
<module>r2dbc</module>
|
<module>r2dbc</module>
|
||||||
<module>rest</module>
|
<module>rest</module>
|
||||||
<module>redis</module>
|
<module>redis</module>
|
||||||
|
|||||||
Reference in New Issue
Block a user