Polishing.
Replaced type check by method providing the correct JpaParameterParameterAccessor. Formatting. See #2370 Original pull request #2461
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
* Copyright 2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,26 +13,28 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
package org.springframework.data.jpa.provider;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.TypeHelper;
|
||||
import org.hibernate.jpa.TypedParameterValue;
|
||||
import org.hibernate.type.Type;
|
||||
import org.springframework.data.jpa.repository.query.JpaParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
import org.springframework.data.repository.query.Parameters;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.data.repository.query.ParameterAccessor} based on an {@link Parameters} instance.
|
||||
* In addition to the {@link JpaParametersParameterAccessor} functions, the bindable value is provided by
|
||||
* fetching the method type when there is null.
|
||||
* {@link org.springframework.data.repository.query.ParameterAccessor} based on an {@link Parameters} instance. In
|
||||
* addition to the {@link JpaParametersParameterAccessor} functions, the bindable value is provided by fetching the
|
||||
* method type when there is null.
|
||||
*
|
||||
* @author Wonchul Heo
|
||||
* @author Jens Schauder
|
||||
* @since 2.7
|
||||
*/
|
||||
public class HibernateJpaParametersParameterAccessor extends JpaParametersParameterAccessor {
|
||||
class HibernateJpaParametersParameterAccessor extends JpaParametersParameterAccessor {
|
||||
|
||||
private final TypeHelper typeHelper;
|
||||
|
||||
@@ -44,25 +46,25 @@ public class HibernateJpaParametersParameterAccessor extends JpaParametersParame
|
||||
* @param em must not be {@literal null}.
|
||||
*/
|
||||
HibernateJpaParametersParameterAccessor(Parameters<?, ?> parameters, Object[] values, EntityManager em) {
|
||||
|
||||
super(parameters, values);
|
||||
|
||||
Session session = em.unwrap(Session.class);
|
||||
this.typeHelper = session.getSessionFactory().getTypeHelper();
|
||||
}
|
||||
|
||||
public Object getValue(Parameter parameter) {
|
||||
Object value = super.getValue(parameter.getIndex());
|
||||
if (value == null) {
|
||||
Type type = typeHelper.basic(parameter.getType());
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
return new TypedParameterValue(type, null);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getValues() {
|
||||
return super.getValues();
|
||||
public Object getValue(Parameter parameter) {
|
||||
|
||||
Object value = super.getValue(parameter.getIndex());
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Type type = typeHelper.basic(parameter.getType());
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
return new TypedParameterValue(type, null);
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,8 @@ import org.hibernate.ScrollMode;
|
||||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.springframework.data.jpa.repository.query.JpaParameters;
|
||||
import org.springframework.data.jpa.repository.query.JpaParametersParameterAccessor;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
@@ -98,6 +100,11 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
public CloseableIterator<Object> executeQueryWithResultStream(Query jpaQuery) {
|
||||
return new HibernateScrollableResultsIterator(jpaQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaParametersParameterAccessor getParameterAccessor(JpaParameters parameters, Object[] values, EntityManager em) {
|
||||
return new HibernateJpaParametersParameterAccessor(parameters, values, em);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -242,6 +249,10 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
return cacheAndReturn(metamodelType, GENERIC_JPA);
|
||||
}
|
||||
|
||||
public JpaParametersParameterAccessor getParameterAccessor(JpaParameters parameters, Object[] values, EntityManager em) {
|
||||
return new JpaParametersParameterAccessor(parameters, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the placeholder to be used for simple count queries. Default implementation returns {@code x}.
|
||||
*
|
||||
|
||||
@@ -152,11 +152,8 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
|
||||
}
|
||||
|
||||
private JpaParametersParameterAccessor obtainParameterAccessor(Object[] values) {
|
||||
if (provider == PersistenceProvider.HIBERNATE) {
|
||||
return new HibernateJpaParametersParameterAccessor(method.getParameters(), values, em);
|
||||
} else {
|
||||
return new JpaParametersParameterAccessor(method.getParameters(), values);
|
||||
}
|
||||
|
||||
return provider.getParameterAccessor(method.getParameters(), values, em);
|
||||
}
|
||||
|
||||
protected JpaQueryExecution getExecution() {
|
||||
|
||||
@@ -36,7 +36,7 @@ public class JpaParametersParameterAccessor extends ParametersParameterAccessor
|
||||
* @param parameters must not be {@literal null}.
|
||||
* @param values must not be {@literal null}.
|
||||
*/
|
||||
JpaParametersParameterAccessor(Parameters<?, ?> parameters, Object[] values) {
|
||||
public JpaParametersParameterAccessor(Parameters<?, ?> parameters, Object[] values) {
|
||||
super(parameters, values);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@@ -19,6 +17,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.data.jpa.domain.sample.User;
|
||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@@ -31,56 +30,58 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
class JpaParametersParameterAccessorTests {
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
private Query query;
|
||||
@PersistenceContext private EntityManager em;
|
||||
private Query query;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
query = mock(Query.class);
|
||||
}
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
query = mock(Query.class);
|
||||
}
|
||||
|
||||
@Test // GH-2370
|
||||
void createsJpaParametersParameterAccessor() throws Exception {
|
||||
@Test // GH-2370
|
||||
void createsJpaParametersParameterAccessor() throws Exception {
|
||||
|
||||
Method withNativeQuery = SampleRepository.class.getMethod("withNativeQuery", Integer.class);
|
||||
Object[] values = { null };
|
||||
JpaParameters parameters = new JpaParameters(withNativeQuery);
|
||||
JpaParametersParameterAccessor accessor = new JpaParametersParameterAccessor(parameters, values);
|
||||
Method withNativeQuery = SampleRepository.class.getMethod("withNativeQuery", Integer.class);
|
||||
Object[] values = { null };
|
||||
JpaParameters parameters = new JpaParameters(withNativeQuery);
|
||||
JpaParametersParameterAccessor accessor = PersistenceProvider.GENERIC_JPA.getParameterAccessor(parameters, values, em);
|
||||
|
||||
bind(parameters, accessor);
|
||||
bind(parameters, accessor);
|
||||
|
||||
verify(query).setParameter(eq(1), isNull());
|
||||
}
|
||||
verify(query).setParameter(eq(1), isNull());
|
||||
}
|
||||
|
||||
@Test // GH-2370
|
||||
void createsHibernateParametersParameterAccessor() throws Exception {
|
||||
@Test // GH-2370
|
||||
void createsHibernateParametersParameterAccessor() throws Exception {
|
||||
|
||||
Method withNativeQuery = SampleRepository.class.getMethod("withNativeQuery", Integer.class);
|
||||
Object[] values = { null };
|
||||
JpaParameters parameters = new JpaParameters(withNativeQuery);
|
||||
JpaParametersParameterAccessor accessor =
|
||||
new HibernateJpaParametersParameterAccessor(parameters, values, em);
|
||||
Method withNativeQuery = SampleRepository.class.getMethod("withNativeQuery", Integer.class);
|
||||
Object[] values = { null };
|
||||
JpaParameters parameters = new JpaParameters(withNativeQuery);
|
||||
JpaParametersParameterAccessor accessor = PersistenceProvider.HIBERNATE.getParameterAccessor(parameters, values,
|
||||
em);
|
||||
|
||||
bind(parameters, accessor);
|
||||
bind(parameters, accessor);
|
||||
|
||||
ArgumentCaptor<TypedParameterValue> captor = ArgumentCaptor.forClass(TypedParameterValue.class);
|
||||
verify(query).setParameter(eq(1), captor.capture());
|
||||
TypedParameterValue captorValue = captor.getValue();
|
||||
assertThat(captorValue.getType()).isEqualTo(StandardBasicTypes.INTEGER);
|
||||
assertThat(captorValue.getValue()).isNull();
|
||||
}
|
||||
ArgumentCaptor<TypedParameterValue> captor = ArgumentCaptor.forClass(TypedParameterValue.class);
|
||||
verify(query).setParameter(eq(1), captor.capture());
|
||||
TypedParameterValue captorValue = captor.getValue();
|
||||
assertThat(captorValue.getType()).isEqualTo(StandardBasicTypes.INTEGER);
|
||||
assertThat(captorValue.getValue()).isNull();
|
||||
}
|
||||
|
||||
private void bind(JpaParameters parameters, JpaParametersParameterAccessor accessor) {
|
||||
ParameterBinderFactory.createBinder(parameters).bind(QueryParameterSetter.BindableQuery.from(query),
|
||||
accessor,
|
||||
QueryParameterSetter.ErrorHandling.LENIENT);
|
||||
}
|
||||
private void bind(JpaParameters parameters, JpaParametersParameterAccessor accessor) {
|
||||
|
||||
interface SampleRepository {
|
||||
@org.springframework.data.jpa.repository.Query(
|
||||
value = "select 1 from user where age = :age",
|
||||
nativeQuery = true)
|
||||
User withNativeQuery(Integer age);
|
||||
}
|
||||
ParameterBinderFactory.createBinder(parameters)
|
||||
.bind( //
|
||||
QueryParameterSetter.BindableQuery.from(query), //
|
||||
accessor, //
|
||||
QueryParameterSetter.ErrorHandling.LENIENT //
|
||||
);
|
||||
}
|
||||
|
||||
interface SampleRepository {
|
||||
|
||||
@org.springframework.data.jpa.repository.Query(value = "select 1 from user where age = :age", nativeQuery = true)
|
||||
User withNativeQuery(Integer age);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user