From 3785d997b0ad96fae7dfe7803b22417aa62ed5b8 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Tue, 1 Oct 2024 09:57:25 +0200 Subject: [PATCH] Do not convert binary data in List. byte[] is mapped to BINARY data and is not considered tuple data. The explicit check for byte[] is not very nice but matches the special handling in MappingJdbcConverter.writeJdbcValue Closes #1900 --- .../query/StringBasedJdbcQuery.java | 5 +- .../JdbcRepositoryIntegrationTests.java | 70 +++++++++++++++---- .../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 +- 10 files changed, 77 insertions(+), 22 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 3e8aebc44d0..234041af363 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 @@ -92,7 +92,8 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery { public StringBasedJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations, @Nullable RowMapper defaultRowMapper, JdbcConverter converter, QueryMethodEvaluationContextProvider evaluationContextProvider) { - this(queryMethod.getRequiredQuery(), queryMethod, operations, result -> (RowMapper) defaultRowMapper, converter, evaluationContextProvider); + this(queryMethod.getRequiredQuery(), queryMethod, operations, result -> (RowMapper) defaultRowMapper, + converter, evaluationContextProvider); } /** @@ -244,7 +245,7 @@ private JdbcValue writeValue(@Nullable Object value, TypeInformation typeInfo TypeInformation actualType = typeInformation.getActualType(); // tuple-binding - if (actualType != null && actualType.getType().isArray()) { + if (actualType != null && actualType.getType().isArray() && !actualType.getType().equals(byte[].class)) { TypeInformation nestedElementType = actualType.getRequiredActualType(); return writeCollection(collection, parameter.getActualSqlType(), 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 babe95a795d..c11335f2165 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 @@ -41,7 +41,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.context.ApplicationListener; @@ -51,23 +50,13 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.data.annotation.Id; -import org.springframework.data.domain.Example; -import org.springframework.data.domain.ExampleMatcher; -import org.springframework.data.domain.Limit; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.ScrollPosition; -import org.springframework.data.domain.Slice; -import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Window; +import org.springframework.data.domain.*; import org.springframework.data.jdbc.core.mapping.AggregateReference; import org.springframework.data.jdbc.repository.query.Modifying; import org.springframework.data.jdbc.repository.query.Query; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.jdbc.testing.ConditionalOnDatabase; import org.springframework.data.jdbc.testing.DatabaseType; -import org.springframework.data.jdbc.testing.EnabledOnDatabase; import org.springframework.data.jdbc.testing.EnabledOnFeature; import org.springframework.data.jdbc.testing.IntegrationTest; import org.springframework.data.jdbc.testing.TestConfiguration; @@ -1357,6 +1346,52 @@ void queryWithTupleIn() { assertThat(result).containsOnly(two); } + @Test // GH-1900 + void queryByListOfByteArray() { + + byte[] oneBytes = { 1, 2, 3, 4, 5, 6, 7, 8 }; + DummyEntity one = createDummyEntity("one"); + one.setBytes(oneBytes); + one = repository.save(one); + + byte[] twoBytes = { 8, 7, 6, 5, 4, 3, 2, 1 }; + DummyEntity two = createDummyEntity("two"); + two.setBytes(twoBytes); + two = repository.save(two); + + byte[] threeBytes = { 3, 3, 3, 3, 3, 3, 3, 3 }; + DummyEntity three = createDummyEntity("three"); + three.setBytes(threeBytes); + three = repository.save(three); + + List result = repository.findByBytesIn(List.of(threeBytes, oneBytes)); + + assertThat(result).extracting("idProp").containsExactlyInAnyOrder(one.idProp, three.idProp); + } + + @Test // GH-1900 + void queryByByteArray() { + + byte[] oneBytes = { 1, 2, 3, 4, 5, 6, 7, 8 }; + DummyEntity one = createDummyEntity("one"); + one.setBytes(oneBytes); + one = repository.save(one); + + byte[] twoBytes = { 8, 7, 6, 5, 4, 3, 2, 1 }; + DummyEntity two = createDummyEntity("two"); + two.setBytes(twoBytes); + two = repository.save(two); + + byte[] threeBytes = { 3, 3, 3, 3, 3, 3, 3, 3 }; + DummyEntity three = createDummyEntity("three"); + three.setBytes(threeBytes); + three = repository.save(three); + + List result = repository.findByBytes(twoBytes); + + assertThat(result).extracting("idProp").containsExactly(two.idProp); + } + private Root createRoot(String namePrefix) { return new Root(null, namePrefix, @@ -1487,6 +1522,12 @@ interface DummyEntityRepository extends CrudRepository, Query @Query("SELECT * FROM DUMMY_ENTITY WHERE (ID_PROP, NAME) IN (:tuples)") List findByListInTuple(List tuples); + + @Query("SELECT * FROM DUMMY_ENTITY WHERE BYTES IN (:bytes)") + List findByBytesIn(List bytes); + + @Query("SELECT * FROM DUMMY_ENTITY WHERE BYTES = :bytes") + List findByBytes(byte[] bytes); } interface RootRepository extends ListCrudRepository { @@ -1810,6 +1851,7 @@ static class DummyEntity { boolean flag; AggregateReference ref; Direction direction; + byte[] bytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; public DummyEntity(String name) { this.name = name; @@ -1890,6 +1932,10 @@ public int hashCode() { return Objects.hash(name, pointInTime, offsetDateTime, idProp, flag, ref, direction); } + public void setBytes(byte[] bytes) { + this.bytes = bytes; + } + @Override public String toString() { return "DummyEntity{" + "name='" + name + '\'' + ", idProp=" + idProp + '}'; 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 e75d0a61bc9..2c66f226e1a 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 @@ -12,7 +12,8 @@ CREATE TABLE dummy_entity OFFSET_DATE_TIME TIMESTAMP, -- with time zone is only supported with z/OS FLAG BOOLEAN, REF BIGINT, - DIRECTION VARCHAR(100) + DIRECTION VARCHAR(100), + BYTES BINARY(8) ); CREATE TABLE ROOT 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 724cd2ba007..b72f6645357 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 @@ -6,7 +6,8 @@ CREATE TABLE dummy_entity OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE, FLAG BOOLEAN, REF BIGINT, - DIRECTION VARCHAR(100) + DIRECTION VARCHAR(100), + BYTES BINARY(8) ); CREATE TABLE ROOT 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 724cd2ba007..b72f6645357 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 @@ -6,7 +6,8 @@ CREATE TABLE dummy_entity OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE, FLAG BOOLEAN, REF BIGINT, - DIRECTION VARCHAR(100) + DIRECTION VARCHAR(100), + BYTES BINARY(8) ); CREATE TABLE ROOT 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 7617b01bf22..75b46639892 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 @@ -6,7 +6,8 @@ CREATE TABLE dummy_entity OFFSET_DATE_TIME TIMESTAMP(3), FLAG BOOLEAN, REF BIGINT, - DIRECTION VARCHAR(100) + DIRECTION VARCHAR(100), + BYTES BINARY(8) ); CREATE TABLE ROOT 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 cabaa038b83..9959dea4a81 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 @@ -12,7 +12,8 @@ CREATE TABLE dummy_entity OFFSET_DATE_TIME DATETIMEOFFSET, FLAG BIT, REF BIGINT, - DIRECTION VARCHAR(100) + DIRECTION VARCHAR(100), + BYTES VARBINARY(8) ); CREATE TABLE ROOT 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 00175585d7b..0d3e16587ff 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 @@ -9,7 +9,8 @@ CREATE TABLE DUMMY_ENTITY OFFSET_DATE_TIME TIMESTAMP(3) DEFAULT NULL, FLAG BIT(1), REF BIGINT, - DIRECTION VARCHAR(100) + DIRECTION VARCHAR(100), + BYTES BINARY(8) ); CREATE TABLE ROOT 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 6383e3c6248..0a08dfbf9ed 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 @@ -12,7 +12,8 @@ CREATE TABLE DUMMY_ENTITY OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE, FLAG NUMBER(1,0), REF NUMBER, - DIRECTION VARCHAR2(100) + DIRECTION VARCHAR2(100), + BYTES RAW(8) ); CREATE TABLE ROOT 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 ca33b4ecd53..37ad6914dee 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 @@ -12,7 +12,8 @@ CREATE TABLE dummy_entity OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE, FLAG BOOLEAN, REF BIGINT, - DIRECTION VARCHAR(100) + DIRECTION VARCHAR(100), + BYTES BYTEA ); CREATE TABLE ROOT