Skip to content

Commit 60dd429

Browse files
michael-simonsmeistermeier
authored andcommitted
GH-2603 - Upgrade to Neo4j Java Driver 5.x.
This is the first of two changes in SDN 7 regarding Neo4j 5: It brings in the new driver 5.0.0 and adapts to its new API in two steps: - All calls to deprecateed API are replaced to the new API where possible. - All calls to `id()` are isolated in a separate utility class - The internal ID generator now logs a warning when used A follow up change will introduce a new internal id generator supporting the new element ids. Nothing is changed internally, SDN still relies on the long id values. Closes #2603
1 parent 3848ec5 commit 60dd429

File tree

101 files changed

+1449
-894
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+1449
-894
lines changed

pom.xml

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
<cdi>3.0.1</cdi>
7777
<checkstyle.skip>${skipTests}</checkstyle.skip>
7878
<checkstyle.version>8.40</checkstyle.version>
79-
<cypher-dsl.version>2022.4.0</cypher-dsl.version>
79+
<cypher-dsl.version>2022.6.0</cypher-dsl.version>
8080
<dist.id>spring-data-neo4j</dist.id>
8181
<dist.key>SDNEO4J</dist.key>
8282
<flatten-maven-plugin.version>1.2.5</flatten-maven-plugin.version>
@@ -104,8 +104,9 @@
104104
<maven.compiler.release>${java.version}</maven.compiler.release>
105105
<mockito>${mockito.version}</mockito>
106106
<mockito.version>4.4.0</mockito.version>
107-
<neo4j-java-driver.version>4.4.9</neo4j-java-driver.version>
108-
<neo4j.version>4.3.6</neo4j.version>
107+
<neo4j-java-driver.version>5.0.0</neo4j-java-driver.version>
108+
<neo4j-migrations.version>1.8.1</neo4j-migrations.version>
109+
<neo4j.version>4.4.8</neo4j.version>
109110
<objenesis.version>3.0.1</objenesis.version>
110111
<project.build.docs>${project.build.directory}/docs</project.build.docs>
111112
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -238,6 +239,16 @@
238239
<artifactId>jackson-databind</artifactId>
239240
<scope>test</scope>
240241
</dependency>
242+
<dependency>
243+
<!-- Including this explicitly in test scope makes
244+
[WARNING] unknown enum constant When.MAYBE
245+
[WARNING] reason: class file for javax.annotation.meta.When not found
246+
go away
247+
-->
248+
<groupId>com.google.code.findbugs</groupId>
249+
<artifactId>jsr305</artifactId>
250+
<scope>test</scope>
251+
</dependency>
241252
<dependency>
242253
<groupId>com.querydsl</groupId>
243254
<artifactId>querydsl-core</artifactId>
@@ -255,6 +266,12 @@
255266
<artifactId>junit-jupiter-causal-cluster-testcontainer-extension</artifactId>
256267
<scope>test</scope>
257268
</dependency>
269+
<dependency>
270+
<groupId>eu.michael-simons.neo4j</groupId>
271+
<artifactId>neo4j-migrations</artifactId>
272+
<version>${neo4j-migrations.version}</version>
273+
<scope>test</scope>
274+
</dependency>
258275
<dependency>
259276
<groupId>io.mockk</groupId>
260277
<artifactId>mockk-jvm</artifactId>
@@ -739,16 +756,25 @@
739756
<artifactId>maven-compiler-plugin</artifactId>
740757
<executions>
741758
<execution>
742-
<goals>
743-
<goal>compile</goal>
744-
</goals>
759+
<id>java-compile</id>
745760
<configuration combine.self="append">
746761
<compilerArgs>
747762
<arg>-Xlint:all,-options,-path</arg>
748763
<arg>-Werror</arg>
749764
</compilerArgs>
750765
</configuration>
751766
</execution>
767+
<execution>
768+
<!-- You would think that applying above configuration to java-test-compile would have the same result.
769+
Alas, it doesn't. The build just fails, -e -X doesn't show anything sane.
770+
So, showDeprecation is just warnings, if set to errors, than it fails hard (which is nice for
771+
deprecation, but it also fails during missing When.MAYBE whateever Jakarta annotation
772+
and there's just no motiviation to deal with Spring Data Commons build setup in this project -->
773+
<id>java-test-compile</id>
774+
<configuration combine.self="append">
775+
<showDeprecation>true</showDeprecation>
776+
</configuration>
777+
</execution>
752778
</executions>
753779
</plugin>
754780
</plugins>

src/main/java/org/springframework/data/neo4j/core/DefaultNeo4jClient.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,13 @@ public QueryRunner getQueryRunner(DatabaseSelection databaseSelection, UserSelec
9999
}
100100
}
101101

102-
return new DelegatingQueryRunner(queryRunner, lastBookmarks, (usedBookmarks, newBookmark) -> {
102+
return new DelegatingQueryRunner(queryRunner, lastBookmarks, (usedBookmarks, newBookmarks) -> {
103103

104104
ReentrantReadWriteLock.WriteLock lock = bookmarksLock.writeLock();
105105
try {
106106
lock.lock();
107107
bookmarks.removeAll(usedBookmarks);
108-
bookmarks.add(newBookmark);
108+
bookmarks.addAll(newBookmarks);
109109
} finally {
110110
lock.unlock();
111111
}
@@ -116,24 +116,23 @@ private static class DelegatingQueryRunner implements QueryRunner {
116116

117117
private final QueryRunner delegate;
118118
private final Collection<Bookmark> usedBookmarks;
119-
private final BiConsumer<Collection<Bookmark>, Bookmark> newBookmarkConsumer;
119+
private final BiConsumer<Collection<Bookmark>, Collection<Bookmark>> newBookmarkConsumer;
120120

121-
private DelegatingQueryRunner(QueryRunner delegate, Collection<Bookmark> lastBookmarks, BiConsumer<Collection<Bookmark>, Bookmark> newBookmarkConsumer) {
121+
private DelegatingQueryRunner(QueryRunner delegate, Collection<Bookmark> lastBookmarks, BiConsumer<Collection<Bookmark>, Collection<Bookmark>> newBookmarkConsumer) {
122122
this.delegate = delegate;
123123
this.usedBookmarks = lastBookmarks;
124124
this.newBookmarkConsumer = newBookmarkConsumer;
125125
}
126126

127127
@Override
128-
public void close() throws Exception {
128+
public void close() {
129129

130130
// We're only going to close sessions we have acquired inside the client, not something that
131131
// has been retrieved from the tx manager.
132-
if (this.delegate instanceof Session) {
132+
if (this.delegate instanceof Session session) {
133133

134-
Session session = (Session) this.delegate;
135134
session.close();
136-
this.newBookmarkConsumer.accept(usedBookmarks, session.lastBookmark());
135+
this.newBookmarkConsumer.accept(usedBookmarks, session.lastBookmarks());
137136
}
138137
}
139138

src/main/java/org/springframework/data/neo4j/core/DefaultReactiveNeo4jClient.java

Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
import org.neo4j.driver.Query;
2121
import org.neo4j.driver.Record;
2222
import org.neo4j.driver.Value;
23-
import org.neo4j.driver.reactive.RxQueryRunner;
24-
import org.neo4j.driver.reactive.RxResult;
25-
import org.neo4j.driver.reactive.RxSession;
23+
import org.neo4j.driver.reactive.ReactiveQueryRunner;
24+
import org.neo4j.driver.reactive.ReactiveResult;
25+
import org.neo4j.driver.reactive.ReactiveSession;
2626
import org.neo4j.driver.summary.ResultSummary;
2727
import org.neo4j.driver.types.TypeSystem;
2828
import org.springframework.core.convert.ConversionService;
@@ -36,6 +36,7 @@
3636
import org.springframework.util.Assert;
3737
import org.springframework.util.StringUtils;
3838

39+
import reactor.adapter.JdkFlowAdapter;
3940
import reactor.core.publisher.Flux;
4041
import reactor.core.publisher.Mono;
4142
import reactor.util.function.Tuple2;
@@ -47,6 +48,7 @@
4748
import java.util.Map;
4849
import java.util.Optional;
4950
import java.util.Set;
51+
import java.util.concurrent.Flow.Publisher;
5052
import java.util.concurrent.locks.ReentrantReadWriteLock;
5153
import java.util.function.BiConsumer;
5254
import java.util.function.BiFunction;
@@ -86,42 +88,42 @@ final class DefaultReactiveNeo4jClient implements ReactiveNeo4jClient {
8688
}
8789

8890
@Override
89-
public Mono<RxQueryRunner> getQueryRunner(Mono<DatabaseSelection> databaseSelection, Mono<UserSelection> userSelection) {
91+
public Mono<ReactiveQueryRunner> getQueryRunner(Mono<DatabaseSelection> databaseSelection, Mono<UserSelection> userSelection) {
9092

9193
return databaseSelection.zipWith(userSelection)
9294
.flatMap(targetDatabaseAndUser ->
93-
ReactiveNeo4jTransactionManager.retrieveReactiveTransaction(driver, targetDatabaseAndUser.getT1(), targetDatabaseAndUser.getT2())
94-
.map(RxQueryRunner.class::cast)
95-
.zipWith(Mono.just(Collections.<Bookmark>emptySet()))
96-
.switchIfEmpty(Mono.fromSupplier(() -> {
97-
ReentrantReadWriteLock.ReadLock lock = bookmarksLock.readLock();
98-
try {
99-
lock.lock();
100-
Set<Bookmark> lastBookmarks = new HashSet<>(bookmarks);
101-
return Tuples.of(driver.rxSession(Neo4jTransactionUtils.sessionConfig(false, lastBookmarks, targetDatabaseAndUser.getT1(), targetDatabaseAndUser.getT2())), lastBookmarks);
102-
} finally {
103-
lock.unlock();
104-
}
105-
})))
106-
.map(t -> new DelegatingQueryRunner(t.getT1(), t.getT2(), (usedBookmarks, newBookmark) -> {
95+
ReactiveNeo4jTransactionManager.retrieveReactiveTransaction(driver, targetDatabaseAndUser.getT1(), targetDatabaseAndUser.getT2())
96+
.map(ReactiveQueryRunner.class::cast)
97+
.zipWith(Mono.just(Collections.<Bookmark>emptySet()))
98+
.switchIfEmpty(Mono.fromSupplier(() -> {
99+
ReentrantReadWriteLock.ReadLock lock = bookmarksLock.readLock();
100+
try {
101+
lock.lock();
102+
Set<Bookmark> lastBookmarks = new HashSet<>(bookmarks);
103+
return Tuples.of(driver.reactiveSession(Neo4jTransactionUtils.sessionConfig(false, lastBookmarks, targetDatabaseAndUser.getT1(), targetDatabaseAndUser.getT2())), lastBookmarks);
104+
} finally {
105+
lock.unlock();
106+
}
107+
})))
108+
.map(t -> new DelegatingQueryRunner(t.getT1(), t.getT2(), (usedBookmarks, newBookmarks) -> {
107109
ReentrantReadWriteLock.WriteLock lock = bookmarksLock.writeLock();
108110
try {
109111
lock.lock();
110112
bookmarks.removeAll(usedBookmarks);
111-
bookmarks.add(newBookmark);
113+
bookmarks.addAll(newBookmarks);
112114
} finally {
113115
lock.unlock();
114116
}
115117
}));
116118
}
117119

118-
private static class DelegatingQueryRunner implements RxQueryRunner {
120+
private static class DelegatingQueryRunner implements ReactiveQueryRunner {
119121

120-
private final RxQueryRunner delegate;
122+
private final ReactiveQueryRunner delegate;
121123
private final Collection<Bookmark> usedBookmarks;
122-
private final BiConsumer<Collection<Bookmark>, Bookmark> newBookmarkConsumer;
124+
private final BiConsumer<Collection<Bookmark>, Collection<Bookmark>> newBookmarkConsumer;
123125

124-
private DelegatingQueryRunner(RxQueryRunner delegate, Collection<Bookmark> lastBookmarks, BiConsumer<Collection<Bookmark>, Bookmark> newBookmarkConsumer) {
126+
private DelegatingQueryRunner(ReactiveQueryRunner delegate, Collection<Bookmark> lastBookmarks, BiConsumer<Collection<Bookmark>, Collection<Bookmark>> newBookmarkConsumer) {
125127
this.delegate = delegate;
126128
this.usedBookmarks = lastBookmarks;
127129
this.newBookmarkConsumer = newBookmarkConsumer;
@@ -131,47 +133,46 @@ Mono<Void> close() {
131133

132134
// We're only going to close sessions we have acquired inside the client, not something that
133135
// has been retrieved from the tx manager.
134-
if (this.delegate instanceof RxSession) {
135-
RxSession session = (RxSession) this.delegate;
136-
return Mono.fromDirect(session.close()).then().doOnSuccess(signal ->
137-
this.newBookmarkConsumer.accept(usedBookmarks, session.lastBookmark()));
136+
if (this.delegate instanceof ReactiveSession session) {
137+
return JdkFlowAdapter.flowPublisherToFlux(session.close()).then().doOnSuccess(signal ->
138+
this.newBookmarkConsumer.accept(usedBookmarks, session.lastBookmarks()));
138139
}
139140

140141
return Mono.empty();
141142
}
142143

143144
@Override
144-
public RxResult run(String query, Value parameters) {
145+
public Publisher<ReactiveResult> run(String query, Value parameters) {
145146
return delegate.run(query, parameters);
146147
}
147148

148149
@Override
149-
public RxResult run(String query, Map<String, Object> parameters) {
150+
public Publisher<ReactiveResult> run(String query, Map<String, Object> parameters) {
150151
return delegate.run(query, parameters);
151152
}
152153

153154
@Override
154-
public RxResult run(String query, Record parameters) {
155+
public Publisher<ReactiveResult> run(String query, Record parameters) {
155156
return delegate.run(query, parameters);
156157
}
157158

158159
@Override
159-
public RxResult run(String query) {
160+
public Publisher<ReactiveResult> run(String query) {
160161
return delegate.run(query);
161162
}
162163

163164
@Override
164-
public RxResult run(Query query) {
165+
public Publisher<ReactiveResult> run(Query query) {
165166
return delegate.run(query);
166167
}
167168
}
168169

169-
<T> Mono<T> doInQueryRunnerForMono(Mono<DatabaseSelection> databaseSelection, Mono<UserSelection> userSelection, Function<RxQueryRunner, Mono<T>> func) {
170+
<T> Mono<T> doInQueryRunnerForMono(Mono<DatabaseSelection> databaseSelection, Mono<UserSelection> userSelection, Function<ReactiveQueryRunner, Mono<T>> func) {
170171

171172
return Mono.usingWhen(getQueryRunner(databaseSelection, userSelection), func, runner -> ((DelegatingQueryRunner) runner).close());
172173
}
173174

174-
<T> Flux<T> doInStatementRunnerForFlux(Mono<DatabaseSelection> databaseSelection, Mono<UserSelection> userSelection, Function<RxQueryRunner, Flux<T>> func) {
175+
<T> Flux<T> doInStatementRunnerForFlux(Mono<DatabaseSelection> databaseSelection, Mono<UserSelection> userSelection, Function<ReactiveQueryRunner, Flux<T>> func) {
175176

176177
return Flux.usingWhen(getQueryRunner(databaseSelection, userSelection), func, runner -> ((DelegatingQueryRunner) runner).close());
177178
}
@@ -187,7 +188,7 @@ public UnboundRunnableSpec query(Supplier<String> cypherSupplier) {
187188
}
188189

189190
@Override
190-
public <T> OngoingDelegation<T> delegateTo(Function<RxQueryRunner, Mono<T>> callback) {
191+
public <T> OngoingDelegation<T> delegateTo(Function<ReactiveQueryRunner, Mono<T>> callback) {
191192
return new DefaultRunnableDelegation<>(callback);
192193
}
193194

@@ -415,27 +416,27 @@ Mono<Tuple2<String, Map<String, Object>>> prepareStatement() {
415416
return Mono.fromSupplier(cypherSupplier).zipWith(Mono.just(parameters.get()));
416417
}
417418

418-
Flux<T> executeWith(Tuple2<String, Map<String, Object>> t, RxQueryRunner runner) {
419+
Flux<T> executeWith(Tuple2<String, Map<String, Object>> t, ReactiveQueryRunner runner) {
419420

420-
return Flux.usingWhen(Flux.just(runner.run(t.getT1(), t.getT2())),
421-
result -> Flux.from(result.records()).mapNotNull(r -> mappingFunction.apply(typeSystem, r)),
422-
result -> Flux.from(result.consume()).doOnNext(ResultSummaries::process));
421+
return Flux.usingWhen(JdkFlowAdapter.flowPublisherToFlux(runner.run(t.getT1(), t.getT2())),
422+
result -> JdkFlowAdapter.flowPublisherToFlux(result.records()).mapNotNull(r -> mappingFunction.apply(typeSystem, r)),
423+
result -> JdkFlowAdapter.flowPublisherToFlux(result.consume()).doOnNext(ResultSummaries::process));
423424
}
424425

425426
@Override
426427
public Mono<T> one() {
427428

428429
return doInQueryRunnerForMono(databaseSelection, userSelection,
429-
(runner) -> prepareStatement().flatMapMany(t -> executeWith(t, runner)).singleOrEmpty())
430-
.onErrorMap(RuntimeException.class, DefaultReactiveNeo4jClient.this::potentiallyConvertRuntimeException);
430+
(runner) -> prepareStatement().flatMapMany(t -> executeWith(t, runner)).singleOrEmpty()
431+
.onErrorMap(RuntimeException.class, DefaultReactiveNeo4jClient.this::potentiallyConvertRuntimeException));
431432
}
432433

433434
@Override
434435
public Mono<T> first() {
435436

436437
return doInQueryRunnerForMono(databaseSelection, userSelection,
437438
runner -> prepareStatement().flatMapMany(t -> executeWith(t, runner)).next())
438-
.onErrorMap(RuntimeException.class, DefaultReactiveNeo4jClient.this::potentiallyConvertRuntimeException);
439+
.onErrorMap(RuntimeException.class, DefaultReactiveNeo4jClient.this::potentiallyConvertRuntimeException);
439440
}
440441

441442
@Override
@@ -448,10 +449,10 @@ public Flux<T> all() {
448449

449450
Mono<ResultSummary> run() {
450451

451-
return doInQueryRunnerForMono(databaseSelection, userSelection, runner -> prepareStatement().flatMap(t -> {
452-
RxResult rxResult = runner.run(t.getT1(), t.getT2());
453-
return Flux.from(rxResult.records()).then(Mono.from(rxResult.consume()).map(ResultSummaries::process));
454-
})).onErrorMap(RuntimeException.class, DefaultReactiveNeo4jClient.this::potentiallyConvertRuntimeException);
452+
return doInQueryRunnerForMono(databaseSelection, userSelection, runner -> prepareStatement()
453+
.flatMap(t -> JdkFlowAdapter.flowPublisherToFlux(runner.run(t.getT1(), t.getT2())).single())
454+
.flatMap(rxResult -> JdkFlowAdapter.flowPublisherToFlux(rxResult.consume()).single().map(ResultSummaries::process)))
455+
.onErrorMap(RuntimeException.class, DefaultReactiveNeo4jClient.this::potentiallyConvertRuntimeException);
455456
}
456457
}
457458

@@ -469,12 +470,12 @@ private RuntimeException potentiallyConvertRuntimeException(RuntimeException ex)
469470

470471
class DefaultRunnableDelegation<T> implements RunnableDelegation<T>, OngoingDelegation<T> {
471472

472-
private final Function<RxQueryRunner, Mono<T>> callback;
473+
private final Function<ReactiveQueryRunner, Mono<T>> callback;
473474

474475
private Mono<DatabaseSelection> databaseSelection;
475-
private Mono<UserSelection> userSelection;
476+
private final Mono<UserSelection> userSelection;
476477

477-
DefaultRunnableDelegation(Function<RxQueryRunner, Mono<T>> callback) {
478+
DefaultRunnableDelegation(Function<ReactiveQueryRunner, Mono<T>> callback) {
478479
this.callback = callback;
479480
this.databaseSelection = resolveTargetDatabaseName(null);
480481
this.userSelection = resolveUser(null);

0 commit comments

Comments
 (0)