diff --git a/pom.xml b/pom.xml index 680dddf73..ee6570e14 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,7 @@ 42.0.0 2.2.3 1.9.1 + 3.0.2 2017 diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java index 9108d1f41..8c24ad3b2 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/EntityRowMapperUnitTests.java @@ -558,13 +558,13 @@ public class EntityRowMapperUnitTests { static class WithEmptyEmbeddedImmutableValue { @Id Long id; - @Embedded(onEmpty = OnEmpty.USE_EMPTY) ImmutableValue embeddedImmutableValue; + @Embedded.Empty ImmutableValue embeddedImmutableValue; } static class WithEmbeddedPrimitiveImmutableValue { @Id Long id; - @Embedded(onEmpty = OnEmpty.USE_NULL) ImmutablePrimitiveValue embeddedImmutablePrimitiveValue; + @Embedded.Nullable ImmutablePrimitiveValue embeddedImmutablePrimitiveValue; } @Value diff --git a/spring-data-relational/pom.xml b/spring-data-relational/pom.xml index ba0ffea14..fa7f2f487 100644 --- a/spring-data-relational/pom.xml +++ b/spring-data-relational/pom.xml @@ -48,6 +48,13 @@ spring-core + + com.google.code.findbugs + jsr305 + ${jsr305.version} + true + + org.assertj assertj-core diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Embedded.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Embedded.java index 6c0afc7c3..4e83767a5 100644 --- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Embedded.java +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/mapping/Embedded.java @@ -21,6 +21,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import javax.annotation.meta.When; + +import org.springframework.core.annotation.AliasFor; + /** * The annotation to configure a value object as embedded in the current table. *

@@ -38,6 +42,8 @@ public @interface Embedded { /** * Set the load strategy for the embedded object if all contained fields yield {@literal null} values. + *

+ * {@link Nullable @Embedded.Nullable} and {@link Empty @Embedded.Empty} offer shortcuts for this. * * @return never {@link} null. */ @@ -57,4 +63,84 @@ public @interface Embedded { enum OnEmpty { USE_NULL, USE_EMPTY } + + /** + * Shortcut for a nullable embedded property. + * + *

+	 * 
+	 * @Embedded.Nullable
+	 * private Address address;
+	 * 
+	 * 
+ * + * as alternative to the more verbose + * + *
+	 * 
+	 *
+	 * @Embedded(onEmpty = USE_NULL)
+	 * @javax.annotation.Nonnull(when = When.MAYBE)
+	 * private Address address;
+	 *
+	 * 
+	 * 
+ * + * @author Christoph Strobl + * @since 1.1 + * @see Embedded#onEmpty() + */ + @Embedded(onEmpty = OnEmpty.USE_NULL) + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.FIELD, ElementType.METHOD }) + @javax.annotation.Nonnull(when = When.MAYBE) + @interface Nullable { + + /** + * @return prefix for columns in the embedded value object. An empty {@link String} by default. + */ + @AliasFor(annotation = Embedded.class, attribute = "prefix") + String prefix() default ""; + } + + /** + * Shortcut for an empty embedded property. + * + *
+	 * 
+	 * @Embedded.Empty
+	 * private Address address;
+	 * 
+	 * 
+ * + * as alternative to the more verbose + * + *
+	 * 
+	 *
+	 * @Embedded(onEmpty = USE_EMPTY)
+	 * @javax.annotation.Nonnull(when = When.NEVER)
+	 * private Address address;
+	 *
+	 * 
+	 * 
+ * + * @author Christoph Strobl + * @since 1.1 + * @see Embedded#onEmpty() + */ + @Embedded(onEmpty = OnEmpty.USE_EMPTY) + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ ElementType.FIELD, ElementType.METHOD }) + @javax.annotation.Nonnull(when = When.NEVER) + @interface Empty { + + /** + * @return prefix for columns in the embedded value object. An empty {@link String} by default. + */ + @AliasFor(annotation = Embedded.class, attribute = "prefix") + String prefix() default ""; + } } diff --git a/src/main/asciidoc/jdbc.adoc b/src/main/asciidoc/jdbc.adoc index b6bc0fd33..77d976108 100644 --- a/src/main/asciidoc/jdbc.adoc +++ b/src/main/asciidoc/jdbc.adoc @@ -314,6 +314,24 @@ public class EmbeddedEntity { If you need a value object multiple times in an entity, this can be achieved with the optional `prefix` element of the `@Embedded` annotation. This element represents a prefix and is prepend for each column name in the embedded object. +[TIP] +==== +Make use of the shortcuts `@Embedded.Nullable` & `@Embedded.Empty` for `@Embedded(onEmpty = USE_NULL)` and `@Embedded(onEmpty = USE_EMPTY)` to reduce verbositility and simultaneously set JSR-305 `@javax.annotation.Nonnull` accordingly. + +[source, java] +---- +public class MyEntity { + + @Id + Integer id; + + @Embedded.Nullable <1> + EmbeddedEntity embeddedEntity; +} +---- +<1> Shortcut for `@Embedded(onEmpty = USE_NULL)`. +==== + [[jdbc.entity-persistence.state-detection-strategies]] === Entity State Detection Strategies