Allow JpaParametersParameterAccessor to extract dates from parameters.

This allows the Hibernate variant (HibernateJpaParametersParameterAccessor) to potentially unwrap TypedParameterValue.

Closes #2857
Original pull request #2859
This commit is contained in:
Greg L. Turnquist
2023-03-14 15:09:32 -05:00
committed by Jens Schauder
parent e853a7a3a0
commit cf97015aa5
4 changed files with 48 additions and 16 deletions

View File

@@ -17,6 +17,8 @@ package org.springframework.data.jpa.provider;
import jakarta.persistence.EntityManager;
import java.util.Date;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.TypedParameterValue;
import org.hibernate.type.BasicTypeRegistry;
@@ -36,6 +38,7 @@ import org.springframework.lang.Nullable;
* @author Cedomir Igaly
* @author Robert Wilson
* @author Oliver Drotbohm
* @author Greg Turnquist
* @since 2.7
*/
class HibernateJpaParametersParameterAccessor extends JpaParametersParameterAccessor {
@@ -53,9 +56,9 @@ class HibernateJpaParametersParameterAccessor extends JpaParametersParameterAcce
super(parameters, values);
this.typeHelper = em.getEntityManagerFactory()
.unwrap(SessionFactoryImplementor.class)
.getTypeConfiguration()
this.typeHelper = em.getEntityManagerFactory() //
.unwrap(SessionFactoryImplementor.class) //
.getTypeConfiguration() //
.getBasicTypeRegistry();
}
@@ -78,4 +81,19 @@ class HibernateJpaParametersParameterAccessor extends JpaParametersParameterAcce
return new TypedParameterValue<>(type, null);
}
/**
* For Hibernate, check if the incoming value is wrapped inside a {@link TypedParameterValue} before extracting and
* casting the {@link Date}.
*
* @param extractedValue
* @since 3.1
*/
@Override
public Date extractDate(Object extractedValue) {
return (extractedValue instanceof TypedParameterValue<?> typedParameterValue)
? (Date) typedParameterValue.getValue()
: (Date) extractedValue;
}
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.jpa.repository.query;
import java.util.Date;
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.Parameters;
@@ -27,6 +29,7 @@ import org.springframework.lang.Nullable;
*
* @author Jens Schauder
* @author Mark Paluch
* @author Greg Turnquist
*/
public class JpaParametersParameterAccessor extends ParametersParameterAccessor {
@@ -49,4 +52,15 @@ public class JpaParametersParameterAccessor extends ParametersParameterAccessor
public Object[] getValues() {
return super.getValues();
}
/**
* For general JPA providers, simply pass through the extracted value, casting it as a {@link Date}.
*
* @param extractedValue
* @since 3.1
*/
public Date extractDate(Object extractedValue) {
return (Date) extractedValue;
}
}

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.jpa.repository.query;
import static org.springframework.data.jpa.repository.query.QueryParameterSetter.ErrorHandling.LENIENT;
import static org.springframework.data.jpa.repository.query.QueryParameterSetter.ErrorHandling.*;
import jakarta.persistence.Parameter;
import jakarta.persistence.Query;
@@ -32,7 +32,6 @@ import java.util.function.Function;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.query.TypedParameterValue;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -82,11 +81,9 @@ interface QueryParameterSetter {
if (temporalType != null) {
var extractedValue = valueExtractor.apply(accessor);
Object extractedValue = valueExtractor.apply(accessor);
final Date value = (extractedValue instanceof TypedParameterValue<?> typedParameterValue)
? (Date) typedParameterValue.getValue()
: (Date) extractedValue;
final Date value = accessor.extractDate(extractedValue);
// One would think we can simply use parameter to identify the parameter we want to set.
// But that does not work with list valued parameters. At least Hibernate tries to bind them by name.

View File

@@ -15,12 +15,16 @@
*/
package org.springframework.data.jpa.repository.query;
import static java.util.Arrays.*;
import static jakarta.persistence.TemporalType.*;
import static java.util.Arrays.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.jpa.repository.query.QueryParameterSetter.ErrorHandling.*;
import jakarta.persistence.Parameter;
import jakarta.persistence.Query;
import jakarta.persistence.TemporalType;
import jakarta.persistence.criteria.ParameterExpression;
import lombok.Value;
import java.util.Arrays;
@@ -29,11 +33,6 @@ import java.util.Date;
import java.util.List;
import java.util.function.Function;
import jakarta.persistence.Parameter;
import jakarta.persistence.Query;
import jakarta.persistence.TemporalType;
import jakarta.persistence.criteria.ParameterExpression;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -65,7 +64,11 @@ class NamedOrIndexedQueryParameterSetterUnitTests {
void before() {
JpaParametersParameterAccessor accessor = mock(JpaParametersParameterAccessor.class);
when(accessor.getValues()).thenReturn(new Object[] { new Date() });
Date testDate = new Date();
when(accessor.getValues()).thenReturn(new Object[] { testDate });
when(accessor.extractDate(testDate)).thenReturn(testDate);
this.methodArguments = accessor;
}