66
77import java .lang .annotation .Annotation ;
88import java .util .ArrayList ;
9- import java .util .Collections ;
109import java .util .EnumSet ;
1110import java .util .HashMap ;
1211import java .util .LinkedHashSet ;
1312import java .util .List ;
14- import java .util .Locale ;
1513import java .util .Map ;
1614import java .util .Set ;
1715import java .util .StringTokenizer ;
3331import org .hibernate .boot .spi .InFlightMetadataCollector ;
3432import org .hibernate .boot .spi .MetadataBuildingContext ;
3533import org .hibernate .boot .spi .PropertyData ;
36- import org .hibernate .internal .log .DeprecationLogger ;
3734import org .hibernate .internal .util .collections .ArrayHelper ;
3835import org .hibernate .mapping .Any ;
3936import org .hibernate .mapping .AttributeContainer ;
5249import org .hibernate .mapping .Value ;
5350import org .hibernate .models .spi .AnnotationTarget ;
5451import org .hibernate .models .spi .ClassDetails ;
55- import org .hibernate .models .spi .ClassDetailsRegistry ;
5652import org .hibernate .models .spi .MemberDetails ;
5753import org .hibernate .models .spi .SourceModelBuildingContext ;
5854import org .hibernate .models .spi .TypeDetails ;
5955import org .hibernate .type .descriptor .java .JavaType ;
6056
6157import jakarta .persistence .ConstraintMode ;
62- import jakarta .persistence .Embeddable ;
63- import jakarta .persistence .EmbeddedId ;
6458import jakarta .persistence .FetchType ;
6559import jakarta .persistence .ForeignKey ;
6660import jakarta .persistence .ManyToOne ;
6761import jakarta .persistence .OneToOne ;
6862
6963import static jakarta .persistence .ConstraintMode .NO_CONSTRAINT ;
7064import static jakarta .persistence .ConstraintMode .PROVIDER_DEFAULT ;
65+ import static java .util .Collections .addAll ;
7166import static org .hibernate .boot .model .internal .AnnotatedColumn .buildColumnOrFormulaFromAnnotation ;
7267import static org .hibernate .boot .model .internal .AnyBinder .resolveImplicitDiscriminatorStrategy ;
68+ import static org .hibernate .boot .model .internal .ForeignKeyType .NON_PRIMARY_KEY_REFERENCE ;
69+ import static org .hibernate .internal .log .DeprecationLogger .DEPRECATION_LOGGER ;
7370import static org .hibernate .internal .util .StringHelper .isEmpty ;
7471import static org .hibernate .internal .util .StringHelper .isNotBlank ;
7572import static org .hibernate .internal .util .StringHelper .qualifier ;
@@ -148,15 +145,17 @@ public static void createSyntheticPropertyReference(
148145 boolean inverse ,
149146 MetadataBuildingContext context ) {
150147 // this work is not necessary for a primary key reference
151- if ( joinColumns .getReferencedColumnsType ( targetEntity ) == ForeignKeyType . NON_PRIMARY_KEY_REFERENCE ) { // && !firstColumn.isImplicit()
148+ if ( joinColumns .getReferencedColumnsType ( targetEntity ) == NON_PRIMARY_KEY_REFERENCE ) { // && !firstColumn.isImplicit()
152149 // all the columns have to belong to the same table;
153150 // figure out which table has the columns by looking
154151 // for a PersistentClass or Join in the hierarchy of
155152 // the target entity which has the first column
156- final AttributeContainer columnOwner = findReferencedColumnOwner ( targetEntity , joinColumns .getJoinColumns ().get (0 ), context );
153+ final AttributeContainer columnOwner =
154+ findReferencedColumnOwner ( targetEntity , joinColumns .getJoinColumns ().get (0 ), context );
157155 checkColumnInSameTable ( joinColumns , targetEntity , associatedEntity , context , columnOwner );
158156 // find all properties mapped to each column
159- final List <Property > properties = findPropertiesByColumns ( columnOwner , joinColumns , associatedEntity , context );
157+ final List <Property > properties =
158+ findPropertiesByColumns ( columnOwner , joinColumns , associatedEntity , context );
160159 // create a Property along with the new synthetic
161160 // Component if necessary (or reuse the existing
162161 // Property that matches exactly)
@@ -192,13 +191,13 @@ private static void checkColumnInSameTable(
192191 PersistentClass targetEntity ,
193192 PersistentClass associatedEntity ,
194193 MetadataBuildingContext context ,
195- Object columnOwner ) {
194+ AttributeContainer columnOwner ) {
196195 if ( joinColumns .hasMappedBy () ) {
197196 // we should only get called for owning side of association
198197 throw new AssertionFailure ("no need to create synthetic properties for unowned collections" );
199198 }
200199 for ( AnnotatedJoinColumn column : joinColumns .getJoinColumns () ) {
201- final Object owner = findReferencedColumnOwner ( targetEntity , column , context );
200+ final AttributeContainer owner = findReferencedColumnOwner ( targetEntity , column , context );
202201 if ( owner == null ) {
203202 throw new AnnotationException ( "A '@JoinColumn' for association "
204203 + associationMessage ( associatedEntity , joinColumns )
@@ -261,33 +260,29 @@ private static void registerSyntheticProperty(
261260 String propertyName ,
262261 String syntheticPropertyName ,
263262 MetadataBuildingContext context ) {
264- if ( value instanceof ToOne ) {
265- ( ( ToOne ) value ) .setReferencedPropertyName ( syntheticPropertyName );
266- ( ( ToOne ) value ) .setReferenceToPrimaryKey ( false );
263+ if ( value instanceof ToOne toOne ) {
264+ toOne .setReferencedPropertyName ( syntheticPropertyName );
265+ toOne .setReferenceToPrimaryKey ( false );
267266 context .getMetadataCollector ().addUniquePropertyReference (
268267 ownerEntity .getEntityName (),
269268 syntheticPropertyName
270269 );
271270 }
272- else if ( value instanceof Collection ) {
273- ( ( Collection ) value ) .setReferencedPropertyName ( syntheticPropertyName );
271+ else if ( value instanceof Collection collection ) {
272+ collection .setReferencedPropertyName ( syntheticPropertyName );
274273 //not unique because we could create a mtm wo association table
275274 context .getMetadataCollector ().addPropertyReference (
276275 ownerEntity .getEntityName (),
277276 syntheticPropertyName
278277 );
279278 }
280279 else {
281- throw new AssertionFailure (
282- "Do a property ref on an unexpected Value type: "
283- + value .getClass ().getName ()
284- );
280+ throw new AssertionFailure ( "Property ref on an unexpected Value type: " + value .getClass ().getName () );
285281 }
286- context .getMetadataCollector ().addPropertyReferencedAssociation (
287- ( inverse ? "inverse__" : "" ) + associatedClass .getEntityName (),
288- propertyName ,
289- syntheticPropertyName
290- );
282+ final String associatedEntityName = associatedClass .getEntityName ();
283+ final String generatedName = inverse ? "inverse__" + associatedEntityName : associatedEntityName ;
284+ context .getMetadataCollector ()
285+ .addPropertyReferencedAssociation ( generatedName , propertyName , syntheticPropertyName );
291286 }
292287
293288 private static String syntheticPropertyName (
@@ -306,11 +301,14 @@ private static String associationMessage(PersistentClass associatedEntity, Annot
306301 if ( associatedEntity != null ) {
307302 return "'" + associatedEntity .getEntityName () + "." + joinColumns .getPropertyName () + "'" ;
308303 }
309- else if ( joinColumns .getPropertyHolder () != null ) {
310- return "'" + joinColumns .getPropertyHolder ().getEntityName () + "." + joinColumns .getPropertyName () + "'" ;
311- }
312304 else {
313- return "" ;
305+ final PropertyHolder propertyHolder = joinColumns .getPropertyHolder ();
306+ if ( propertyHolder != null ) {
307+ return "'" + propertyHolder .getEntityName () + "." + joinColumns .getPropertyName () + "'" ;
308+ }
309+ else {
310+ return "" ;
311+ }
314312 }
315313 }
316314
@@ -392,7 +390,7 @@ private static Property cloneProperty(PersistentClass ownerEntity, MetadataBuild
392390 * and other attributes.
393391 */
394392 public static Property shallowCopy (Property property ) {
395- Property clone = new SyntheticProperty ();
393+ final Property clone = new SyntheticProperty ();
396394 clone .setCascade ( property .getCascade () );
397395 clone .setInsertable ( property .isInsertable () );
398396 clone .setLazy ( property .isLazy () );
@@ -409,25 +407,12 @@ public static Property shallowCopy(Property property) {
409407 }
410408
411409 private static List <Property > findPropertiesByColumns (
412- Object columnOwner ,
410+ AttributeContainer columnOwner ,
413411 AnnotatedJoinColumns columns ,
414412 PersistentClass associatedEntity ,
415413 MetadataBuildingContext context ) {
416414
417- final Table referencedTable ;
418- if ( columnOwner instanceof PersistentClass ) {
419- referencedTable = ( (PersistentClass ) columnOwner ).getTable ();
420- }
421- else if ( columnOwner instanceof Join ) {
422- referencedTable = ( (Join ) columnOwner ).getTable ();
423- }
424- else {
425- throw new AssertionFailure (
426- columnOwner == null ?
427- "columnOwner is null" :
428- "columnOwner neither PersistentClass nor Join: " + columnOwner .getClass ()
429- );
430- }
415+ final Table referencedTable = columnOwner .getTable ();
431416
432417 // Build the list of column names in the exact order they were
433418 // specified by the @JoinColumn annotations.
@@ -923,16 +908,18 @@ public static String getCascadeStrategy(
923908 boolean orphanRemoval ,
924909 MetadataBuildingContext context ) {
925910 final EnumSet <CascadeType > cascadeTypes = convertToHibernateCascadeType ( ejbCascades );
926- final CascadeType [] hibernateCascades = hibernateCascadeAnnotation == null
927- ? null
928- : hibernateCascadeAnnotation .value ();
911+ final CascadeType [] hibernateCascades =
912+ hibernateCascadeAnnotation == null ? null : hibernateCascadeAnnotation .value ();
929913 if ( !isEmpty ( hibernateCascades ) ) {
930- Collections . addAll ( cascadeTypes , hibernateCascades );
914+ addAll ( cascadeTypes , hibernateCascades );
931915 }
932916 if ( orphanRemoval ) {
933917 cascadeTypes .add ( CascadeType .DELETE_ORPHAN );
934918 cascadeTypes .add ( CascadeType .REMOVE );
935919 }
920+ if ( cascadeTypes .contains ( CascadeType .REPLICATE ) ) {
921+ warnAboutDeprecatedCascadeType ( CascadeType .REPLICATE );
922+ }
936923 cascadeTypes .addAll ( context .getEffectiveDefaults ().getDefaultCascadeTypes () );
937924 return renderCascadeTypeList ( cascadeTypes );
938925 }
@@ -960,68 +947,31 @@ private static CascadeType convertCascadeType(jakarta.persistence.CascadeType ca
960947
961948 private static String renderCascadeTypeList (EnumSet <CascadeType > cascadeTypes ) {
962949 final StringBuilder cascade = new StringBuilder ();
963- for ( CascadeType cascadeType : cascadeTypes ) {
964- switch ( cascadeType ) {
965- case ALL :
966- cascade .append ( "," ).append ( "all" );
967- break ;
968- case PERSIST :
969- cascade .append ( "," ).append ( "persist" );
970- break ;
971- case MERGE :
972- cascade .append ( "," ).append ( "merge" );
973- break ;
974- case LOCK :
975- cascade .append ( "," ).append ( "lock" );
976- break ;
977- case REFRESH :
978- cascade .append ( "," ).append ( "refresh" );
979- break ;
980- case DETACH :
981- cascade .append ( "," ).append ( "evict" );
982- break ;
983- case REMOVE :
984- cascade .append ( "," ).append ( "delete" );
985- break ;
986- case DELETE_ORPHAN :
987- cascade .append ( "," ).append ( "delete-orphan" );
988- break ;
989- case REPLICATE :
990- warnAboutDeprecatedCascadeType ( CascadeType .REPLICATE );
991- cascade .append ( "," ).append ( "replicate" );
992- break ;
993- }
950+ for ( CascadeType cascadeType : cascadeTypes ) {
951+ cascade .append ( "," );
952+ cascade .append ( switch ( cascadeType ) {
953+ case ALL -> "all" ;
954+ case PERSIST -> "persist" ;
955+ case MERGE -> "merge" ;
956+ case LOCK -> "lock" ;
957+ case REFRESH -> "refresh" ;
958+ case DETACH -> "evict" ;
959+ case REMOVE -> "delete" ;
960+ case DELETE_ORPHAN -> "delete-orphan" ;
961+ case REPLICATE -> "replicate" ;
962+ } );
994963 }
995964 return cascade .isEmpty () ? "none" : cascade .substring (1 );
996965 }
997966
998967 private static void warnAboutDeprecatedCascadeType (CascadeType cascadeType ) {
999- DeprecationLogger .DEPRECATION_LOGGER .warnf (
1000- "%s.%s is deprecated" ,
1001- CascadeType .class .getName (),
1002- cascadeType .name ().toLowerCase ( Locale .ROOT )
1003- );
1004- }
1005-
1006- private static void warnAboutDeprecatedCascadeType (CascadeType oldType , CascadeType newType ) {
1007- DeprecationLogger .DEPRECATION_LOGGER .warnf (
1008- "%s.%s is deprecated, use %s.%s instead" ,
1009- CascadeType .class .getName (),
1010- oldType .name ().toLowerCase ( Locale .ROOT ),
1011- CascadeType .class .getName (),
1012- newType .name ().toLowerCase ( Locale .ROOT )
1013- );
968+ DEPRECATION_LOGGER .warnf ( "CascadeType.%s is deprecated" , cascadeType .name () );
1014969 }
1015970
1016971 static boolean isGlobalGeneratorNameGlobal (MetadataBuildingContext context ) {
1017972 return context .getBootstrapContext ().getJpaCompliance ().isGlobalGeneratorScopeEnabled ();
1018973 }
1019974
1020- static boolean isCompositeId (ClassDetails idClass , MemberDetails idProperty ) {
1021- return idClass .hasDirectAnnotationUsage ( Embeddable .class )
1022- || idProperty .hasDirectAnnotationUsage ( EmbeddedId .class );
1023- }
1024-
1025975 public static boolean isDefault (ClassDetails clazz ) {
1026976 return clazz == ClassDetails .VOID_CLASS_DETAILS ;
1027977 }
@@ -1036,33 +986,38 @@ public static void checkMappedByType(
1036986 String propertyName ,
1037987 PropertyHolder propertyHolder ,
1038988 Map <String , PersistentClass > persistentClasses ) {
1039- final ToOne toOne ;
1040- if ( targetValue instanceof Collection ) {
1041- toOne = ( ToOne ) ( ( Collection ) targetValue ). getElement ( );
989+ if ( targetValue instanceof Collection collection ) {
990+ final ToOne element = ( ToOne ) collection . getElement ();
991+ checkMappedByType ( mappedBy , propertyName , propertyHolder , persistentClasses , element );
1042992 }
1043- else if ( targetValue instanceof ToOne ) {
1044- toOne = (ToOne ) targetValue ;
1045- }
1046- else {
1047- // Nothing to check, EARLY EXIT
1048- return ;
993+ else if ( targetValue instanceof ToOne toOne ) {
994+ checkMappedByType ( mappedBy , propertyName , propertyHolder , persistentClasses , toOne );
1049995 }
996+ }
997+
998+ private static void checkMappedByType (
999+ String mappedBy ,
1000+ String propertyName ,
1001+ PropertyHolder propertyHolder ,
1002+ Map <String , PersistentClass > persistentClasses ,
1003+ ToOne toOne ) {
10501004 final String referencedEntityName = toOne .getReferencedEntityName ();
10511005 final PersistentClass referencedClass = persistentClasses .get ( referencedEntityName );
10521006 PersistentClass ownerClass = propertyHolder .getPersistentClass ();
10531007 while ( ownerClass != null ) {
10541008 if ( checkReferencedClass ( ownerClass , referencedClass ) ) {
1009+ // the two entities map to the same table
1010+ // so we are good
10551011 return ;
10561012 }
1057- else {
1058- ownerClass = ownerClass .getSuperPersistentClass ();
1059- }
1013+ ownerClass = ownerClass .getSuperPersistentClass ();
10601014 }
1015+ // we could not find any entity mapping to the same table
10611016 throw new AnnotationException (
10621017 "Association '" + qualify ( propertyHolder .getPath (), propertyName )
1063- + "' is 'mappedBy' a property named '" + mappedBy
1064- + "' which references the wrong entity type '" + referencedEntityName
1065- + "', expected '" + propertyHolder .getEntityName () + "'"
1018+ + "' is 'mappedBy' a property named '" + mappedBy
1019+ + "' which references the wrong entity type '" + referencedEntityName
1020+ + "', expected '" + propertyHolder .getEntityName () + "'"
10661021 );
10671022 }
10681023
@@ -1111,21 +1066,20 @@ public static <A extends Annotation> A extractFromPackage(
11111066
11121067 final String declaringClassName = classDetails .getName ();
11131068 final String packageName = qualifier ( declaringClassName );
1114-
11151069 if ( isEmpty ( packageName ) ) {
11161070 return null ;
11171071 }
1118- final SourceModelBuildingContext sourceModelContext = context .getMetadataCollector ().getSourceModelBuildingContext ();
1119- final ClassDetailsRegistry classDetailsRegistry = sourceModelContext .getClassDetailsRegistry ();
1120-
1121- final String packageInfoName = packageName + ".package-info" ;
1122- try {
1123- final ClassDetails packageInfoClassDetails = classDetailsRegistry .resolveClassDetails ( packageInfoName );
1124- return packageInfoClassDetails .getAnnotationUsage ( annotationType , sourceModelContext );
1125- }
1126- catch (ClassLoadingException ignore ) {
1072+ else {
1073+ final SourceModelBuildingContext sourceModelContext =
1074+ context .getMetadataCollector ().getSourceModelBuildingContext ();
1075+ try {
1076+ return sourceModelContext .getClassDetailsRegistry ()
1077+ .resolveClassDetails ( packageName + ".package-info" )
1078+ .getAnnotationUsage ( annotationType , sourceModelContext );
1079+ }
1080+ catch (ClassLoadingException ignore ) {
1081+ return null ;
1082+ }
11271083 }
1128-
1129- return null ;
11301084 }
11311085}
0 commit comments