From 491b1bc06fcfb36dbe9aff3f68da0cfcbed817d1 Mon Sep 17 00:00:00 2001 From: Gavin Date: Sun, 25 Dec 2022 21:20:28 +0100 Subject: [PATCH] HHH-15935 add discriminatorType to @DiscriminatorFormula --- .../annotations/DiscriminatorFormula.java | 47 ++++++++++++++++++- .../AnnotatedDiscriminatorColumn.java | 13 ++++- .../boot/model/internal/EntityBinder.java | 10 +--- .../annotations/sharedfk/AbstractChild.java | 9 ++-- .../annotations/sharedfk/ConcreteChild1.java | 1 - .../annotations/sharedfk/ConcreteChild2.java | 1 - .../orm/test/annotations/sharedfk/Parent.java | 2 +- 7 files changed, 65 insertions(+), 18 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/DiscriminatorFormula.java b/hibernate-core/src/main/java/org/hibernate/annotations/DiscriminatorFormula.java index a6301df28a..d3014d6323 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/DiscriminatorFormula.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/DiscriminatorFormula.java @@ -6,9 +6,12 @@ */ package org.hibernate.annotations; +import jakarta.persistence.DiscriminatorType; + import java.lang.annotation.Retention; import java.lang.annotation.Target; +import static jakarta.persistence.DiscriminatorType.STRING; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -18,6 +21,40 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; * the hierarchy. *

* Used in place of the JPA {@link jakarta.persistence.DiscriminatorColumn}. + *

+ * For example, we might declare a supertype as follows: + *

{@code
+ * @Entity
+ * @DiscriminatorFormula(discriminatorType = INTEGER,
+ * 		value = "case when value1 is not null then 1 when value2 is not null then 2 end")
+ * public abstract class AbstractChild {
+ *     @Id
+ *     @GeneratedValue
+ *     Integer id;
+ *     ...
+ * }
+ * }
+ * and then each concrete subclass must specify a matching discriminator value: + *
{@code
+ * @Entity
+ * @DiscriminatorValue("1")
+ * public class ConcreteChild1 extends AbstractChild {
+ *     @Basic(optional = false)
+ *     @Column(name = "VALUE1")
+ *     String value;
+ *     ...
+ * }
+ * }
+ *
{@code
+ * @Entity
+ * @DiscriminatorValue("2")
+ * public class ConcreteChild2 extends AbstractChild {
+ *     @Basic(optional = false)
+ *     @Column(name = "VALUE2")
+ *     String value;
+ *     ...
+ * }
+ * }
* * @see Formula * @see DialectOverride.DiscriminatorFormula @@ -25,11 +62,19 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; * @author Emmanuel Bernard * @author Steve Ebersole */ -@Target({TYPE}) +@Target(TYPE) @Retention(RUNTIME) public @interface DiscriminatorFormula { /** * The formula string. */ String value(); + + /** + * The type of value returned by the formula. + *

+ * This is required, unless the {@linkplain #value() + * expression} is of type {@code varchar} or similar. + */ + DiscriminatorType discriminatorType() default STRING; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java index 49d5d83019..dc81b873bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java @@ -43,18 +43,26 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn { } public static AnnotatedDiscriminatorColumn buildDiscriminatorColumn( - DiscriminatorType type, DiscriminatorColumn discriminatorColumn, DiscriminatorFormula discriminatorFormula, MetadataBuildingContext context) { final AnnotatedColumns parent = new AnnotatedColumns(); parent.setBuildingContext( context ); final AnnotatedDiscriminatorColumn column = new AnnotatedDiscriminatorColumn(); + final DiscriminatorType discriminatorType; if ( discriminatorFormula != null ) { + final DiscriminatorType type = discriminatorFormula.discriminatorType(); + if ( type == DiscriminatorType.STRING ) { + discriminatorType = discriminatorColumn == null ? type : discriminatorColumn.discriminatorType(); + } + else { + discriminatorType = type; + } column.setImplicit( false ); column.setFormula( discriminatorFormula.value() ); } else if ( discriminatorColumn != null ) { + discriminatorType = discriminatorColumn.discriminatorType(); column.setImplicit( false ); if ( !discriminatorColumn.columnDefinition().isEmpty() ) { column.setSqlType( discriminatorColumn.columnDefinition() ); @@ -65,9 +73,10 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn { column.setNullable( false ); } else { + discriminatorType = DiscriminatorType.STRING; column.setImplicit( true ); } - setDiscriminatorType( type, discriminatorColumn, column ); + setDiscriminatorType( discriminatorType, discriminatorColumn, column ); column.setParent( parent ); column.bind(); return column; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java index 7a2c9e565d..281f75b0bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java @@ -779,16 +779,13 @@ public class EntityBinder { private AnnotatedDiscriminatorColumn processSingleTableDiscriminatorProperties(InheritanceState inheritanceState) { final DiscriminatorColumn discriminatorColumn = annotatedClass.getAnnotation( DiscriminatorColumn.class ); - final DiscriminatorType discriminatorType = discriminatorColumn != null - ? discriminatorColumn.discriminatorType() - : DiscriminatorType.STRING; final DiscriminatorFormula discriminatorFormula = getOverridableAnnotation( annotatedClass, DiscriminatorFormula.class, context ); final boolean isRoot = !inheritanceState.hasParents(); final AnnotatedDiscriminatorColumn discriminator = isRoot - ? buildDiscriminatorColumn( discriminatorType, discriminatorColumn, discriminatorFormula, context ) + ? buildDiscriminatorColumn( discriminatorColumn, discriminatorFormula, context ) : null; if ( discriminatorColumn != null && !isRoot ) { //TODO: shouldn't this be an error?! @@ -835,10 +832,7 @@ public class EntityBinder { } if ( generateDiscriminatorColumn ) { - final DiscriminatorType discriminatorType = discriminatorColumn != null - ? discriminatorColumn.discriminatorType() - : DiscriminatorType.STRING; - return buildDiscriminatorColumn( discriminatorType, discriminatorColumn, null, context ); + return buildDiscriminatorColumn( discriminatorColumn, null, context ); } } else { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/AbstractChild.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/AbstractChild.java index 6df8f858b9..a8740541c4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/AbstractChild.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/AbstractChild.java @@ -3,13 +3,14 @@ package org.hibernate.orm.test.annotations.sharedfk; import jakarta.persistence.*; import org.hibernate.annotations.DiscriminatorFormula; +import static jakarta.persistence.DiscriminatorType.INTEGER; + @Entity @Table(name = " INHERITANCE_TAB") -@Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@Access(AccessType.FIELD) //@DiscriminatorColumn(name = "DISC") -@DiscriminatorFormula("case when value1 is not null then 1 when value2 is not null then 2 end") -public class AbstractChild { +@DiscriminatorFormula(discriminatorType = INTEGER, + value = "case when value1 is not null then 1 when value2 is not null then 2 end") +public abstract class AbstractChild { @Id @GeneratedValue @Column(name = "ID") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/ConcreteChild1.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/ConcreteChild1.java index 2885e0492f..786bb24dff 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/ConcreteChild1.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/ConcreteChild1.java @@ -8,7 +8,6 @@ import jakarta.persistence.DiscriminatorValue; import jakarta.persistence.Entity; @Entity -@Access(AccessType.FIELD) @DiscriminatorValue("1") public class ConcreteChild1 extends AbstractChild { @Basic(optional = false) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/ConcreteChild2.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/ConcreteChild2.java index d505edc5ec..0a83996076 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/ConcreteChild2.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/ConcreteChild2.java @@ -3,7 +3,6 @@ package org.hibernate.orm.test.annotations.sharedfk; import jakarta.persistence.*; @Entity -@Access(AccessType.FIELD) @DiscriminatorValue("2") public class ConcreteChild2 extends AbstractChild { @Basic(optional = false) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/Parent.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/Parent.java index 45072435b8..2021d910c4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/Parent.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/sharedfk/Parent.java @@ -19,8 +19,8 @@ public class Parent { @OneToMany( fetch= FetchType.EAGER) @JoinColumn(name = "PARENT_ID") @OrderColumn(name = "ORDER_C") - List child1s = new LinkedList<>(); + @OneToMany( fetch= FetchType.EAGER) @JoinColumn(name = "PARENT_ID") @OrderColumn(name = "ORDER_C")