diff --git a/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java b/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java index 1c9eb844b..ac181bbf4 100644 --- a/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java +++ b/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java @@ -18,6 +18,7 @@ package org.springframework.data.jpa.provider; import static org.springframework.data.jpa.provider.JpaClassUtils.*; import static org.springframework.data.jpa.provider.PersistenceProvider.Constants.*; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -43,7 +44,9 @@ import org.hibernate.proxy.HibernateProxy; import org.springframework.data.util.CloseableIterator; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.ConcurrentReferenceHashMap; +import org.springframework.util.ReflectionUtils; /** * Enumeration representing persistence providers to be used. @@ -401,6 +404,11 @@ public enum PersistenceProvider implements QueryExtractor,ProxyIdAccessor { */ private static class HibernateScrollableResultsIterator implements CloseableIterator { + private static final Method READ_ONLY_METHOD = ClassUtils.getMethod(org.hibernate.Query.class, "setReadOnly", + boolean.class); + private static final Method SCROLL_METHOD = ClassUtils.getMethod(READ_ONLY_METHOD.getReturnType(), "scroll", + ScrollMode.class); + private final ScrollableResults scrollableResults; /** @@ -411,9 +419,18 @@ public enum PersistenceProvider implements QueryExtractor,ProxyIdAccessor { public HibernateScrollableResultsIterator(Query jpaQuery) { org.hibernate.Query query = jpaQuery.unwrap(org.hibernate.Query.class); + boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); - this.scrollableResults = query.setReadOnly(TransactionSynchronizationManager.isCurrentTransactionReadOnly()) - .scroll(ScrollMode.FORWARD_ONLY); + if (READ_ONLY_METHOD.getReturnType().equals(org.hibernate.Query.class)) { + + this.scrollableResults = query.setReadOnly(isReadOnly).scroll(ScrollMode.FORWARD_ONLY); + + } else { + + Object intermediate = ReflectionUtils.invokeMethod(READ_ONLY_METHOD, jpaQuery, isReadOnly); + this.scrollableResults = (ScrollableResults) ReflectionUtils.invokeMethod(SCROLL_METHOD, intermediate, + ScrollMode.FORWARD_ONLY); + } } /* diff --git a/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java b/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java index c748caa5d..f67a2ba39 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java @@ -81,6 +81,7 @@ public abstract class QueryUtils { private static final Pattern ALIAS_MATCH; private static final Pattern COUNT_MATCH; + private static final Pattern NO_DIGITS = Pattern.compile("\\D+"); private static final String IDENTIFIER = "[\\p{Lu}\\P{InBASIC_LATIN}\\p{Alnum}._$]+"; private static final String IDENTIFIER_GROUP = String.format("(%s)", IDENTIFIER); @@ -386,7 +387,11 @@ public abstract class QueryUtils { public static boolean hasNamedParameter(Query query) { for (Parameter parameter : query.getParameters()) { - if (parameter.getName() != null) { + + String name = parameter.getName(); + + // Hibernate 3 specific hack as it returns the index as String for the name. + if (name != null && NO_DIGITS.matcher(name).find()) { return true; } } diff --git a/src/main/java/org/springframework/data/jpa/repository/query/StringQueryParameterBinder.java b/src/main/java/org/springframework/data/jpa/repository/query/StringQueryParameterBinder.java index b792d311a..0a27b6e81 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/StringQueryParameterBinder.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/StringQueryParameterBinder.java @@ -71,6 +71,10 @@ public class StringQueryParameterBinder extends ParameterBinder { */ private ParameterBinding getBindingFor(Query jpaQuery, int position, Parameter methodParameter) { + if (hasNamedParameter(jpaQuery)) { + return query.getBindingFor(methodParameter.getName()); + } + try { jpaQuery.getParameter(position); @@ -78,15 +82,11 @@ public class StringQueryParameterBinder extends ParameterBinder { } catch (IllegalArgumentException o_O) { - if (hasNamedParameter(jpaQuery)) { - return query.getBindingFor(methodParameter.getName()); - } + // We should actually reject parameters unavailable, but as EclipseLink doesn't implement ….getParameter(int) for + // native queries correctly we need to fall back to an indexed parameter + // @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=427892 + + return new ParameterBinding(position); } - - // We should actually reject parameters unavailable, but as EclipseLink doesn't implement ….getParameter(int) for - // native queries correctly we need to fall back to an indexed parameter - // @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=427892 - - return new ParameterBinding(position); } }