From 3b6f01f83e96f2127c7135597f64f599975c015a Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 6 Feb 2019 13:05:42 +0100 Subject: [PATCH] DATAJDBC-259 - Polishing. Unwrap multi-dimensional array types to determine the proper component type. Extend tests. Inline isCollectionOf[Entities|SimpleType]Like calls and remove utility methods on RelationalPersistentProperty as the usage-scope is specific to array handling. Original pull request: #113. --- .../jdbc/core/DefaultDataAccessStrategy.java | 8 ++++-- .../data/jdbc/core/EntityRowMapper.java | 2 +- ...JdbcAggregateTemplateIntegrationTests.java | 27 +++++++++++++++++++ ...AggregateTemplateIntegrationTests-hsql.sql | 2 +- ...egateTemplateIntegrationTests-postgres.sql | 2 +- .../BasicRelationalPersistentProperty.java | 14 +++++++--- .../mapping/RelationalPersistentProperty.java | 12 +++------ ...RelationalPersistentPropertyUnitTests.java | 12 ++++----- 8 files changed, 56 insertions(+), 23 deletions(-) diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java index b028b53e..7ee0cf83 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java @@ -81,7 +81,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy { this.accessStrategy = this; } - /* + /* * (non-Javadoc) * @see org.springframework.data.jdbc.core.DataAccessStrategy#insert(java.lang.Object, java.lang.Class, java.util.Map) */ @@ -320,7 +320,11 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy { return convertedValue; } - Class componentType = convertedValue.getClass().getComponentType(); + Class componentType = convertedValue.getClass(); + while (componentType.isArray()) { + componentType = componentType.getComponentType(); + } + String typeName = JDBCType.valueOf(JdbcUtil.sqlTypeFor(componentType)).getName(); return operations.getJdbcOperations().execute( diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java index 076ad807..abe1c163 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java @@ -110,7 +110,7 @@ public class EntityRowMapper implements RowMapper { private Object readOrLoadProperty(ResultSet resultSet, @Nullable Object id, RelationalPersistentProperty property, String prefix) { - if (property.isCollectionOfEntitiesLike() && id != null) { + if (property.isCollectionLike() && property.isEntity() && id != null) { return accessStrategy.findAllByProperty(id, property); } else if (property.isMap() && id != null) { return ITERABLE_OF_ENTRY_TO_MAP_CONVERTER.convert(accessStrategy.findAllByProperty(id, property)); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java index f5dfce85..2fc7f427 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateTemplateIntegrationTests.java @@ -56,6 +56,7 @@ import org.springframework.transaction.annotation.Transactional; * * @author Jens Schauder * @author Thomas Lang + * @author Mark Paluch */ @ContextConfiguration @Transactional @@ -347,6 +348,31 @@ public class JdbcAggregateTemplateIntegrationTests { assertThat(reloaded.digits).isEqualTo(new String[] { "one", "two", "three" }); } + @Test // DATAJDBC-259 + public void saveAndLoadAnEntityWithMultidimensionalArray() { + + // MySQL and other do not support array datatypes. See + // https://dev.mysql.com/doc/refman/8.0/en/data-type-overview.html + assumeNot("mysql"); + assumeNot("mariadb"); + assumeNot("mssql"); + assumeNot("hsqldb"); + + ArrayOwner arrayOwner = new ArrayOwner(); + arrayOwner.multidimensional = new String[][] { { "one-a", "two-a", "three-a" }, { "one-b", "two-b", "three-b" } }; + + ArrayOwner saved = template.save(arrayOwner); + + assertThat(saved.id).isNotNull(); + + ArrayOwner reloaded = template.findById(saved.id, ArrayOwner.class); + + assertThat(reloaded).isNotNull(); + assertThat(reloaded.id).isEqualTo(saved.id); + assertThat(reloaded.multidimensional) + .isEqualTo(new String[][] { { "one-a", "two-a", "three-a" }, { "one-b", "two-b", "three-b" } }); + } + @Test // DATAJDBC-259 public void saveAndLoadAnEntityWithList() { @@ -404,6 +430,7 @@ public class JdbcAggregateTemplateIntegrationTests { @Id Long id; String[] digits; + String[][] multidimensional; } @Table("ARRAY_OWNER") diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-hsql.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-hsql.sql index 2bfce4d2..a327aeca 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-hsql.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-hsql.sql @@ -10,4 +10,4 @@ CREATE TABLE Child_No_Id (ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, content VARCHAR CREATE TABLE LIST_PARENT ( id4 BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, NAME VARCHAR(100)); CREATE TABLE element_no_id ( content VARCHAR(100), LIST_PARENT_key BIGINT, LIST_PARENT BIGINT); -CREATE TABLE ARRAY_OWNER (ID BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, DIGITS VARCHAR(20) ARRAY[10] NOT NULL); \ No newline at end of file +CREATE TABLE ARRAY_OWNER (ID BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, DIGITS VARCHAR(20) ARRAY[10] NOT NULL, MULTIDIMENSIONAL VARCHAR(20) ARRAY[10] NULL); diff --git a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql index f7fa03f5..d5ba24a9 100644 --- a/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql +++ b/spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.core/JdbcAggregateTemplateIntegrationTests-postgres.sql @@ -13,4 +13,4 @@ CREATE TABLE Child_No_Id (ONE_TO_ONE_PARENT INTEGER PRIMARY KEY, content VARCHAR CREATE TABLE LIST_PARENT ( id4 SERIAL PRIMARY KEY, NAME VARCHAR(100)); CREATE TABLE element_no_id ( content VARCHAR(100), LIST_PARENT_key BIGINT, LIST_PARENT INTEGER); -CREATE TABLE ARRAY_OWNER (ID SERIAL PRIMARY KEY, DIGITS VARCHAR(20) ARRAY[10] NOT NULL); \ No newline at end of file +CREATE TABLE ARRAY_OWNER (ID SERIAL PRIMARY KEY, DIGITS VARCHAR(20)[10], MULTIDIMENSIONAL VARCHAR(20)[10][10]); diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java index 3223ce8d..d6fc4980 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentProperty.java @@ -60,6 +60,7 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent private final Lazy> keyColumnName; private final Lazy isEmbedded; private final Lazy embeddedPrefix; + private final Lazy> columnType = Lazy.of(this::doGetColumnType); /** * Creates a new {@link AnnotationBasedPersistentProperty}. @@ -130,9 +131,12 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent * * @return a {@link Class} that is suitable for usage with JDBC drivers */ - @SuppressWarnings("unchecked") @Override - public Class getColumnType() { + public Class getColumnType() { + return columnType.get(); + } + + private Class doGetColumnType() { if (isReference()) { return columnTypeForReference(); @@ -146,7 +150,11 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent Class componentColumnType = columnTypeForNonEntity(getActualType()); - if (isCollectionOfSimpleTypeLike()) { + while (componentColumnType.isArray()) { + componentColumnType = componentColumnType.getComponentType(); + } + + if (isCollectionLike() && !isEntity()) { return Array.newInstance(componentColumnType, 0).getClass(); } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java index f6352b5b..2653be60 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/RelationalPersistentProperty.java @@ -37,9 +37,11 @@ public interface RelationalPersistentProperty extends PersistentProperty getColumnType(); @@ -84,12 +86,4 @@ public interface RelationalPersistentProperty extends PersistentProperty checkEitherOr = (p, s) -> softly - .assertThat(p.isCollectionOfSimpleTypeLike()).describedAs(s + " contains either simple types or entities") - .isNotEqualTo(p.isCollectionOfEntitiesLike()); + .assertThat(p.isCollectionLike() && !p.isEntity()).describedAs(s + " contains either simple types or entities") + .isNotEqualTo(p.isCollectionLike() && p.isEntity()); checkEitherOr.accept(listOfString,"listOfString"); checkEitherOr.accept(arrayOfString,"arrayOfString");