From df7e525496587f1cbd68f73d45d7868d169da5f3 Mon Sep 17 00:00:00 2001 From: Bastian Wilhelm Date: Fri, 8 Feb 2019 22:18:47 +0100 Subject: [PATCH 1/4] DATAJDBC-331 Deprecate @Columns keyColumn attribute. Introduce @MappedCollection annotation --- .../BasicJdbcPersistentPropertyUnitTests.java | 3 +- ...mbeddedWithCollectionIntegrationTests.java | 3 +- .../BasicRelationalPersistentProperty.java | 31 +++++++++++-- .../data/relational/core/mapping/Column.java | 3 ++ .../core/mapping/MappedCollection.java | 44 +++++++++++++++++++ ...RelationalPersistentPropertyUnitTests.java | 2 +- 6 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentPropertyUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentPropertyUnitTests.java index 9c690dc417..5b631d6807 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentPropertyUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/mapping/BasicJdbcPersistentPropertyUnitTests.java @@ -31,6 +31,7 @@ import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.relational.core.mapping.BasicRelationalPersistentProperty; import org.springframework.data.relational.core.mapping.Column; +import org.springframework.data.relational.core.mapping.MappedCollection; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; @@ -137,7 +138,7 @@ private static class DummyEntity { private final List listField; private final UUID uuid; - @Column(value = "dummy_column_name", keyColumn = "dummy_key_column_name") private List someList; + @MappedCollection(idColumn = "dummy_column_name", keyColumn = "dummy_key_column_name") private List someList; // DATACMNS-106 private @Column("dummy_name") String name; diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java index e965e37608..0f35ce8c21 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedWithCollectionIntegrationTests.java @@ -32,6 +32,7 @@ import org.springframework.data.jdbc.testing.TestConfiguration; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.mapping.Embedded; +import org.springframework.data.relational.core.mapping.MappedCollection; import org.springframework.data.repository.CrudRepository; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -254,7 +255,7 @@ private static class DummyEntity { @Data private static class Embeddable { - @Column(value = "id", keyColumn = "order_key") + @MappedCollection(idColumn = "id", keyColumn = "order_key") List list = new ArrayList<>(); String test; 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 d6fc49805d..1c98da75e3 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 @@ -57,7 +57,10 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent private final RelationalMappingContext context; private final Lazy> columnName; - private final Lazy> keyColumnName; + /** @deprecated see {@link Column#keyColumn()} */ + @Deprecated private final Lazy> keyColumnName; + private final Lazy> collectionIdColumnName; + private final Lazy> collectionKeyColumnName; private final Lazy isEmbedded; private final Lazy embeddedPrefix; private final Lazy> columnType = Lazy.of(this::doGetColumnType); @@ -88,7 +91,7 @@ public BasicRelationalPersistentProperty(Property property, PersistentEntity Optional.ofNullable( // findAnnotation(Column.class)) // .map(Column::value) // - .filter(StringUtils::hasText) // + .filter(StringUtils::hasText)// ); this.keyColumnName = Lazy.of(() -> Optional.ofNullable( // @@ -96,6 +99,18 @@ public BasicRelationalPersistentProperty(Property property, PersistentEntity Optional.ofNullable( // + findAnnotation(MappedCollection.class)) // + .map(MappedCollection::idColumn) // + .filter(StringUtils::hasText)// + ); + + this.collectionKeyColumnName = Lazy.of(() -> Optional.ofNullable( // + findAnnotation(MappedCollection.class)) // + .map(MappedCollection::keyColumn) // + .filter(StringUtils::hasText)// + ); } /* @@ -173,14 +188,22 @@ public RelationalPersistentEntity getOwner() { @Override public String getReverseColumnName() { - return columnName.get().orElseGet(() -> context.getNamingStrategy().getReverseColumnName(this)); + return collectionIdColumnName.get().orElseGet( + () -> columnName.get().orElseGet( + () -> context.getNamingStrategy().getReverseColumnName(this) + ) + ); } @Override public String getKeyColumn() { if (isQualified()) { - return keyColumnName.get().orElseGet(() -> context.getNamingStrategy().getKeyColumn(this)); + return collectionKeyColumnName.get().orElseGet( + () -> keyColumnName.get().orElseGet( + () -> context.getNamingStrategy().getKeyColumn(this) + ) + ); } else { return null; } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java index cbb01e90cb..013f902a71 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java @@ -39,6 +39,9 @@ /** * The column name for key columns of List or Map collections. + * + * @deprecated Was used for collection mapping. Use {@link MappedCollection} instead of this. */ + @Deprecated String keyColumn() default ""; } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java new file mode 100644 index 0000000000..421b8318d2 --- /dev/null +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018-2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.relational.core.mapping; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The annotation to configure the mapping from an collection in the database. + * + * @author Kazuki Shimizu + * @author Florian Lüdiger + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) +@Documented +public @interface MappedCollection { + + /** + * The column name for id column in the corresponding relationship table. + */ + String idColumn() default ""; + + /** + * The column name for key columns of List or Map collections in the corresponding relationship table. + */ + String keyColumn() default ""; +} diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java index aea002609a..28741fd6a8 100644 --- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java +++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/mapping/BasicRelationalPersistentPropertyUnitTests.java @@ -182,7 +182,7 @@ private static class DummyEntity { private final List listOfEntity; private final OtherEntity[] arrayOfEntity; - @Column(value = "dummy_column_name", keyColumn = "dummy_key_column_name") private List someList; + @MappedCollection(idColumn = "dummy_column_name", keyColumn = "dummy_key_column_name") private List someList; // DATACMNS-106 private @Column("dummy_name") String name; From b1ea7b44aa0e922dd12e37bdd9d3d98af4375221 Mon Sep 17 00:00:00 2001 From: Bastian Wilhelm Date: Fri, 8 Feb 2019 22:23:37 +0100 Subject: [PATCH 2/4] DATAJDBC-331 Modify reference documentation --- src/main/asciidoc/jdbc.adoc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/asciidoc/jdbc.adoc b/src/main/asciidoc/jdbc.adoc index 8796935cff..07fcf33e35 100644 --- a/src/main/asciidoc/jdbc.adoc +++ b/src/main/asciidoc/jdbc.adoc @@ -136,7 +136,7 @@ You can change this name by implementing `NamingStrategy.getReverseColumnName(Re * `Map` is considered a qualified one-to-many relationship. The table of the referenced entity is expected to have two additional columns: One named the same as the table of the referencing entity for the foreign key and one with the same name and an additional `_key` suffix for the map key. You can change this behavior by implementing `NamingStrategy.getReverseColumnName(RelationalPersistentProperty property)` and `NamingStrategy.getKeyColumn(RelationalPersistentProperty property)`, respectively. -Alternatively you may annotate the attribute with `@Column(value="your_column_name", keyColumn="your_key_column_name")` +Alternatively you may annotate the attribute with `@MappedCollection(idColumn="your_column_name", keyColumn="your_key_column_name")` * `List` is mapped as a `Map`. @@ -233,10 +233,10 @@ public class MyEntity { ---- ==== -The {javadoc-base}org/springframework/data/relational/core/mapping/Column.html[`@Column`] annotation can also be used on a reference type (one-to-one relationship) or on Sets, Lists, and Maps (one-to-many relationship) +The {javadoc-base}org/springframework/data/relational/core/mapping/MappedCollection.html[`@MappedCollection`] annotation can be used on a reference type (one-to-one relationship) or on Sets, Lists, and Maps (one-to-many relationship) On all these types the `value` element of the annotation is used to provide a custom name for the foreign key column referencing the id column in the other table. In the following example the corresponding table for the `MySubEntity` class has a name column, and the id column of the `MyEntity` id for relationship reasons. -The name of this `MySubEntity` class's id column can also be customized with the `value` element of the {javadoc-base}org/springframework/data/relational/core/mapping/Column.html[`@Column`] annotation: +The name of this `MySubEntity` class's id column can also be customized with the `idColumn` element of the {javadoc-base}org/springframework/data/relational/core/mapping/MappedCollection.html[`@MappedCollection`] annotation: ==== [source, java] @@ -245,7 +245,7 @@ public class MyEntity { @Id Integer id; - @Column("CUSTOM_COLUMN_NAME") + @MappedCollection(idColumn = "CUSTOM_COLUMN_NAME") Set name; } @@ -256,7 +256,7 @@ public class MySubEntity { ==== When using `List` and `Map` you must have an additional column for the position of a dataset in the `List` or the key value of the entity in the `Map`. -This additional column name may be customized with the `keyColumn` Element of the {javadoc-base}org/springframework/data/relational/core/mapping/Column.html[`@Column`] annotation: +This additional column name may be customized with the `keyColumn` Element of the {javadoc-base}org/springframework/data/relational/core/mapping/MappedCollection.html[`@MappedCollection`] annotation: ==== [source, java] @@ -265,7 +265,7 @@ public class MyEntity { @Id Integer id; - @Column(value = "CUSTOM_COLUMN_NAME", keyColumn = "CUSTOM_KEY_COLUMN_NAME") + @MappedCollection(idColumn = "CUSTOM_COLUMN_NAME", keyColumn = "CUSTOM_KEY_COLUMN_NAME") List name; } From f72aa6397bb69e68efe58a90161821ea79478428 Mon Sep 17 00:00:00 2001 From: Bastian Wilhelm Date: Fri, 8 Feb 2019 22:37:38 +0100 Subject: [PATCH 3/4] DATAJDBC-331 Modify @Author in JavaDoc --- .../springframework/data/relational/core/mapping/Column.java | 1 + .../data/relational/core/mapping/MappedCollection.java | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java index 013f902a71..74628320f4 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java @@ -26,6 +26,7 @@ * * @author Kazuki Shimizu * @author Florian Lüdiger + * @author Bastian Wilhelm */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java index 421b8318d2..19046cc250 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java @@ -24,8 +24,7 @@ /** * The annotation to configure the mapping from an collection in the database. * - * @author Kazuki Shimizu - * @author Florian Lüdiger + * @author Bastian Wilhelm */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) From 26f20b1a81b9469f9246524fdf4884edfd157348 Mon Sep 17 00:00:00 2001 From: Bastian Wilhelm Date: Mon, 11 Feb 2019 17:20:15 +0100 Subject: [PATCH 4/4] DATAJDBC-331 Polishing --- .../BasicRelationalPersistentProperty.java | 56 ++++++++++--------- .../data/relational/core/mapping/Column.java | 2 +- .../core/mapping/MappedCollection.java | 7 ++- 3 files changed, 37 insertions(+), 28 deletions(-) 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 1c98da75e3..91e3b5f137 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 @@ -21,8 +21,10 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Stream; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.PersistentEntity; @@ -57,8 +59,6 @@ public class BasicRelationalPersistentProperty extends AnnotationBasedPersistent private final RelationalMappingContext context; private final Lazy> columnName; - /** @deprecated see {@link Column#keyColumn()} */ - @Deprecated private final Lazy> keyColumnName; private final Lazy> collectionIdColumnName; private final Lazy> collectionKeyColumnName; private final Lazy isEmbedded; @@ -94,22 +94,34 @@ public BasicRelationalPersistentProperty(Property property, PersistentEntity Optional.ofNullable( // - findAnnotation(Column.class)) // - .map(Column::keyColumn) // - .filter(StringUtils::hasText) // - ); - - this.collectionIdColumnName = Lazy.of(() -> Optional.ofNullable( // - findAnnotation(MappedCollection.class)) // - .map(MappedCollection::idColumn) // - .filter(StringUtils::hasText)// + this.collectionIdColumnName = Lazy.of(() -> + Stream.concat( // + Stream.of( // + findAnnotation(MappedCollection.class)) // + .filter(Objects::nonNull) // + .map(MappedCollection::idColumn), // + Stream.of( // + findAnnotation(Column.class)) // + .filter(Objects::nonNull) // + .map(Column::value) // + ) + .filter(StringUtils::hasText) + .findFirst() ); - this.collectionKeyColumnName = Lazy.of(() -> Optional.ofNullable( // - findAnnotation(MappedCollection.class)) // - .map(MappedCollection::keyColumn) // - .filter(StringUtils::hasText)// + this.collectionKeyColumnName = Lazy.of(() -> + Stream.concat( // + Stream.of( // + findAnnotation(MappedCollection.class)) // + .filter(Objects::nonNull) // + .map(MappedCollection::keyColumn), // + Stream.of( // + findAnnotation(Column.class)) // + .filter(Objects::nonNull) // + .map(Column::keyColumn) // + ) + .filter(StringUtils::hasText) + .findFirst() ); } @@ -188,22 +200,14 @@ public RelationalPersistentEntity getOwner() { @Override public String getReverseColumnName() { - return collectionIdColumnName.get().orElseGet( - () -> columnName.get().orElseGet( - () -> context.getNamingStrategy().getReverseColumnName(this) - ) - ); + return collectionIdColumnName.get().orElseGet(() -> context.getNamingStrategy().getReverseColumnName(this)); } @Override public String getKeyColumn() { if (isQualified()) { - return collectionKeyColumnName.get().orElseGet( - () -> keyColumnName.get().orElseGet( - () -> context.getNamingStrategy().getKeyColumn(this) - ) - ); + return collectionKeyColumnName.get().orElseGet(() -> context.getNamingStrategy().getKeyColumn(this)); } else { return null; } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java index 74628320f4..549e61b40e 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Column.java @@ -41,7 +41,7 @@ /** * The column name for key columns of List or Map collections. * - * @deprecated Was used for collection mapping. Use {@link MappedCollection} instead of this. + * @deprecated since 1.1, was used for collection mapping. Use {@link MappedCollection} instead of this. */ @Deprecated String keyColumn() default ""; diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java index 19046cc250..1df6a893b0 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/MappedCollection.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 the original author or authors. + * Copyright 2019 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. @@ -24,6 +24,7 @@ /** * The annotation to configure the mapping from an collection in the database. * + * @since 1.1 * @author Bastian Wilhelm */ @Retention(RetentionPolicy.RUNTIME) @@ -33,11 +34,15 @@ /** * The column name for id column in the corresponding relationship table. + * If the default value (empty String) is used, the column name is resolved by the used + * {@link NamingStrategy} method {@link NamingStrategy#getReverseColumnName(RelationalPersistentProperty)} */ String idColumn() default ""; /** * The column name for key columns of List or Map collections in the corresponding relationship table. + * If the default value (empty String) is used, the column name is resolved by the used + * {@link NamingStrategy} method {@link NamingStrategy#getKeyColumn(RelationalPersistentProperty)} */ String keyColumn() default ""; }