From f97434de2044fc0de65fba88b3121ac7dad999c5 Mon Sep 17 00:00:00 2001 From: Chirag Tailor Date: Thu, 7 Apr 2022 08:32:45 -0500 Subject: [PATCH] Update @Query argument conversion to handle Collection. + Copy logic from QueryMapper#convertToJdbcValue to resolve Iterable arguments on findBy* query methods to resolve the same for @Query. + Use parameter ResolvableType instead of Class to retain generics info. Original pull request #1226 Closes #1212 --- .../query/StringBasedJdbcQuery.java | 38 +++++- ...itoryCustomConversionIntegrationTests.java | 120 +++++++++++++++++- .../JdbcRepositoryIntegrationTests.java | 53 +++++++- .../query/StringBasedJdbcQueryUnitTests.java | 116 ++++++++++++++++- ...ryCustomConversionIntegrationTests-db2.sql | 2 +- ...oryCustomConversionIntegrationTests-h2.sql | 2 +- ...yCustomConversionIntegrationTests-hsql.sql | 2 +- ...stomConversionIntegrationTests-mariadb.sql | 2 +- ...CustomConversionIntegrationTests-mssql.sql | 2 +- ...CustomConversionIntegrationTests-mysql.sql | 2 +- ...ustomConversionIntegrationTests-oracle.sql | 3 +- ...tomConversionIntegrationTests-postgres.sql | 2 +- .../JdbcRepositoryIntegrationTests-db2.sql | 3 +- .../JdbcRepositoryIntegrationTests-h2.sql | 3 +- .../JdbcRepositoryIntegrationTests-hsql.sql | 3 +- ...JdbcRepositoryIntegrationTests-mariadb.sql | 3 +- .../JdbcRepositoryIntegrationTests-mssql.sql | 3 +- .../JdbcRepositoryIntegrationTests-mysql.sql | 3 +- .../JdbcRepositoryIntegrationTests-oracle.sql | 3 +- ...dbcRepositoryIntegrationTests-postgres.sql | 3 +- .../query/RelationalParameters.java | 12 ++ 21 files changed, 346 insertions(+), 34 deletions(-) diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java index 6f832525df..7d6cdf108e 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-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. @@ -19,9 +19,12 @@ import java.lang.reflect.Constructor; import java.sql.JDBCType; +import java.util.ArrayList; +import java.util.List; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactory; +import org.springframework.core.ResolvableType; import org.springframework.core.convert.converter.Converter; import org.springframework.data.jdbc.core.convert.JdbcColumnTypes; import org.springframework.data.jdbc.core.convert.JdbcConverter; @@ -29,6 +32,7 @@ import org.springframework.data.jdbc.support.JdbcUtil; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.repository.query.RelationalParameterAccessor; +import org.springframework.data.relational.repository.query.RelationalParameters; import org.springframework.data.relational.repository.query.RelationalParametersParameterAccessor; import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameters; @@ -53,6 +57,7 @@ * @author Maciej Walkowiak * @author Mark Paluch * @author Hebert Coelho + * @author Chirag Tailor * @since 2.0 */ public class StringBasedJdbcQuery extends AbstractJdbcQuery { @@ -157,11 +162,34 @@ private void convertAndAddParameter(MapSqlParameterSource parameters, Parameter String parameterName = p.getName().orElseThrow(() -> new IllegalStateException(PARAMETER_NEEDS_TO_BE_NAMED)); - Class parameterType = queryMethod.getParameters().getParameter(p.getIndex()).getType(); - Class conversionTargetType = JdbcColumnTypes.INSTANCE.resolvePrimitiveType(parameterType); + RelationalParameters.RelationalParameter parameter = queryMethod.getParameters().getParameter(p.getIndex()); + ResolvableType resolvableType = parameter.getResolvableType(); + Class type = resolvableType.resolve(); + Assert.notNull(type, "@Query parameter could not be resolved!"); - JdbcValue jdbcValue = converter.writeJdbcValue(value, conversionTargetType, - JdbcUtil.sqlTypeFor(conversionTargetType)); + JdbcValue jdbcValue; + if (value instanceof Iterable) { + + List mapped = new ArrayList<>(); + SQLType jdbcType = null; + + Class elementType = resolvableType.getGeneric(0).resolve(); + Assert.notNull(elementType, "@Query Iterable parameter generic type could not be resolved!"); + for (Object o : (Iterable) value) { + JdbcValue elementJdbcValue = converter.writeJdbcValue(o, elementType, + JdbcUtil.targetSqlTypeFor(JdbcColumnTypes.INSTANCE.resolvePrimitiveType(elementType))); + if (jdbcType == null) { + jdbcType = elementJdbcValue.getJdbcType(); + } + + mapped.add(elementJdbcValue.getValue()); + } + + jdbcValue = JdbcValue.of(mapped, jdbcType); + } else { + jdbcValue = converter.writeJdbcValue(value, type, + JdbcUtil.sqlTypeFor(JdbcColumnTypes.INSTANCE.resolvePrimitiveType(type))); + } JDBCType jdbcType = jdbcValue.getJdbcType(); if (jdbcType == null) { diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCustomConversionIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCustomConversionIntegrationTests.java index 790154e7dd..7e60739f82 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCustomConversionIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryCustomConversionIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2019-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. @@ -16,6 +16,7 @@ package org.springframework.data.jdbc.repository; import static java.util.Arrays.*; +import static java.util.Collections.*; import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.SoftAssertions.*; import static org.springframework.test.context.TestExecutionListeners.MergeMode.*; @@ -23,6 +24,7 @@ import java.math.BigDecimal; import java.sql.JDBCType; import java.util.Date; +import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -36,6 +38,7 @@ import org.springframework.data.convert.WritingConverter; import org.springframework.data.jdbc.core.convert.JdbcCustomConversions; import org.springframework.data.jdbc.core.convert.JdbcValue; +import org.springframework.data.jdbc.repository.query.Query; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.jdbc.testing.AssumeFeatureTestExecutionListener; import org.springframework.data.jdbc.testing.TestConfiguration; @@ -50,6 +53,7 @@ * * @author Jens Schauder * @author Sanghyuk Jung + * @author Chirag Tailor */ @ContextConfiguration @Transactional @@ -69,18 +73,19 @@ Class testClass() { } @Bean - EntityWithBooleanRepository repository() { - return factory.getRepository(EntityWithBooleanRepository.class); + EntityWithStringyBigDecimalRepository repository() { + return factory.getRepository(EntityWithStringyBigDecimalRepository.class); } @Bean JdbcCustomConversions jdbcCustomConversions() { return new JdbcCustomConversions(asList(StringToBigDecimalConverter.INSTANCE, BigDecimalToString.INSTANCE, - CustomIdReadingConverter.INSTANCE, CustomIdWritingConverter.INSTANCE)); + CustomIdReadingConverter.INSTANCE, CustomIdWritingConverter.INSTANCE, DirectionToIntegerConverter.INSTANCE, + NumberToDirectionConverter.INSTANCE, IntegerToDirectionConverter.INSTANCE)); } } - @Autowired EntityWithBooleanRepository repository; + @Autowired EntityWithStringyBigDecimalRepository repository; /** * In PostrgreSQL this fails if a simple converter like the following is used. @@ -143,13 +148,50 @@ public void saveAndLoadAnEntityWithReference() { }); } - interface EntityWithBooleanRepository extends CrudRepository {} + @Test // GH-1212 + void queryByEnumTypeIn() { + + EntityWithStringyBigDecimal entityA = new EntityWithStringyBigDecimal(); + entityA.direction = Direction.LEFT; + EntityWithStringyBigDecimal entityB = new EntityWithStringyBigDecimal(); + entityB.direction = Direction.CENTER; + EntityWithStringyBigDecimal entityC = new EntityWithStringyBigDecimal(); + entityC.direction = Direction.RIGHT; + repository.saveAll(asList(entityA, entityB, entityC)); + + assertThat(repository.findByEnumTypeIn(asList(Direction.LEFT, Direction.RIGHT))) + .extracting(entity -> entity.direction).containsExactlyInAnyOrder(Direction.LEFT, Direction.RIGHT); + } + + @Test // GH-1212 + void queryByEnumTypeEqual() { + + EntityWithStringyBigDecimal entityA = new EntityWithStringyBigDecimal(); + entityA.direction = Direction.LEFT; + EntityWithStringyBigDecimal entityB = new EntityWithStringyBigDecimal(); + entityB.direction = Direction.CENTER; + EntityWithStringyBigDecimal entityC = new EntityWithStringyBigDecimal(); + entityC.direction = Direction.RIGHT; + repository.saveAll(asList(entityA, entityB, entityC)); + + assertThat(repository.findByEnumTypeIn(singletonList(Direction.CENTER))).extracting(entity -> entity.direction) + .containsExactly(Direction.CENTER); + } + + interface EntityWithStringyBigDecimalRepository extends CrudRepository { + @Query("SELECT * FROM ENTITY_WITH_STRINGY_BIG_DECIMAL WHERE DIRECTION IN (:types)") + List findByEnumTypeIn(List types); + + @Query("SELECT * FROM ENTITY_WITH_STRINGY_BIG_DECIMAL WHERE DIRECTION = :type") + List findByEnumType(Direction type); + } private static class EntityWithStringyBigDecimal { @Id CustomId id; - String stringyNumber; + String stringyNumber = "1.0"; OtherEntity reference; + Direction direction = Direction.CENTER; } private static class CustomId { @@ -167,6 +209,10 @@ private static class OtherEntity { Date created; } + enum Direction { + LEFT, CENTER, RIGHT + } + @WritingConverter enum StringToBigDecimalConverter implements Converter { @@ -214,4 +260,64 @@ public CustomId convert(Number source) { } } + @WritingConverter + enum DirectionToIntegerConverter implements Converter { + + INSTANCE; + + @Override + public JdbcValue convert(Direction source) { + + int integer; + switch (source) { + case LEFT: + integer = -1; + break; + case CENTER: + integer = 0; + break; + case RIGHT: + integer = 1; + break; + default: + throw new IllegalArgumentException(); + } + return JdbcValue.of(integer, JDBCType.INTEGER); + } + } + + @ReadingConverter // Needed for Oracle since the JDBC driver returns BigDecimal on read + enum NumberToDirectionConverter implements Converter { + + INSTANCE; + + @Override + public Direction convert(Number source) { + int sourceAsInt = source.intValue(); + if (sourceAsInt == 0) { + return Direction.CENTER; + } else if (sourceAsInt < 0) { + return Direction.LEFT; + } else { + return Direction.RIGHT; + } + } + } + + @ReadingConverter + enum IntegerToDirectionConverter implements Converter { + + INSTANCE; + + @Override + public Direction convert(Integer source) { + if (source == 0) { + return Direction.CENTER; + } else if (source < 0) { + return Direction.LEFT; + } else { + return Direction.RIGHT; + } + } + } } diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java index 19684cc647..2568c92005 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java @@ -20,10 +20,6 @@ import static org.assertj.core.api.SoftAssertions.*; import static org.springframework.test.context.TestExecutionListeners.MergeMode.*; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.Value; - import java.io.IOException; import java.sql.ResultSet; import java.time.Instant; @@ -33,6 +29,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -73,11 +70,16 @@ import org.springframework.test.jdbc.JdbcTestUtils; import org.springframework.transaction.annotation.Transactional; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.Value; + /** * Very simple use cases for creation and usage of JdbcRepositories. * * @author Jens Schauder * @author Mark Paluch + * @author Chirag Tailor */ @Transactional @TestExecutionListeners(value = AssumeFeatureTestExecutionListener.class, mergeMode = MERGE_WITH_DEFAULTS) @@ -565,6 +567,38 @@ void nullStringResult() { assertThat(repository.returnInput(null)).isNull(); } + @Test // GH-1212 + void queryByEnumTypeIn() { + + DummyEntity dummyA = new DummyEntity("dummyA"); + dummyA.setDirection(Direction.LEFT); + DummyEntity dummyB = new DummyEntity("dummyB"); + dummyB.setDirection(Direction.CENTER); + DummyEntity dummyC = new DummyEntity("dummyC"); + dummyC.setDirection(Direction.RIGHT); + repository.saveAll(asList(dummyA, dummyB, dummyC)); + + assertThat(repository.findByEnumTypeIn(asList(Direction.LEFT, Direction.RIGHT))) + .extracting(DummyEntity::getDirection) + .containsExactlyInAnyOrder(Direction.LEFT, Direction.RIGHT); + } + + @Test // GH-1212 + void queryByEnumTypeEqual() { + + DummyEntity dummyA = new DummyEntity("dummyA"); + dummyA.setDirection(Direction.LEFT); + DummyEntity dummyB = new DummyEntity("dummyB"); + dummyB.setDirection(Direction.CENTER); + DummyEntity dummyC = new DummyEntity("dummyC"); + dummyC.setDirection(Direction.RIGHT); + repository.saveAll(asList(dummyA, dummyB, dummyC)); + + assertThat(repository.findByEnumType(Direction.CENTER)) + .extracting(DummyEntity::getDirection) + .containsExactlyInAnyOrder(Direction.CENTER); + } + private Instant createDummyBeforeAndAfterNow() { Instant now = Instant.now(); @@ -645,6 +679,12 @@ interface DummyEntityRepository extends CrudRepository { @Query("SELECT CAST(:hello AS CHAR(5)) FROM DUMMY_ENTITY") @Nullable String returnInput(@Nullable String hello); + + @Query("SELECT * FROM DUMMY_ENTITY WHERE DIRECTION IN (:directions)") + List findByEnumTypeIn(List directions); + + @Query("SELECT * FROM DUMMY_ENTITY WHERE DIRECTION = :direction") + List findByEnumType(Direction direction); } @Configuration @@ -698,12 +738,17 @@ static class DummyEntity { @Id private Long idProp; boolean flag; AggregateReference ref; + Direction direction; public DummyEntity(String name) { this.name = name; } } + enum Direction { + LEFT, CENTER, RIGHT + } + interface DummyProjection { String getName(); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java index 6e3a5d96bd..0370f2672c 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * Copyright 2020-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. @@ -15,28 +15,38 @@ */ package org.springframework.data.jdbc.repository.query; +import static java.util.Arrays.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import java.lang.reflect.Method; +import java.sql.JDBCType; import java.sql.ResultSet; import java.util.List; import java.util.Properties; +import java.util.Set; import java.util.stream.Stream; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; +import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; +import org.springframework.data.convert.ReadingConverter; +import org.springframework.data.convert.WritingConverter; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.jdbc.core.convert.BasicJdbcConverter; import org.springframework.data.jdbc.core.convert.JdbcConverter; +import org.springframework.data.jdbc.core.convert.JdbcCustomConversions; +import org.springframework.data.jdbc.core.convert.JdbcTypeFactory; import org.springframework.data.jdbc.core.convert.RelationResolver; +import org.springframework.data.jdbc.core.mapping.JdbcValue; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.relational.core.mapping.RelationalMappingContext; +import org.springframework.data.relational.core.sql.IdentifierProcessing; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries; @@ -55,6 +65,7 @@ * @author Evgeni Dimitrov * @author Mark Paluch * @author Dennis Effing + * @author Chirag Tailor */ class StringBasedJdbcQueryUnitTests { @@ -64,7 +75,7 @@ class StringBasedJdbcQueryUnitTests { JdbcConverter converter; @BeforeEach - void setup() throws NoSuchMethodException { + void setup() { this.defaultRowMapper = mock(RowMapper.class); this.operations = mock(NamedParameterJdbcOperations.class); @@ -172,6 +183,54 @@ void pageQueryNotSupported() { .hasMessageContaining("Page queries are not supported using string-based queries"); } + @Test // GH-1212 + void convertsEnumCollectionParameterIntoStringCollectionParameter() { + + JdbcQueryMethod queryMethod = createMethod("findByEnumTypeIn", Set.class); + BasicJdbcConverter converter = new BasicJdbcConverter(mock(RelationalMappingContext.class), mock(RelationResolver.class)); + StringBasedJdbcQuery query = new StringBasedJdbcQuery(queryMethod, operations, result -> mock(RowMapper.class), converter); + + query.execute(new Object[] { asList(Direction.LEFT, Direction.RIGHT) }); + + ArgumentCaptor captor = ArgumentCaptor.forClass(SqlParameterSource.class); + verify(operations).query(anyString(), captor.capture(), any(ResultSetExtractor.class)); + + SqlParameterSource sqlParameterSource = captor.getValue(); + assertThat(sqlParameterSource.getValue("directions")).asList().containsExactlyInAnyOrder("LEFT", "RIGHT"); + } + + @Test // GH-1212 + void convertsEnumCollectionParameterUsingCustomConverterWhenRegisteredForType() { + + JdbcQueryMethod queryMethod = createMethod("findByEnumTypeIn", Set.class); + BasicJdbcConverter converter = new BasicJdbcConverter(mock(RelationalMappingContext.class), mock(RelationResolver.class), new JdbcCustomConversions(asList(DirectionToIntegerConverter.INSTANCE, IntegerToDirectionConverter.INSTANCE)), JdbcTypeFactory.unsupported(), IdentifierProcessing.ANSI); + StringBasedJdbcQuery query = new StringBasedJdbcQuery(queryMethod, operations, result -> mock(RowMapper.class), converter); + + query.execute(new Object[] { asList(Direction.LEFT, Direction.RIGHT) }); + + ArgumentCaptor captor = ArgumentCaptor.forClass(SqlParameterSource.class); + verify(operations).query(anyString(), captor.capture(), any(ResultSetExtractor.class)); + + SqlParameterSource sqlParameterSource = captor.getValue(); + assertThat(sqlParameterSource.getValue("directions")).asList().containsExactlyInAnyOrder(-1, 1); + } + + @Test // GH-1212 + void doesNotConvertNonCollectionParameter() { + + JdbcQueryMethod queryMethod = createMethod("findBySimpleValue", Integer.class); + BasicJdbcConverter converter = new BasicJdbcConverter(mock(RelationalMappingContext.class), mock(RelationResolver.class)); + StringBasedJdbcQuery query = new StringBasedJdbcQuery(queryMethod, operations, result -> mock(RowMapper.class), converter); + + query.execute(new Object[] { 1 }); + + ArgumentCaptor captor = ArgumentCaptor.forClass(SqlParameterSource.class); + verify(operations).query(anyString(), captor.capture(), any(ResultSetExtractor.class)); + + SqlParameterSource sqlParameterSource = captor.getValue(); + assertThat(sqlParameterSource.getValue("value")).isEqualTo(1); + } + private JdbcQueryMethod createMethod(String methodName, Class... paramTypes) { Method method = ReflectionUtils.findMethod(MyRepository.class, methodName, paramTypes); @@ -212,6 +271,11 @@ interface MyRepository extends Repository { @Query(value = "some sql statement") Slice sliceAll(Pageable pageable); + @Query(value = "some sql statement") + List findByEnumTypeIn(Set directions); + + @Query(value = "some sql statement") + List findBySimpleValue(Integer value); } private static class CustomRowMapper implements RowMapper { @@ -241,6 +305,54 @@ public Object extractData(ResultSet rs) throws DataAccessException { } } + private enum Direction { + LEFT, CENTER, RIGHT + } + + @WritingConverter + enum DirectionToIntegerConverter implements Converter { + + INSTANCE; + + @Override + public JdbcValue convert(Direction source) { + + int integer; + switch (source) { + case LEFT: + integer = -1; + break; + case CENTER: + integer = 0; + break; + case RIGHT: + integer = 1; + break; + default: + throw new IllegalArgumentException(); + } + return JdbcValue.of(integer, JDBCType.INTEGER); + } + } + + @ReadingConverter + enum IntegerToDirectionConverter implements Converter { + + INSTANCE; + + @Override + public Direction convert(Integer source) { + + if (source == 0) { + return Direction.CENTER; + } else if (source < 0) { + return Direction.LEFT; + } else { + return Direction.RIGHT; + } + } + } + private static class DummyEntity { private Long id; diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-db2.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-db2.sql index e75592d0bc..6abce10e3a 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-db2.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-db2.sql @@ -1,5 +1,5 @@ DROP TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL; DROP TABLE OTHER_ENTITY; -CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, Stringy_number DECIMAL(20,10)); +CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, Stringy_number DECIMAL(20,10), DIRECTION INTEGER); CREATE TABLE OTHER_ENTITY ( ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY, CREATED DATE, ENTITY_WITH_STRINGY_BIG_DECIMAL INTEGER); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-h2.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-h2.sql index d383545694..426153b9e3 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-h2.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-h2.sql @@ -1,2 +1,2 @@ -CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id IDENTITY PRIMARY KEY, Stringy_number DECIMAL(20,10)); +CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id IDENTITY PRIMARY KEY, Stringy_number DECIMAL(20,10), DIRECTION INTEGER); CREATE TABLE OTHER_ENTITY ( ID IDENTITY PRIMARY KEY, CREATED DATE, ENTITY_WITH_STRINGY_BIG_DECIMAL INTEGER); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-hsql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-hsql.sql index 78d9c930b7..9508fbb0e2 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-hsql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-hsql.sql @@ -1,3 +1,3 @@ -CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id IDENTITY PRIMARY KEY, Stringy_number DECIMAL(20,10)); +CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id IDENTITY PRIMARY KEY, Stringy_number DECIMAL(20,10), DIRECTION INTEGER); CREATE TABLE OTHER_ENTITY ( ID IDENTITY PRIMARY KEY, CREATED DATE, ENTITY_WITH_STRINGY_BIG_DECIMAL INTEGER); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mariadb.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mariadb.sql index e89bb0d951..4e2dee5382 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mariadb.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mariadb.sql @@ -1,2 +1,2 @@ -CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id BIGINT AUTO_INCREMENT PRIMARY KEY, Stringy_number DECIMAL(20,10)); +CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id BIGINT AUTO_INCREMENT PRIMARY KEY, Stringy_number DECIMAL(20,10), DIRECTION INTEGER); CREATE TABLE OTHER_ENTITY ( ID BIGINT AUTO_INCREMENT PRIMARY KEY, CREATED DATE, ENTITY_WITH_STRINGY_BIG_DECIMAL INTEGER); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mssql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mssql.sql index 34b2982692..0a884be3cf 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mssql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mssql.sql @@ -1,5 +1,5 @@ DROP TABLE OTHER_ENTITY; DROP TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL; -CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id BIGINT IDENTITY PRIMARY KEY, Stringy_number DECIMAL(20,10)); +CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id BIGINT IDENTITY PRIMARY KEY, Stringy_number DECIMAL(20,10), DIRECTION INTEGER); CREATE TABLE OTHER_ENTITY ( ID BIGINT IDENTITY PRIMARY KEY, CREATED DATE, ENTITY_WITH_STRINGY_BIG_DECIMAL INTEGER); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mysql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mysql.sql index 34776fc5a8..b1d3da76c2 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mysql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-mysql.sql @@ -1,2 +1,2 @@ -CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( ID BIGINT AUTO_INCREMENT PRIMARY KEY, Stringy_number DECIMAL(20,10)); +CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( ID BIGINT AUTO_INCREMENT PRIMARY KEY, Stringy_number DECIMAL(20,10), DIRECTION INTEGER); CREATE TABLE OTHER_ENTITY ( ID BIGINT AUTO_INCREMENT PRIMARY KEY, CREATED DATE, ENTITY_WITH_STRINGY_BIG_DECIMAL INTEGER); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-oracle.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-oracle.sql index 1b02ef7214..1d653cf453 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-oracle.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-oracle.sql @@ -3,7 +3,8 @@ DROP TABLE OTHER_ENTITY CASCADE CONSTRAINTS PURGE; CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY, - STRINGY_NUMBER DECIMAL(20,10) + STRINGY_NUMBER DECIMAL(20,10), + DIRECTION INTEGER ); CREATE TABLE OTHER_ENTITY ( diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-postgres.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-postgres.sql index c376dcf03f..882d8df894 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-postgres.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryCustomConversionIntegrationTests-postgres.sql @@ -1,2 +1,2 @@ -CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id SERIAL PRIMARY KEY, Stringy_number DECIMAL(20,10)); +CREATE TABLE ENTITY_WITH_STRINGY_BIG_DECIMAL ( id SERIAL PRIMARY KEY, Stringy_number DECIMAL(20,10), DIRECTION INTEGER); CREATE TABLE OTHER_ENTITY ( ID SERIAL PRIMARY KEY, CREATED DATE, ENTITY_WITH_STRINGY_BIG_DECIMAL INTEGER); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-db2.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-db2.sql index 34be74ec51..ce25ff6442 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-db2.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-db2.sql @@ -7,5 +7,6 @@ CREATE TABLE dummy_entity POINT_IN_TIME TIMESTAMP, OFFSET_DATE_TIME TIMESTAMP, -- with time zone is only supported with z/OS FLAG BOOLEAN, - REF BIGINT + REF BIGINT, + DIRECTION VARCHAR(100) ); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-h2.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-h2.sql index b3b93bc744..30a8df2e20 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-h2.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-h2.sql @@ -5,5 +5,6 @@ CREATE TABLE dummy_entity POINT_IN_TIME TIMESTAMP, OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE, FLAG BOOLEAN, - REF BIGINT + REF BIGINT, + DIRECTION VARCHAR(100) ); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-hsql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-hsql.sql index b3b93bc744..30a8df2e20 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-hsql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-hsql.sql @@ -5,5 +5,6 @@ CREATE TABLE dummy_entity POINT_IN_TIME TIMESTAMP, OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE, FLAG BOOLEAN, - REF BIGINT + REF BIGINT, + DIRECTION VARCHAR(100) ); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mariadb.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mariadb.sql index 949e626399..c505db351c 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mariadb.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mariadb.sql @@ -5,5 +5,6 @@ CREATE TABLE dummy_entity POINT_IN_TIME TIMESTAMP(3), OFFSET_DATE_TIME TIMESTAMP(3), FLAG BOOLEAN, - REF BIGINT + REF BIGINT, + DIRECTION VARCHAR(100) ); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mssql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mssql.sql index 15f8881327..94f7aadf9f 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mssql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mssql.sql @@ -6,5 +6,6 @@ CREATE TABLE dummy_entity POINT_IN_TIME DATETIME, OFFSET_DATE_TIME DATETIMEOFFSET, FLAG BIT, - REF BIGINT + REF BIGINT, + DIRECTION VARCHAR(100) ); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mysql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mysql.sql index e3baa94602..eb04d9ed4d 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mysql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mysql.sql @@ -8,5 +8,6 @@ CREATE TABLE DUMMY_ENTITY POINT_IN_TIME TIMESTAMP(3) DEFAULT NULL, OFFSET_DATE_TIME TIMESTAMP(3) DEFAULT NULL, FLAG BIT(1), - REF BIGINT + REF BIGINT, + DIRECTION VARCHAR(100) ); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-oracle.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-oracle.sql index e71eb63286..c575139be1 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-oracle.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-oracle.sql @@ -7,5 +7,6 @@ CREATE TABLE DUMMY_ENTITY POINT_IN_TIME TIMESTAMP, OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE, FLAG NUMBER(1,0), - REF NUMBER + REF NUMBER, + DIRECTION VARCHAR2(100) ); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-postgres.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-postgres.sql index 97fc78c9da..592b3ea26e 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-postgres.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-postgres.sql @@ -6,5 +6,6 @@ CREATE TABLE dummy_entity POINT_IN_TIME TIMESTAMP, OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE, FLAG BOOLEAN, - REF BIGINT + REF BIGINT, + DIRECTION VARCHAR(100) ); diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalParameters.java b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalParameters.java index 05da136e67..6275a1a7b1 100755 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalParameters.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/repository/query/RelationalParameters.java @@ -16,9 +16,11 @@ package org.springframework.data.relational.repository.query; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.List; import org.springframework.core.MethodParameter; +import org.springframework.core.ResolvableType; import org.springframework.data.relational.repository.query.RelationalParameters.RelationalParameter; import org.springframework.data.repository.query.Parameter; import org.springframework.data.repository.query.Parameters; @@ -65,9 +67,12 @@ protected RelationalParameters createFrom(List parameters) * Custom {@link Parameter} implementation. * * @author Mark Paluch + * @author Chirag Tailor */ public static class RelationalParameter extends Parameter { + private final MethodParameter parameter; + /** * Creates a new {@link RelationalParameter}. * @@ -75,6 +80,13 @@ public static class RelationalParameter extends Parameter { */ RelationalParameter(MethodParameter parameter) { super(parameter); + this.parameter = parameter; + } + + + public ResolvableType getResolvableType() { + return ResolvableType + .forClassWithGenerics(super.getType(), ResolvableType.forMethodParameter(this.parameter).getGenerics()); } } }