From c1c77c0cd22df3c1721183f726d02cd17d74bffb Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Wed, 28 Mar 2018 07:19:49 +0200 Subject: [PATCH] DATAJPA-1300 - Detection of EclipseLink through Proxies. For parameter binding we check the JPA provider in order to work around some limitations of EclipseLink. This check now works even when the Query instance under consideration is wrapped in a Proxy if that proxy exposes it's delegate upon call of unwrap(null). This is the behavior of SharedEntityManagerCreator.DeferredQueryInvocationHandler. I wasn't able to properly test this because it would require mocking getClass or actually coding a Query implementation in an org.eclipse package. Original pull request: #264. --- .../query/QueryParameterSetter.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetter.java b/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetter.java index cee43558e..cd506b372 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetter.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetter.java @@ -17,6 +17,7 @@ package org.springframework.data.jpa.repository.query; import static org.springframework.data.jpa.repository.query.QueryParameterSetter.ErrorHandling.*; +import java.lang.reflect.Proxy; import java.util.Date; import java.util.function.Function; @@ -50,6 +51,8 @@ interface QueryParameterSetter { */ class NamedOrIndexedQueryParameterSetter implements QueryParameterSetter { + private static final Logger LOGGER = LoggerFactory.getLogger(NamedOrIndexedQueryParameterSetter.class); + private final Function valueExtractor; private final Parameter parameter; private final @Nullable TemporalType temporalType; @@ -133,7 +136,28 @@ interface QueryParameterSetter { // parameters in the query. // https://bugs.eclipse.org/bugs/show_bug.cgi?id=521915 - return query.getParameters().size() == 0 && query.getClass().getName().startsWith("org.eclipse"); + return query.getParameters().size() == 0 && unwrapClass(query).getName().startsWith("org.eclipse"); + } + + /** + * Returns the actual target Query instance, even if the provided query is a {@link Proxy} based on + * {@link org.springframework.orm.jpa.SharedEntityManagerCreator.DeferredQueryInvocationHandler}. + * + * @param query a Query instance, possibly a Proxy. + * @return the class of the actual underlying class if it can be determined, the class of the passed in instance + * otherwise. + */ + private Class unwrapClass(Query query) { + + try { + + return query instanceof Proxy ? query.unwrap(null).getClass() : query.getClass(); + } catch (RuntimeException e) { + + LOGGER.warn("Failed to unwrap actual class for Query proxy.", e); + + return query.getClass(); + } } }