Browse Source

Do not convert binary data in `List<byte[]>` to array SQL type.

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
Original pull request: #1903
pull/1912/head
Jens Schauder 1 year ago committed by Mark Paluch
parent
commit
ae8651869e
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 5
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java
  2. 70
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
  3. 3
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-db2.sql
  4. 3
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-h2.sql
  5. 3
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-hsql.sql
  6. 3
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mariadb.sql
  7. 3
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mssql.sql
  8. 3
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-mysql.sql
  9. 3
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-oracle.sql
  10. 3
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryIntegrationTests-postgres.sql

5
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, public StringBasedJdbcQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
@Nullable RowMapper<?> defaultRowMapper, JdbcConverter converter, @Nullable RowMapper<?> defaultRowMapper, JdbcConverter converter,
QueryMethodEvaluationContextProvider evaluationContextProvider) { QueryMethodEvaluationContextProvider evaluationContextProvider) {
this(queryMethod.getRequiredQuery(), queryMethod, operations, result -> (RowMapper<Object>) defaultRowMapper, converter, evaluationContextProvider); this(queryMethod.getRequiredQuery(), queryMethod, operations, result -> (RowMapper<Object>) defaultRowMapper,
converter, evaluationContextProvider);
} }
/** /**
@ -244,7 +245,7 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
TypeInformation<?> actualType = typeInformation.getActualType(); TypeInformation<?> actualType = typeInformation.getActualType();
// tuple-binding // tuple-binding
if (actualType != null && actualType.getType().isArray()) { if (actualType != null && actualType.getType().isArray() && !actualType.getType().equals(byte[].class)) {
TypeInformation<?> nestedElementType = actualType.getRequiredActualType(); TypeInformation<?> nestedElementType = actualType.getRequiredActualType();
return writeCollection(collection, parameter.getActualSqlType(), return writeCollection(collection, parameter.getActualSqlType(),

70
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java

@ -41,7 +41,6 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
@ -51,23 +50,13 @@ import org.springframework.context.annotation.Import;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Example; import org.springframework.data.domain.*;
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.jdbc.core.mapping.AggregateReference; import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.jdbc.repository.query.Modifying; import org.springframework.data.jdbc.repository.query.Modifying;
import org.springframework.data.jdbc.repository.query.Query; import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.data.jdbc.testing.ConditionalOnDatabase; import org.springframework.data.jdbc.testing.ConditionalOnDatabase;
import org.springframework.data.jdbc.testing.DatabaseType; 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.EnabledOnFeature;
import org.springframework.data.jdbc.testing.IntegrationTest; import org.springframework.data.jdbc.testing.IntegrationTest;
import org.springframework.data.jdbc.testing.TestConfiguration; import org.springframework.data.jdbc.testing.TestConfiguration;
@ -1357,6 +1346,52 @@ public class JdbcRepositoryIntegrationTests {
assertThat(result).containsOnly(two); 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<DummyEntity> 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<DummyEntity> result = repository.findByBytes(twoBytes);
assertThat(result).extracting("idProp").containsExactly(two.idProp);
}
private Root createRoot(String namePrefix) { private Root createRoot(String namePrefix) {
return new Root(null, namePrefix, return new Root(null, namePrefix,
@ -1487,6 +1522,12 @@ public class JdbcRepositoryIntegrationTests {
@Query("SELECT * FROM DUMMY_ENTITY WHERE (ID_PROP, NAME) IN (:tuples)") @Query("SELECT * FROM DUMMY_ENTITY WHERE (ID_PROP, NAME) IN (:tuples)")
List<DummyEntity> findByListInTuple(List<Object[]> tuples); List<DummyEntity> findByListInTuple(List<Object[]> tuples);
@Query("SELECT * FROM DUMMY_ENTITY WHERE BYTES IN (:bytes)")
List<DummyEntity> findByBytesIn(List<byte[]> bytes);
@Query("SELECT * FROM DUMMY_ENTITY WHERE BYTES = :bytes")
List<DummyEntity> findByBytes(byte[] bytes);
} }
interface RootRepository extends ListCrudRepository<Root, Long> { interface RootRepository extends ListCrudRepository<Root, Long> {
@ -1810,6 +1851,7 @@ public class JdbcRepositoryIntegrationTests {
boolean flag; boolean flag;
AggregateReference<DummyEntity, Long> ref; AggregateReference<DummyEntity, Long> ref;
Direction direction; Direction direction;
byte[] bytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
public DummyEntity(String name) { public DummyEntity(String name) {
this.name = name; this.name = name;
@ -1890,6 +1932,10 @@ public class JdbcRepositoryIntegrationTests {
return Objects.hash(name, pointInTime, offsetDateTime, idProp, flag, ref, direction); return Objects.hash(name, pointInTime, offsetDateTime, idProp, flag, ref, direction);
} }
public void setBytes(byte[] bytes) {
this.bytes = bytes;
}
@Override @Override
public String toString() { public String toString() {
return "DummyEntity{" + "name='" + name + '\'' + ", idProp=" + idProp + '}'; return "DummyEntity{" + "name='" + name + '\'' + ", idProp=" + idProp + '}';

3
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 OFFSET_DATE_TIME TIMESTAMP, -- with time zone is only supported with z/OS
FLAG BOOLEAN, FLAG BOOLEAN,
REF BIGINT, REF BIGINT,
DIRECTION VARCHAR(100) DIRECTION VARCHAR(100),
BYTES BINARY(8)
); );
CREATE TABLE ROOT CREATE TABLE ROOT

3
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, OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE,
FLAG BOOLEAN, FLAG BOOLEAN,
REF BIGINT, REF BIGINT,
DIRECTION VARCHAR(100) DIRECTION VARCHAR(100),
BYTES BINARY(8)
); );
CREATE TABLE ROOT CREATE TABLE ROOT

3
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, OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE,
FLAG BOOLEAN, FLAG BOOLEAN,
REF BIGINT, REF BIGINT,
DIRECTION VARCHAR(100) DIRECTION VARCHAR(100),
BYTES BINARY(8)
); );
CREATE TABLE ROOT CREATE TABLE ROOT

3
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), OFFSET_DATE_TIME TIMESTAMP(3),
FLAG BOOLEAN, FLAG BOOLEAN,
REF BIGINT, REF BIGINT,
DIRECTION VARCHAR(100) DIRECTION VARCHAR(100),
BYTES BINARY(8)
); );
CREATE TABLE ROOT CREATE TABLE ROOT

3
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, OFFSET_DATE_TIME DATETIMEOFFSET,
FLAG BIT, FLAG BIT,
REF BIGINT, REF BIGINT,
DIRECTION VARCHAR(100) DIRECTION VARCHAR(100),
BYTES VARBINARY(8)
); );
CREATE TABLE ROOT CREATE TABLE ROOT

3
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, OFFSET_DATE_TIME TIMESTAMP(3) DEFAULT NULL,
FLAG BIT(1), FLAG BIT(1),
REF BIGINT, REF BIGINT,
DIRECTION VARCHAR(100) DIRECTION VARCHAR(100),
BYTES BINARY(8)
); );
CREATE TABLE ROOT CREATE TABLE ROOT

3
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, OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE,
FLAG NUMBER(1,0), FLAG NUMBER(1,0),
REF NUMBER, REF NUMBER,
DIRECTION VARCHAR2(100) DIRECTION VARCHAR2(100),
BYTES RAW(8)
); );
CREATE TABLE ROOT CREATE TABLE ROOT

3
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, OFFSET_DATE_TIME TIMESTAMP WITH TIME ZONE,
FLAG BOOLEAN, FLAG BOOLEAN,
REF BIGINT, REF BIGINT,
DIRECTION VARCHAR(100) DIRECTION VARCHAR(100),
BYTES BYTEA
); );
CREATE TABLE ROOT CREATE TABLE ROOT

Loading…
Cancel
Save