40
40
import javax .persistence .Cacheable ;
41
41
import javax .persistence .CollectionTable ;
42
42
import javax .persistence .Column ;
43
+ import javax .persistence .DiscriminatorColumn ;
43
44
import javax .persistence .DiscriminatorType ;
44
45
import javax .persistence .DiscriminatorValue ;
45
46
import javax .persistence .ElementCollection ;
95
96
import org .hibernate .annotations .Check ;
96
97
import org .hibernate .annotations .CollectionId ;
97
98
import org .hibernate .annotations .Columns ;
99
+ import org .hibernate .annotations .DiscriminatorFormula ;
98
100
import org .hibernate .annotations .DiscriminatorOptions ;
99
101
import org .hibernate .annotations .Fetch ;
100
102
import org .hibernate .annotations .FetchProfile ;
@@ -567,12 +569,27 @@ public static void bindClass(
567
569
Ejb3JoinColumn [] inheritanceJoinedColumns = makeInheritanceJoinColumns (
568
570
clazzToProcess , mappings , inheritanceState , superEntity
569
571
);
570
- Ejb3DiscriminatorColumn discriminatorColumn = null ;
572
+
573
+ final Ejb3DiscriminatorColumn discriminatorColumn ;
571
574
if ( InheritanceType .SINGLE_TABLE .equals ( inheritanceState .getType () ) ) {
572
- discriminatorColumn = processDiscriminatorProperties (
573
- clazzToProcess , mappings , inheritanceState , entityBinder
575
+ discriminatorColumn = processSingleTableDiscriminatorProperties (
576
+ clazzToProcess ,
577
+ mappings ,
578
+ inheritanceState ,
579
+ entityBinder
580
+ );
581
+ }
582
+ else if ( InheritanceType .JOINED .equals ( inheritanceState .getType () ) ) {
583
+ discriminatorColumn = processJoinedDiscriminatorProperties (
584
+ clazzToProcess ,
585
+ mappings ,
586
+ inheritanceState ,
587
+ entityBinder
574
588
);
575
589
}
590
+ else {
591
+ discriminatorColumn = null ;
592
+ }
576
593
577
594
entityBinder .setProxy ( clazzToProcess .getAnnotation ( Proxy .class ) );
578
595
entityBinder .setBatchSize ( clazzToProcess .getAnnotation ( BatchSize .class ) );
@@ -617,46 +634,71 @@ else if ( clazzToProcess.isAnnotationPresent( Table.class ) ) {
617
634
618
635
OnDelete onDeleteAnn = clazzToProcess .getAnnotation ( OnDelete .class );
619
636
boolean onDeleteAppropriate = false ;
620
- if ( InheritanceType .JOINED .equals ( inheritanceState .getType () ) && inheritanceState .hasParents () ) {
621
- onDeleteAppropriate = true ;
622
- final JoinedSubclass jsc = ( JoinedSubclass ) persistentClass ;
623
- SimpleValue key = new DependantValue ( mappings , jsc .getTable (), jsc .getIdentifier () );
624
- jsc .setKey ( key );
625
- ForeignKey fk = clazzToProcess .getAnnotation ( ForeignKey .class );
626
- if ( fk != null && !BinderHelper .isEmptyAnnotationValue ( fk .name () ) ) {
627
- key .setForeignKeyName ( fk .name () );
628
- }
629
- if ( onDeleteAnn != null ) {
630
- key .setCascadeDeleteEnabled ( OnDeleteAction .CASCADE .equals ( onDeleteAnn .action () ) );
631
- }
632
- else {
633
- key .setCascadeDeleteEnabled ( false );
634
- }
635
- //we are never in a second pass at that stage, so queue it
636
- SecondPass sp = new JoinedSubclassFkSecondPass ( jsc , inheritanceJoinedColumns , key , mappings );
637
- mappings .addSecondPass ( sp );
638
- mappings .addSecondPass ( new CreateKeySecondPass ( jsc ) );
639
637
638
+ // todo : sucks that this is separate from RootClass distinction
639
+ final boolean isInheritanceRoot = !inheritanceState .hasParents ();
640
+ final boolean hasSubclasses = inheritanceState .hasSiblings ();
641
+
642
+ if ( InheritanceType .JOINED .equals ( inheritanceState .getType () ) ) {
643
+ if ( inheritanceState .hasParents () ) {
644
+ onDeleteAppropriate = true ;
645
+ final JoinedSubclass jsc = ( JoinedSubclass ) persistentClass ;
646
+ SimpleValue key = new DependantValue ( mappings , jsc .getTable (), jsc .getIdentifier () );
647
+ jsc .setKey ( key );
648
+ ForeignKey fk = clazzToProcess .getAnnotation ( ForeignKey .class );
649
+ if ( fk != null && !BinderHelper .isEmptyAnnotationValue ( fk .name () ) ) {
650
+ key .setForeignKeyName ( fk .name () );
651
+ }
652
+ if ( onDeleteAnn != null ) {
653
+ key .setCascadeDeleteEnabled ( OnDeleteAction .CASCADE .equals ( onDeleteAnn .action () ) );
654
+ }
655
+ else {
656
+ key .setCascadeDeleteEnabled ( false );
657
+ }
658
+ //we are never in a second pass at that stage, so queue it
659
+ SecondPass sp = new JoinedSubclassFkSecondPass ( jsc , inheritanceJoinedColumns , key , mappings );
660
+ mappings .addSecondPass ( sp );
661
+ mappings .addSecondPass ( new CreateKeySecondPass ( jsc ) );
662
+ }
663
+
664
+ if ( isInheritanceRoot ) {
665
+ // the class we are processing is the root of the hierarchy, see if we had a discriminator column
666
+ // (it is perfectly valid for joined subclasses to not have discriminators).
667
+ if ( discriminatorColumn != null ) {
668
+ // we have a discriminator column
669
+ if ( hasSubclasses || !discriminatorColumn .isImplicit () ) {
670
+ bindDiscriminatorColumnToRootPersistentClass (
671
+ (RootClass ) persistentClass ,
672
+ discriminatorColumn ,
673
+ entityBinder .getSecondaryTables (),
674
+ propertyHolder ,
675
+ mappings
676
+ );
677
+ //bind it again since the type might have changed
678
+ entityBinder .bindDiscriminatorValue ();
679
+ }
680
+ }
681
+ }
640
682
}
641
683
else if ( InheritanceType .SINGLE_TABLE .equals ( inheritanceState .getType () ) ) {
642
- if ( ! inheritanceState .hasParents () ) {
643
- if ( inheritanceState .hasSiblings () || !discriminatorColumn .isImplicit () ) {
644
- //need a discriminator column
645
- bindDiscriminatorToPersistentClass (
646
- ( RootClass ) persistentClass ,
684
+ if ( isInheritanceRoot ) {
685
+ if ( hasSubclasses || !discriminatorColumn .isImplicit () ) {
686
+ bindDiscriminatorColumnToRootPersistentClass (
687
+ (RootClass ) persistentClass ,
647
688
discriminatorColumn ,
648
689
entityBinder .getSecondaryTables (),
649
690
propertyHolder ,
650
691
mappings
651
692
);
652
- entityBinder .bindDiscriminatorValue ();//bind it again since the type might have changed
693
+ //bind it again since the type might have changed
694
+ entityBinder .bindDiscriminatorValue ();
653
695
}
654
696
}
655
697
}
656
- else if ( InheritanceType .TABLE_PER_CLASS .equals ( inheritanceState .getType () ) ) {
657
- //nothing to do
698
+
699
+ if ( onDeleteAnn != null && !onDeleteAppropriate ) {
700
+ LOG .invalidOnDeleteAnnotation (propertyHolder .getEntityName ());
658
701
}
659
- if (onDeleteAnn != null && !onDeleteAppropriate ) LOG .invalidOnDeleteAnnotation (propertyHolder .getEntityName ());
660
702
661
703
// try to find class level generators
662
704
HashMap <String , IdGenerator > classGenerators = buildLocalGenerators ( clazzToProcess , mappings );
@@ -714,32 +756,43 @@ else if ( InheritanceType.TABLE_PER_CLASS.equals( inheritanceState.getType() ) )
714
756
715
757
}
716
758
717
- // parse everything discriminator column relevant in case of single table inheritance
718
- private static Ejb3DiscriminatorColumn processDiscriminatorProperties (XClass clazzToProcess , Mappings mappings , InheritanceState inheritanceState , EntityBinder entityBinder ) {
759
+ /**
760
+ * Process all discriminator-related metadata per rules for "single table" inheritance
761
+ */
762
+ private static Ejb3DiscriminatorColumn processSingleTableDiscriminatorProperties (
763
+ XClass clazzToProcess ,
764
+ Mappings mappings ,
765
+ InheritanceState inheritanceState ,
766
+ EntityBinder entityBinder ) {
767
+ final boolean isRoot = !inheritanceState .hasParents ();
768
+
719
769
Ejb3DiscriminatorColumn discriminatorColumn = null ;
720
770
javax .persistence .DiscriminatorColumn discAnn = clazzToProcess .getAnnotation (
721
771
javax .persistence .DiscriminatorColumn .class
722
772
);
723
- DiscriminatorType discriminatorType = discAnn != null ?
724
- discAnn .discriminatorType () :
725
- DiscriminatorType .STRING ;
773
+ DiscriminatorType discriminatorType = discAnn != null
774
+ ? discAnn .discriminatorType ()
775
+ : DiscriminatorType .STRING ;
726
776
727
777
org .hibernate .annotations .DiscriminatorFormula discFormulaAnn = clazzToProcess .getAnnotation (
728
778
org .hibernate .annotations .DiscriminatorFormula .class
729
779
);
730
- if ( ! inheritanceState . hasParents () ) {
780
+ if ( isRoot ) {
731
781
discriminatorColumn = Ejb3DiscriminatorColumn .buildDiscriminatorColumn (
732
- discriminatorType , discAnn , discFormulaAnn , mappings
782
+ discriminatorType ,
783
+ discAnn ,
784
+ discFormulaAnn ,
785
+ mappings
733
786
);
734
787
}
735
- if ( discAnn != null && inheritanceState . hasParents () ) {
788
+ if ( discAnn != null && ! isRoot ) {
736
789
LOG .invalidDiscriminatorAnnotation ( clazzToProcess .getName () );
737
790
}
738
791
739
- String discrimValue = clazzToProcess .isAnnotationPresent ( DiscriminatorValue .class ) ?
740
- clazzToProcess .getAnnotation ( DiscriminatorValue .class ).value () :
741
- null ;
742
- entityBinder .setDiscriminatorValue ( discrimValue );
792
+ final String discriminatorValue = clazzToProcess .isAnnotationPresent ( DiscriminatorValue .class )
793
+ ? clazzToProcess .getAnnotation ( DiscriminatorValue .class ).value ()
794
+ : null ;
795
+ entityBinder .setDiscriminatorValue ( discriminatorValue );
743
796
744
797
DiscriminatorOptions discriminatorOptions = clazzToProcess .getAnnotation ( DiscriminatorOptions .class );
745
798
if ( discriminatorOptions != null ) {
@@ -750,6 +803,53 @@ private static Ejb3DiscriminatorColumn processDiscriminatorProperties(XClass cla
750
803
return discriminatorColumn ;
751
804
}
752
805
806
+ /**
807
+ * Process all discriminator-related metadata per rules for "joined" inheritance
808
+ */
809
+ private static Ejb3DiscriminatorColumn processJoinedDiscriminatorProperties (
810
+ XClass clazzToProcess ,
811
+ Mappings mappings ,
812
+ InheritanceState inheritanceState ,
813
+ EntityBinder entityBinder ) {
814
+ if ( clazzToProcess .isAnnotationPresent ( DiscriminatorFormula .class ) ) {
815
+ throw new MappingException ( "@DiscriminatorFormula on joined inheritance not supported at this time" );
816
+ }
817
+
818
+
819
+ // DiscriminatorValue handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
820
+
821
+ final DiscriminatorValue discriminatorValueAnnotation = clazzToProcess .getAnnotation ( DiscriminatorValue .class );
822
+ final String discriminatorValue = discriminatorValueAnnotation != null
823
+ ? clazzToProcess .getAnnotation ( DiscriminatorValue .class ).value ()
824
+ : null ;
825
+ entityBinder .setDiscriminatorValue ( discriminatorValue );
826
+
827
+
828
+ // DiscriminatorColumn handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
829
+
830
+ final DiscriminatorColumn discriminatorColumnAnnotation = clazzToProcess .getAnnotation ( DiscriminatorColumn .class );
831
+ if ( !inheritanceState .hasParents () ) {
832
+ if ( discriminatorColumnAnnotation != null || mappings .useImplicitDiscriminatorColumnForJoinedInheritance () ) {
833
+ final DiscriminatorType discriminatorType = discriminatorColumnAnnotation != null
834
+ ? discriminatorColumnAnnotation .discriminatorType ()
835
+ : DiscriminatorType .STRING ;
836
+ return Ejb3DiscriminatorColumn .buildDiscriminatorColumn (
837
+ discriminatorType ,
838
+ discriminatorColumnAnnotation ,
839
+ null ,
840
+ mappings
841
+ );
842
+ }
843
+ }
844
+ else {
845
+ if ( discriminatorColumnAnnotation != null ) {
846
+ LOG .invalidDiscriminatorAnnotation ( clazzToProcess .getName () );
847
+ }
848
+ }
849
+
850
+ return null ;
851
+ }
852
+
753
853
private static void processIdPropertiesIfNotAlready (
754
854
Map <XClass , InheritanceState > inheritanceStatePerClass ,
755
855
Mappings mappings ,
@@ -1308,7 +1408,7 @@ private static void bindTypeDef(TypeDef defAnn, Mappings mappings) {
1308
1408
}
1309
1409
1310
1410
1311
- private static void bindDiscriminatorToPersistentClass (
1411
+ private static void bindDiscriminatorColumnToRootPersistentClass (
1312
1412
RootClass rootClass ,
1313
1413
Ejb3DiscriminatorColumn discriminatorColumn ,
1314
1414
Map <String , Join > secondaryTables ,
@@ -1320,10 +1420,10 @@ private static void bindDiscriminatorToPersistentClass(
1320
1420
}
1321
1421
discriminatorColumn .setJoins ( secondaryTables );
1322
1422
discriminatorColumn .setPropertyHolder ( propertyHolder );
1323
- SimpleValue discrim = new SimpleValue ( mappings , rootClass .getTable () );
1324
- rootClass .setDiscriminator ( discrim );
1325
- discriminatorColumn .linkWithValue ( discrim );
1326
- discrim .setTypeName ( discriminatorColumn .getDiscriminatorTypeName () );
1423
+ SimpleValue discriminatorColumnBinding = new SimpleValue ( mappings , rootClass .getTable () );
1424
+ rootClass .setDiscriminator ( discriminatorColumnBinding );
1425
+ discriminatorColumn .linkWithValue ( discriminatorColumnBinding );
1426
+ discriminatorColumnBinding .setTypeName ( discriminatorColumn .getDiscriminatorTypeName () );
1327
1427
rootClass .setPolymorphic ( true );
1328
1428
if ( LOG .isTraceEnabled () ) {
1329
1429
LOG .tracev ( "Setting discriminator for entity {0}" , rootClass .getEntityName () );
0 commit comments