From af886623d907d7fa9fd1e702c003a45e07c9ce33 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Wed, 11 Dec 2019 21:52:17 +0100 Subject: [PATCH] DATAGRAPH-1276 - Explicitly Pass READ_ONLY mode to Session.query. --- .../transaction/SharedSessionCreator.java | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/transaction/SharedSessionCreator.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/transaction/SharedSessionCreator.java index e3a24f74d..a2f5df051 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/transaction/SharedSessionCreator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/transaction/SharedSessionCreator.java @@ -19,10 +19,12 @@ import static org.neo4j.ogm.transaction.Transaction.Status.*; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.lang.reflect.Proxy; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.function.Function; @@ -81,8 +83,12 @@ public class SharedSessionCreator { private final SessionFactory sessionFactory; + private final Method queryMethod; + public SharedSessionInvocationHandler(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; + this.queryMethod = ReflectionUtils + .findMethod(Session.class, "query", String.class, Map.class, boolean.class); } @Override @@ -102,14 +108,29 @@ public class SharedSessionCreator { return this.sessionFactory.metaData(); case "beginTransaction": throw new IllegalStateException( - "Not allowed to create transaction on shared Session - " + "use Spring transactions instead"); + "Not allowed to create transaction on shared Session - " + + "use Spring transactions instead"); default: - Function methodCall = targetSession -> ReflectionUtils.invokeMethod(method, targetSession, - args); + Function methodCall; + if (isGenericQueryMethod(method)) { + Object[] newArgs = new Object[args.length + 1]; + System.arraycopy(args, 0, newArgs, 0, args.length); + newArgs[newArgs.length - 1] = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); + methodCall = targetSession -> ReflectionUtils.invokeMethod(queryMethod, targetSession, newArgs); + } else { + methodCall = targetSession -> ReflectionUtils.invokeMethod(method, targetSession, args); + } return invokeInTransaction(methodName, methodCall); } } + private static boolean isGenericQueryMethod(Method method) { + + Parameter[] parameters = method.getParameters(); + return "query".equals(method.getName()) && method.getParameterCount() == 2 && + parameters[0].getType() == String.class && parameters[1].getType() == Map.class; + } + private Object invokeInTransaction(String methodName, Function methodCall) { // Determine current Session: either the transactional one @@ -118,8 +139,10 @@ public class SharedSessionCreator { if (TRANSACTION_REQUIRING_METHODS.contains(methodName)) { if (targetSession == null - || (!TransactionSynchronizationManager.isActualTransactionActive() && targetSession.getTransaction() != null - && EnumSet.of(CLOSED, COMMITTED, ROLLEDBACK).contains(targetSession.getTransaction().status()))) { + || (!TransactionSynchronizationManager.isActualTransactionActive() + && targetSession.getTransaction() != null + && EnumSet.of(CLOSED, COMMITTED, ROLLEDBACK) + .contains(targetSession.getTransaction().status()))) { throw new IllegalStateException("No Session with actual transaction available " + "for current thread - cannot reliably process '" + methodName + "' call"); }