Skip to content

Commit 7d65de1

Browse files
michael-simonsmeistermeier
authored andcommitted
refactor: Upgrade to Driver 6, and test against last Neo4j 5.26 LTS release by default.
Signed-off-by: Michael Simons <michael@simons.ac>
1 parent a87f748 commit 7d65de1

File tree

10 files changed

+102
-109
lines changed

10 files changed

+102
-109
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
<maven-install-plugin.version>3.1.4</maven-install-plugin.version>
9898
<maven-site-plugin.version>3.7.1</maven-site-plugin.version>
9999
<maven.compiler.release>${java.version}</maven.compiler.release>
100-
<neo4j-java-driver.version>5.28.9</neo4j-java-driver.version>
100+
<neo4j-java-driver.version>6.0.0</neo4j-java-driver.version>
101101
<neo4j-migrations.version>2.17.3</neo4j-migrations.version>
102102
<neo4j.version>5.26.12</neo4j.version>
103103
<objenesis.version>3.0.1</objenesis.version>

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

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.neo4j.core;
1717

18+
import java.util.List;
1819
import java.util.function.Consumer;
1920
import java.util.function.Predicate;
2021
import java.util.regex.Pattern;
@@ -23,10 +24,9 @@
2324

2425
import org.apache.commons.logging.LogFactory;
2526
import org.jspecify.annotations.Nullable;
26-
import org.neo4j.driver.NotificationCategory;
27+
import org.neo4j.driver.NotificationClassification;
2728
import org.neo4j.driver.NotificationSeverity;
28-
import org.neo4j.driver.summary.InputPosition;
29-
import org.neo4j.driver.summary.Notification;
29+
import org.neo4j.driver.summary.GqlNotification;
3030
import org.neo4j.driver.summary.Plan;
3131
import org.neo4j.driver.summary.ResultSummary;
3232

@@ -66,8 +66,15 @@ final class ResultSummaries {
6666
private static final LogAccessor cypherTopologyNotificationLog = new LogAccessor(
6767
LogFactory.getLog("org.springframework.data.neo4j.cypher.topology"));
6868

69-
private static final Pattern DEPRECATED_ID_PATTERN = Pattern
70-
.compile("(?im)The query used a deprecated function[.:] \\(?[`']id.+");
69+
private static final LogAccessor cypherSchemaNotificationLog = new LogAccessor(
70+
LogFactory.getLog("org.springframework.data.neo4j.cypher.schema"));
71+
72+
private static final List<Pattern> STUFF_THAT_MIGHT_INFORM_THAT_THE_ID_FUNCTION_IS_PROBLEMATIC = Stream.of(
73+
"(?im)The query used a deprecated function[.:] \\(?[`']id.+",
74+
"(?im).*id is deprecated and will be removed without a replacement\\.",
75+
"(?im).*feature deprecated with replacement\\. id is deprecated\\. It is replaced by elementId or consider using an application-generated id\\.")
76+
.map(Pattern::compile)
77+
.toList();
7178

7279
private ResultSummaries() {
7380
}
@@ -86,29 +93,33 @@ static ResultSummary process(ResultSummary resultSummary) {
8693

8794
private static void logNotifications(ResultSummary resultSummary) {
8895

89-
if (resultSummary.notifications().isEmpty() || !Neo4jClient.cypherLog.isWarnEnabled()) {
96+
if (resultSummary.gqlStatusObjects().isEmpty() || !Neo4jClient.cypherLog.isWarnEnabled()) {
9097
return;
9198
}
9299

93100
boolean supressIdDeprecations = Neo4jClient.SUPPRESS_ID_DEPRECATIONS.getAcquire();
94-
Predicate<Notification> isDeprecationWarningForId;
101+
Predicate<GqlNotification> isDeprecationWarningForId;
95102
try {
96103
isDeprecationWarningForId = notification -> supressIdDeprecations
97-
&& notification.category()
98-
.orElse(NotificationCategory.UNRECOGNIZED)
99-
.equals(NotificationCategory.DEPRECATION)
100-
&& DEPRECATED_ID_PATTERN.matcher(notification.description()).matches();
104+
&& notification.classification()
105+
.filter(cat -> cat == NotificationClassification.UNRECOGNIZED
106+
|| cat == NotificationClassification.DEPRECATION)
107+
.isPresent()
108+
&& STUFF_THAT_MIGHT_INFORM_THAT_THE_ID_FUNCTION_IS_PROBLEMATIC.stream()
109+
.anyMatch(p -> p.matcher(notification.statusDescription()).matches());
101110
}
102111
finally {
103112
Neo4jClient.SUPPRESS_ID_DEPRECATIONS.setRelease(supressIdDeprecations);
104113
}
105114

106115
String query = resultSummary.query().text();
107-
resultSummary.notifications()
116+
resultSummary.gqlStatusObjects()
108117
.stream()
118+
.filter(GqlNotification.class::isInstance)
119+
.map(GqlNotification.class::cast)
109120
.filter(Predicate.not(isDeprecationWarningForId))
110-
.forEach(notification -> notification.severityLevel().ifPresent(severityLevel -> {
111-
var category = notification.category().orElse(null);
121+
.forEach(notification -> notification.severity().ifPresent(severityLevel -> {
122+
var category = notification.classification().orElse(null);
112123

113124
var logger = getLogAccessor(category);
114125
Consumer<String> logFunction;
@@ -130,35 +141,22 @@ else if (severityLevel == NotificationSeverity.OFF) {
130141
}));
131142
}
132143

133-
private static LogAccessor getLogAccessor(@Nullable NotificationCategory category) {
134-
if (category == null) {
144+
private static LogAccessor getLogAccessor(@Nullable NotificationClassification classification) {
145+
if (classification == null) {
135146
return Neo4jClient.cypherLog;
136147
}
137-
if (category.equals(NotificationCategory.HINT)) {
138-
return cypherHintNotificationLog;
139-
}
140-
else if (category.equals(NotificationCategory.DEPRECATION)) {
141-
return cypherDeprecationNotificationLog;
142-
}
143-
else if (category.equals(NotificationCategory.PERFORMANCE)) {
144-
return cypherPerformanceNotificationLog;
145-
}
146-
else if (category.equals(NotificationCategory.GENERIC)) {
147-
return cypherGenericNotificationLog;
148-
}
149-
else if (category.equals(NotificationCategory.UNSUPPORTED)) {
150-
return cypherUnsupportedNotificationLog;
151-
}
152-
else if (category.equals(NotificationCategory.UNRECOGNIZED)) {
153-
return cypherUnrecognizedNotificationLog;
154-
}
155-
else if (category.equals(NotificationCategory.SECURITY)) {
156-
return cypherSecurityNotificationLog;
157-
}
158-
else if (category.equals(NotificationCategory.TOPOLOGY)) {
159-
return cypherTopologyNotificationLog;
160-
}
161-
return Neo4jClient.cypherLog;
148+
149+
return switch (classification) {
150+
case HINT -> cypherHintNotificationLog;
151+
case UNRECOGNIZED -> cypherUnrecognizedNotificationLog;
152+
case UNSUPPORTED -> cypherUnsupportedNotificationLog;
153+
case PERFORMANCE -> cypherPerformanceNotificationLog;
154+
case DEPRECATION -> cypherDeprecationNotificationLog;
155+
case SECURITY -> cypherSecurityNotificationLog;
156+
case TOPOLOGY -> cypherTopologyNotificationLog;
157+
case GENERIC -> cypherGenericNotificationLog;
158+
case SCHEMA -> cypherSchemaNotificationLog;
159+
};
162160
}
163161

164162
/**
@@ -167,25 +165,23 @@ else if (category.equals(NotificationCategory.TOPOLOGY)) {
167165
* @param forQuery the query that caused the notification
168166
* @return a formatted string
169167
*/
170-
static String format(Notification notification, String forQuery) {
168+
static String format(GqlNotification notification, String forQuery) {
171169

172-
InputPosition position = notification.position();
173-
boolean hasPosition = position != null;
170+
var position = notification.position().orElse(null);
174171

175172
StringBuilder queryHint = new StringBuilder();
176173
String[] lines = forQuery.split("(\r\n|\n)");
177174
for (int i = 0; i < lines.length; i++) {
178175
String line = lines[i];
179176
queryHint.append("\t").append(line).append(LINE_SEPARATOR);
180-
if (hasPosition && i + 1 == position.line()) {
177+
if (position != null && i + 1 == position.line()) {
181178
queryHint.append("\t")
182179
.append(Stream.generate(() -> " ").limit(position.column() - 1).collect(Collectors.joining()))
183180
.append("^")
184181
.append(System.lineSeparator());
185182
}
186183
}
187-
return String.format("%s: %s%n%s%s", notification.code(), notification.title(), queryHint,
188-
notification.description());
184+
return String.format("%s (%s):%n%s", notification.statusDescription(), notification.gqlStatus(), queryHint);
189185
}
190186

191187
/**

src/main/java/org/springframework/data/neo4j/repository/query/AbstractNeo4jQuery.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import java.util.function.LongSupplier;
2424
import java.util.function.Supplier;
2525
import java.util.function.UnaryOperator;
26-
import java.util.stream.Collectors;
2726

2827
import org.jspecify.annotations.Nullable;
2928
import org.neo4j.driver.types.MapAccessor;
@@ -166,7 +165,7 @@ else if (geoNearQuery) {
166165
rawResult = newGeoResults(rawResult);
167166
}
168167
else if (this.queryMethod.isSearchQuery()) {
169-
rawResult = createSearchResult((List<?>) rawResult, returnedType.getReturnedType());
168+
rawResult = createSearchResult((List<?>) rawResult);
170169
}
171170

172171
return resultProcessor.processResult(rawResult, preparingConverter);
@@ -207,11 +206,9 @@ private Slice<?> createSlice(boolean incrementLimit, Neo4jParameterAccessor para
207206
}
208207
}
209208

210-
private <T> SearchResults<?> createSearchResult(List<?> rawResult, Class<T> returnedType) {
211-
List<SearchResult<T>> searchResults = rawResult.stream()
212-
.map(rawValue -> (SearchResult<T>) rawValue)
213-
.collect(Collectors.toUnmodifiableList());
214-
return new SearchResults<>(searchResults);
209+
@SuppressWarnings("unchecked")
210+
private <T> SearchResults<?> createSearchResult(List<?> rawResult) {
211+
return new SearchResults<>(rawResult.stream().map(rawValue -> (SearchResult<T>) rawValue).toList());
215212
}
216213

217214
protected abstract <T> PreparedQuery<T> prepareQuery(Class<T> returnedType,

src/test/java/org/springframework/data/neo4j/core/Neo4jClientTests.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ void databaseSelectionShouldWorkBeforeAsUser() {
141141
verify(this.session).run(eq(cypher), MockitoHamcrest.argThat(new MapAssertionMatcher(expectedParameters)));
142142
verify(this.result).stream();
143143
verify(this.result).consume();
144-
verify(this.resultSummary).notifications();
144+
verify(this.resultSummary).gqlStatusObjects();
145145
verify(this.resultSummary).hasPlan();
146146
verify(this.record1).asMap();
147147
verify(this.session).close();
@@ -181,7 +181,7 @@ void databaseSelectionShouldWorkAfterAsUser() {
181181
verify(this.session).run(eq(cypher), MockitoHamcrest.argThat(new MapAssertionMatcher(expectedParameters)));
182182
verify(this.result).stream();
183183
verify(this.result).consume();
184-
verify(this.resultSummary).notifications();
184+
verify(this.resultSummary).gqlStatusObjects();
185185
verify(this.resultSummary).hasPlan();
186186
verify(this.record1).asMap();
187187
verify(this.session).close();
@@ -220,7 +220,7 @@ void userSelectionShouldWork() {
220220
verify(this.session).run(eq(cypher), MockitoHamcrest.argThat(new MapAssertionMatcher(expectedParameters)));
221221
verify(this.result).stream();
222222
verify(this.result).consume();
223-
verify(this.resultSummary).notifications();
223+
verify(this.resultSummary).gqlStatusObjects();
224224
verify(this.resultSummary).hasPlan();
225225
verify(this.record1).asMap();
226226
verify(this.session).close();
@@ -268,7 +268,7 @@ void queryCreationShouldFeelGood() {
268268

269269
verify(this.result).stream();
270270
verify(this.result).consume();
271-
verify(this.resultSummary).notifications();
271+
verify(this.resultSummary).gqlStatusObjects();
272272
verify(this.resultSummary).hasPlan();
273273
verify(this.record1).asMap();
274274
verify(this.record2).asMap();
@@ -305,7 +305,7 @@ void databaseSelectionShouldBePossibleOnlyOnce() {
305305
verify(this.session).run(eq(cypher), MockitoHamcrest.argThat(new MapAssertionMatcher(expectedParameters)));
306306
verify(this.result).stream();
307307
verify(this.result).consume();
308-
verify(this.resultSummary).notifications();
308+
verify(this.resultSummary).gqlStatusObjects();
309309
verify(this.resultSummary).hasPlan();
310310
verify(this.record1).asMap();
311311
verify(this.session).close();
@@ -350,7 +350,7 @@ void databaseSelectionBeanShouldGetRespectedIfExisting() {
350350
verify(this.session).run(eq(query), anyMap());
351351
verify(this.result).stream();
352352
verify(this.result).consume();
353-
verify(this.resultSummary).notifications();
353+
verify(this.resultSummary).gqlStatusObjects();
354354
verify(this.resultSummary).hasPlan();
355355
verify(this.record1).asMap();
356356
verify(this.session).close();
@@ -379,7 +379,7 @@ void queriesWithoutResultShouldFitInAsWell() {
379379

380380
verify(this.session).run(eq(cypher), MockitoHamcrest.argThat(new MapAssertionMatcher(expectedParameters)));
381381
verify(this.result).consume();
382-
verify(this.resultSummary).notifications();
382+
verify(this.resultSummary).gqlStatusObjects();
383383
verify(this.resultSummary).hasPlan();
384384
verify(this.session).close();
385385
}
@@ -577,7 +577,7 @@ void reading() {
577577
MockitoHamcrest.argThat(new MapAssertionMatcher(expectedParameters)));
578578
verify(Neo4jClientTests.this.result).stream();
579579
verify(Neo4jClientTests.this.result).consume();
580-
verify(Neo4jClientTests.this.resultSummary).notifications();
580+
verify(Neo4jClientTests.this.resultSummary).gqlStatusObjects();
581581
verify(Neo4jClientTests.this.resultSummary).hasPlan();
582582
verify(Neo4jClientTests.this.record1).get("name");
583583
verify(Neo4jClientTests.this.session).close();
@@ -614,7 +614,7 @@ void shouldApplyNullChecksDuringReading() {
614614
MockitoHamcrest.argThat(new MapAssertionMatcher(Collections.emptyMap())));
615615
verify(Neo4jClientTests.this.result).stream();
616616
verify(Neo4jClientTests.this.result).consume();
617-
verify(Neo4jClientTests.this.resultSummary).notifications();
617+
verify(Neo4jClientTests.this.resultSummary).gqlStatusObjects();
618618
verify(Neo4jClientTests.this.resultSummary).hasPlan();
619619
verify(Neo4jClientTests.this.record1).get("name");
620620
verify(Neo4jClientTests.this.session).close();
@@ -646,7 +646,7 @@ void writing() {
646646
verify(Neo4jClientTests.this.session).run(eq(cypher),
647647
MockitoHamcrest.argThat(new MapAssertionMatcher(expectedParameters)));
648648
verify(Neo4jClientTests.this.result).consume();
649-
verify(Neo4jClientTests.this.resultSummary).notifications();
649+
verify(Neo4jClientTests.this.resultSummary).gqlStatusObjects();
650650
verify(Neo4jClientTests.this.resultSummary).hasPlan();
651651
verify(Neo4jClientTests.this.session).close();
652652
}
@@ -677,7 +677,7 @@ void automaticConversion() {
677677
verify(Neo4jClientTests.this.result).hasNext();
678678
verify(Neo4jClientTests.this.result).single();
679679
verify(Neo4jClientTests.this.result).consume();
680-
verify(Neo4jClientTests.this.resultSummary).notifications();
680+
verify(Neo4jClientTests.this.resultSummary).gqlStatusObjects();
681681
verify(Neo4jClientTests.this.resultSummary).hasPlan();
682682
verify(Neo4jClientTests.this.session).close();
683683
}

0 commit comments

Comments
 (0)