From dfb9d7a42820511df63eba566b5ad9e49adc2847 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Thu, 10 Mar 2022 12:12:02 +0100 Subject: [PATCH] Polishing. Replaced type check by method providing the correct JpaParameterParameterAccessor. Formatting. See #2370 Original pull request #2461 --- ...bernateJpaParametersParameterAccessor.java | 43 +++++---- .../jpa/provider/PersistenceProvider.java | 11 +++ .../repository/query/AbstractJpaQuery.java | 7 +- .../query/JpaParametersParameterAccessor.java | 2 +- .../JpaParametersParameterAccessorTests.java | 93 ++++++++++--------- 5 files changed, 84 insertions(+), 72 deletions(-) rename src/main/java/org/springframework/data/jpa/{repository/query => provider}/HibernateJpaParametersParameterAccessor.java (70%) diff --git a/src/main/java/org/springframework/data/jpa/repository/query/HibernateJpaParametersParameterAccessor.java b/src/main/java/org/springframework/data/jpa/provider/HibernateJpaParametersParameterAccessor.java similarity index 70% rename from src/main/java/org/springframework/data/jpa/repository/query/HibernateJpaParametersParameterAccessor.java rename to src/main/java/org/springframework/data/jpa/provider/HibernateJpaParametersParameterAccessor.java index 3054f27fe..e6aca458d 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/HibernateJpaParametersParameterAccessor.java +++ b/src/main/java/org/springframework/data/jpa/provider/HibernateJpaParametersParameterAccessor.java @@ -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,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.jpa.repository.query; +package org.springframework.data.jpa.provider; import javax.persistence.EntityManager; @@ -21,18 +21,21 @@ 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 +47,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); } } 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 23e0d9ea0..fa1a41c55 100644 --- a/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java +++ b/src/main/java/org/springframework/data/jpa/provider/PersistenceProvider.java @@ -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; @@ -114,6 +116,11 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor { public CloseableIterator executeQueryWithResultStream(Query jpaQuery) { return new HibernateScrollableResultsIterator(jpaQuery); } + + @Override + public JpaParametersParameterAccessor getParameterAccessor(JpaParameters parameters, Object[] values, EntityManager em) { + return new HibernateJpaParametersParameterAccessor(parameters, values, em); + } }, /** @@ -286,6 +293,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}. * diff --git a/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java index 821d1d342..99bc1f684 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java @@ -160,11 +160,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() { diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaParametersParameterAccessor.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaParametersParameterAccessor.java index f01dbdc69..787002340 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaParametersParameterAccessor.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaParametersParameterAccessor.java @@ -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); } diff --git a/src/test/java/org/springframework/data/jpa/repository/query/JpaParametersParameterAccessorTests.java b/src/test/java/org/springframework/data/jpa/repository/query/JpaParametersParameterAccessorTests.java index edc724b09..17ea638fe 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/JpaParametersParameterAccessorTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/JpaParametersParameterAccessorTests.java @@ -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 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 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); + } }