From 4541e9c1c74ba80ff3c00c16ffdc218648bd1f82 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 d01c7b830..35fcd9f5f 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(); + } } }