Skip to content

Commit 2301ad8

Browse files
GH-2367 - Remove AutoCloseableQueryRunner proxy.
Closes #2367, delegating is the nicer choice for all driver versions. For 6.1.x and below, we still need to expose the type, as 4.2.x drivers class hierachy is slightly different.
1 parent 53cb12c commit 2301ad8

File tree

2 files changed

+51
-38
lines changed

2 files changed

+51
-38
lines changed

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

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

18-
import java.lang.reflect.InvocationHandler;
19-
import java.lang.reflect.InvocationTargetException;
20-
import java.lang.reflect.Method;
21-
import java.lang.reflect.Proxy;
2218
import java.util.Collection;
2319
import java.util.Map;
2420
import java.util.Optional;
@@ -28,10 +24,12 @@
2824
import java.util.stream.Collectors;
2925

3026
import org.neo4j.driver.Driver;
27+
import org.neo4j.driver.Query;
3128
import org.neo4j.driver.QueryRunner;
3229
import org.neo4j.driver.Record;
3330
import org.neo4j.driver.Result;
3431
import org.neo4j.driver.Session;
32+
import org.neo4j.driver.Value;
3533
import org.neo4j.driver.summary.ResultSummary;
3634
import org.neo4j.driver.types.TypeSystem;
3735
import org.springframework.core.convert.ConversionService;
@@ -71,49 +69,57 @@ class DefaultNeo4jClient implements Neo4jClient {
7169
new Neo4jConversions().registerConvertersIn((ConverterRegistry) conversionService);
7270
}
7371

74-
AutoCloseableQueryRunner getQueryRunner(@Nullable final String targetDatabase) {
72+
DelegatingQueryRunner getQueryRunner(@Nullable final String targetDatabase) {
7573

7674
QueryRunner queryRunner = Neo4jTransactionManager.retrieveTransaction(driver, targetDatabase);
7775
if (queryRunner == null) {
7876
queryRunner = driver.session(Neo4jTransactionUtils.defaultSessionConfig(targetDatabase));
7977
}
8078

81-
return (AutoCloseableQueryRunner) Proxy.newProxyInstance(this.getClass().getClassLoader(),
82-
new Class<?>[] { AutoCloseableQueryRunner.class }, new AutoCloseableQueryRunnerHandler(queryRunner));
79+
return new DelegatingQueryRunner(queryRunner);
8380
}
8481

85-
/**
86-
* Makes a query runner automatically closeable and aware whether it's session or a transaction
87-
*/
88-
interface AutoCloseableQueryRunner extends QueryRunner, AutoCloseable {
82+
static class DelegatingQueryRunner implements QueryRunner, AutoCloseable {
83+
84+
private final QueryRunner delegate;
85+
86+
DelegatingQueryRunner(QueryRunner delegate) {
87+
this.delegate = delegate;
88+
}
8989

9090
@Override
91-
void close();
92-
}
91+
public void close() {
9392

94-
static class AutoCloseableQueryRunnerHandler implements InvocationHandler {
93+
// We're only going to close sessions we have acquired inside the client, not something that
94+
// has been retrieved from the tx manager.
95+
if (this.delegate instanceof Session) {
96+
((Session) this.delegate).close();
97+
}
98+
}
9599

96-
private final QueryRunner target;
100+
@Override
101+
public Result run(String s, Value value) {
102+
return delegate.run(s, value);
103+
}
97104

98-
AutoCloseableQueryRunnerHandler(QueryRunner target) {
99-
this.target = target;
105+
@Override
106+
public Result run(String s, Map<String, Object> map) {
107+
return delegate.run(s, map);
100108
}
101109

102110
@Override
103-
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
111+
public Result run(String s, Record record) {
112+
return delegate.run(s, record);
113+
}
104114

105-
if ("close".equals(method.getName())) {
106-
if (this.target instanceof Session) {
107-
((Session) this.target).close();
108-
}
109-
return null;
110-
} else {
111-
try {
112-
return method.invoke(target, args);
113-
} catch (InvocationTargetException ite) {
114-
throw ite.getCause();
115-
}
116-
}
115+
@Override
116+
public Result run(String s) {
117+
return delegate.run(s);
118+
}
119+
120+
@Override
121+
public Result run(Query query) {
122+
return delegate.run(query);
117123
}
118124
}
119125

@@ -158,7 +164,7 @@ class RunnableStatement {
158164

159165
private final NamedParameters parameters;
160166

161-
protected final Result runWith(AutoCloseableQueryRunner statementRunner) {
167+
protected final Result runWith(QueryRunner statementRunner) {
162168
String statementTemplate = cypherSupplier.get();
163169

164170
if (cypherLog.isDebugEnabled()) {
@@ -256,7 +262,7 @@ public RecordFetchSpec<Map<String, Object>> fetch() {
256262
@Override
257263
public ResultSummary run() {
258264

259-
try (AutoCloseableQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
265+
try (DelegatingQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
260266
Result result = runnableStatement.runWith(statementRunner);
261267
return ResultSummaries.process(result.consume());
262268
} catch (RuntimeException e) {
@@ -305,7 +311,7 @@ public RecordFetchSpec<T> mappedBy(
305311
@Override
306312
public Optional<T> one() {
307313

308-
try (AutoCloseableQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
314+
try (DelegatingQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
309315
Result result = runnableStatement.runWith(statementRunner);
310316
Optional<T> optionalValue = result.hasNext() ?
311317
Optional.ofNullable(mappingFunction.apply(typeSystem, result.single())) :
@@ -320,7 +326,7 @@ public Optional<T> one() {
320326
@Override
321327
public Optional<T> first() {
322328

323-
try (AutoCloseableQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
329+
try (DelegatingQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
324330
Result result = runnableStatement.runWith(statementRunner);
325331
Optional<T> optionalValue = result.stream().map(partialMappingFunction(typeSystem)).findFirst();
326332
ResultSummaries.process(result.consume());
@@ -333,7 +339,7 @@ public Optional<T> first() {
333339
@Override
334340
public Collection<T> all() {
335341

336-
try (AutoCloseableQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
342+
try (DelegatingQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
337343
Result result = runnableStatement.runWith(statementRunner);
338344
Collection<T> values = result.stream().map(partialMappingFunction(typeSystem)).collect(Collectors.toList());
339345
ResultSummaries.process(result.consume());
@@ -376,8 +382,10 @@ public RunnableDelegation in(@Nullable @SuppressWarnings("HiddenField") String t
376382

377383
@Override
378384
public Optional<T> run() {
379-
try (AutoCloseableQueryRunner queryRunner = getQueryRunner(targetDatabase)) {
385+
try (DelegatingQueryRunner queryRunner = getQueryRunner(targetDatabase)) {
380386
return callback.apply(queryRunner);
387+
} catch (RuntimeException e) {
388+
throw potentiallyConvertRuntimeException(e, persistenceExceptionTranslator);
381389
}
382390
}
383391
}

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.neo4j.driver.reactive.RxSession;
4747
import org.neo4j.driver.reactive.RxTransaction;
4848
import org.neo4j.driver.types.TypeSystem;
49+
import org.springframework.data.neo4j.core.DefaultNeo4jClient.DelegatingQueryRunner;
4950
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
5051
import org.springframework.transaction.support.TransactionTemplate;
5152

@@ -92,8 +93,10 @@ void shouldCallCloseOnSession() {
9293

9394
// Make template acquire session
9495
DefaultNeo4jClient neo4jClient = new DefaultNeo4jClient(driver, null);
95-
try (DefaultNeo4jClient.AutoCloseableQueryRunner s = neo4jClient.getQueryRunner("aDatabase")) {
96+
try (DelegatingQueryRunner s = neo4jClient.getQueryRunner("aDatabase")) {
9697
s.run("MATCH (n) RETURN n");
98+
} catch (Exception e) {
99+
throw new RuntimeException(e);
97100
}
98101

99102
verify(driver).session(configArgumentCaptor.capture());
@@ -126,8 +129,10 @@ void shouldNotInvokeCloseOnTransaction() {
126129

127130
DefaultNeo4jClient neo4jClient = new DefaultNeo4jClient(driver, null);
128131
txTemplate.execute(tx -> {
129-
try (DefaultNeo4jClient.AutoCloseableQueryRunner s = neo4jClient.getQueryRunner(null)) {
132+
try (DelegatingQueryRunner s = neo4jClient.getQueryRunner(null)) {
130133
s.run("MATCH (n) RETURN n");
134+
} catch (Exception e) {
135+
throw new RuntimeException(e);
131136
}
132137
return null;
133138
});

0 commit comments

Comments
 (0)