Skip to content

Commit d742694

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 b930e2f commit d742694

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;
@@ -69,49 +67,57 @@ class DefaultNeo4jClient implements Neo4jClient {
6967
new Neo4jConversions().registerConvertersIn((ConverterRegistry) conversionService);
7068
}
7169

72-
AutoCloseableQueryRunner getQueryRunner(@Nullable final String targetDatabase) {
70+
DelegatingQueryRunner getQueryRunner(@Nullable final String targetDatabase) {
7371

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

79-
return (AutoCloseableQueryRunner) Proxy.newProxyInstance(this.getClass().getClassLoader(),
80-
new Class<?>[] { AutoCloseableQueryRunner.class }, new AutoCloseableQueryRunnerHandler(queryRunner));
77+
return new DelegatingQueryRunner(queryRunner);
8178
}
8279

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

8888
@Override
89-
void close();
90-
}
89+
public void close() {
9190

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

94-
private final QueryRunner target;
98+
@Override
99+
public Result run(String s, Value value) {
100+
return delegate.run(s, value);
101+
}
95102

96-
AutoCloseableQueryRunnerHandler(QueryRunner target) {
97-
this.target = target;
103+
@Override
104+
public Result run(String s, Map<String, Object> map) {
105+
return delegate.run(s, map);
98106
}
99107

100108
@Override
101-
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
109+
public Result run(String s, Record record) {
110+
return delegate.run(s, record);
111+
}
102112

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

@@ -151,7 +157,7 @@ class RunnableStatement {
151157

152158
private final NamedParameters parameters;
153159

154-
protected final Result runWith(AutoCloseableQueryRunner statementRunner) {
160+
protected final Result runWith(QueryRunner statementRunner) {
155161
String statementTemplate = cypherSupplier.get();
156162

157163
if (cypherLog.isDebugEnabled()) {
@@ -248,7 +254,7 @@ public RecordFetchSpec<Map<String, Object>> fetch() {
248254
@Override
249255
public ResultSummary run() {
250256

251-
try (AutoCloseableQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
257+
try (DelegatingQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
252258
Result result = runnableStatement.runWith(statementRunner);
253259
return ResultSummaries.process(result.consume());
254260
} catch (RuntimeException e) {
@@ -283,7 +289,7 @@ public RecordFetchSpec<T> mappedBy(
283289
@Override
284290
public Optional<T> one() {
285291

286-
try (AutoCloseableQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
292+
try (DelegatingQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
287293
Result result = runnableStatement.runWith(statementRunner);
288294
Optional<T> optionalValue = result.hasNext() ?
289295
Optional.ofNullable(mappingFunction.apply(typeSystem, result.single())) :
@@ -298,7 +304,7 @@ public Optional<T> one() {
298304
@Override
299305
public Optional<T> first() {
300306

301-
try (AutoCloseableQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
307+
try (DelegatingQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
302308
Result result = runnableStatement.runWith(statementRunner);
303309
Optional<T> optionalValue = result.stream().map(partialMappingFunction(typeSystem)).findFirst();
304310
ResultSummaries.process(result.consume());
@@ -311,7 +317,7 @@ public Optional<T> first() {
311317
@Override
312318
public Collection<T> all() {
313319

314-
try (AutoCloseableQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
320+
try (DelegatingQueryRunner statementRunner = getQueryRunner(this.targetDatabase)) {
315321
Result result = runnableStatement.runWith(statementRunner);
316322
Collection<T> values = result.stream().map(partialMappingFunction(typeSystem)).collect(Collectors.toList());
317323
ResultSummaries.process(result.consume());
@@ -354,8 +360,10 @@ public RunnableDelegation in(@Nullable @SuppressWarnings("HiddenField") String t
354360

355361
@Override
356362
public Optional<T> run() {
357-
try (AutoCloseableQueryRunner queryRunner = getQueryRunner(targetDatabase)) {
363+
try (DelegatingQueryRunner queryRunner = getQueryRunner(targetDatabase)) {
358364
return callback.apply(queryRunner);
365+
} catch (RuntimeException e) {
366+
throw potentiallyConvertRuntimeException(e, persistenceExceptionTranslator);
359367
}
360368
}
361369
}

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);
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);
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)