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.
This commit is contained in:
Jens Schauder
2018-03-28 07:19:49 +02:00
committed by Oliver Gierke
parent d5231a14b3
commit c1c77c0cd2

View File

@@ -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<Object[], Object> 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();
}
}
}