6
6
7
7
import java .lang .annotation .Annotation ;
8
8
import java .util .ArrayList ;
9
- import java .util .Collections ;
10
9
import java .util .EnumSet ;
11
10
import java .util .HashMap ;
12
11
import java .util .LinkedHashSet ;
13
12
import java .util .List ;
14
- import java .util .Locale ;
15
13
import java .util .Map ;
16
14
import java .util .Set ;
17
15
import java .util .StringTokenizer ;
33
31
import org .hibernate .boot .spi .InFlightMetadataCollector ;
34
32
import org .hibernate .boot .spi .MetadataBuildingContext ;
35
33
import org .hibernate .boot .spi .PropertyData ;
36
- import org .hibernate .internal .log .DeprecationLogger ;
37
34
import org .hibernate .internal .util .collections .ArrayHelper ;
38
35
import org .hibernate .mapping .Any ;
39
36
import org .hibernate .mapping .AttributeContainer ;
52
49
import org .hibernate .mapping .Value ;
53
50
import org .hibernate .models .spi .AnnotationTarget ;
54
51
import org .hibernate .models .spi .ClassDetails ;
55
- import org .hibernate .models .spi .ClassDetailsRegistry ;
56
52
import org .hibernate .models .spi .MemberDetails ;
57
53
import org .hibernate .models .spi .SourceModelBuildingContext ;
58
54
import org .hibernate .models .spi .TypeDetails ;
59
55
import org .hibernate .type .descriptor .java .JavaType ;
60
56
61
57
import jakarta .persistence .ConstraintMode ;
62
- import jakarta .persistence .Embeddable ;
63
- import jakarta .persistence .EmbeddedId ;
64
58
import jakarta .persistence .FetchType ;
65
59
import jakarta .persistence .ForeignKey ;
66
60
import jakarta .persistence .ManyToOne ;
67
61
import jakarta .persistence .OneToOne ;
68
62
69
63
import static jakarta .persistence .ConstraintMode .NO_CONSTRAINT ;
70
64
import static jakarta .persistence .ConstraintMode .PROVIDER_DEFAULT ;
65
+ import static java .util .Collections .addAll ;
71
66
import static org .hibernate .boot .model .internal .AnnotatedColumn .buildColumnOrFormulaFromAnnotation ;
72
67
import 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 ;
73
70
import static org .hibernate .internal .util .StringHelper .isEmpty ;
74
71
import static org .hibernate .internal .util .StringHelper .isNotBlank ;
75
72
import static org .hibernate .internal .util .StringHelper .qualifier ;
@@ -148,15 +145,17 @@ public static void createSyntheticPropertyReference(
148
145
boolean inverse ,
149
146
MetadataBuildingContext context ) {
150
147
// 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()
152
149
// all the columns have to belong to the same table;
153
150
// figure out which table has the columns by looking
154
151
// for a PersistentClass or Join in the hierarchy of
155
152
// 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 );
157
155
checkColumnInSameTable ( joinColumns , targetEntity , associatedEntity , context , columnOwner );
158
156
// 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 );
160
159
// create a Property along with the new synthetic
161
160
// Component if necessary (or reuse the existing
162
161
// Property that matches exactly)
@@ -192,13 +191,13 @@ private static void checkColumnInSameTable(
192
191
PersistentClass targetEntity ,
193
192
PersistentClass associatedEntity ,
194
193
MetadataBuildingContext context ,
195
- Object columnOwner ) {
194
+ AttributeContainer columnOwner ) {
196
195
if ( joinColumns .hasMappedBy () ) {
197
196
// we should only get called for owning side of association
198
197
throw new AssertionFailure ("no need to create synthetic properties for unowned collections" );
199
198
}
200
199
for ( AnnotatedJoinColumn column : joinColumns .getJoinColumns () ) {
201
- final Object owner = findReferencedColumnOwner ( targetEntity , column , context );
200
+ final AttributeContainer owner = findReferencedColumnOwner ( targetEntity , column , context );
202
201
if ( owner == null ) {
203
202
throw new AnnotationException ( "A '@JoinColumn' for association "
204
203
+ associationMessage ( associatedEntity , joinColumns )
@@ -261,33 +260,29 @@ private static void registerSyntheticProperty(
261
260
String propertyName ,
262
261
String syntheticPropertyName ,
263
262
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 );
267
266
context .getMetadataCollector ().addUniquePropertyReference (
268
267
ownerEntity .getEntityName (),
269
268
syntheticPropertyName
270
269
);
271
270
}
272
- else if ( value instanceof Collection ) {
273
- ( ( Collection ) value ) .setReferencedPropertyName ( syntheticPropertyName );
271
+ else if ( value instanceof Collection collection ) {
272
+ collection .setReferencedPropertyName ( syntheticPropertyName );
274
273
//not unique because we could create a mtm wo association table
275
274
context .getMetadataCollector ().addPropertyReference (
276
275
ownerEntity .getEntityName (),
277
276
syntheticPropertyName
278
277
);
279
278
}
280
279
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 () );
285
281
}
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 );
291
286
}
292
287
293
288
private static String syntheticPropertyName (
@@ -306,11 +301,14 @@ private static String associationMessage(PersistentClass associatedEntity, Annot
306
301
if ( associatedEntity != null ) {
307
302
return "'" + associatedEntity .getEntityName () + "." + joinColumns .getPropertyName () + "'" ;
308
303
}
309
- else if ( joinColumns .getPropertyHolder () != null ) {
310
- return "'" + joinColumns .getPropertyHolder ().getEntityName () + "." + joinColumns .getPropertyName () + "'" ;
311
- }
312
304
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
+ }
314
312
}
315
313
}
316
314
@@ -392,7 +390,7 @@ private static Property cloneProperty(PersistentClass ownerEntity, MetadataBuild
392
390
* and other attributes.
393
391
*/
394
392
public static Property shallowCopy (Property property ) {
395
- Property clone = new SyntheticProperty ();
393
+ final Property clone = new SyntheticProperty ();
396
394
clone .setCascade ( property .getCascade () );
397
395
clone .setInsertable ( property .isInsertable () );
398
396
clone .setLazy ( property .isLazy () );
@@ -409,25 +407,12 @@ public static Property shallowCopy(Property property) {
409
407
}
410
408
411
409
private static List <Property > findPropertiesByColumns (
412
- Object columnOwner ,
410
+ AttributeContainer columnOwner ,
413
411
AnnotatedJoinColumns columns ,
414
412
PersistentClass associatedEntity ,
415
413
MetadataBuildingContext context ) {
416
414
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 ();
431
416
432
417
// Build the list of column names in the exact order they were
433
418
// specified by the @JoinColumn annotations.
@@ -923,16 +908,18 @@ public static String getCascadeStrategy(
923
908
boolean orphanRemoval ,
924
909
MetadataBuildingContext context ) {
925
910
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 ();
929
913
if ( !isEmpty ( hibernateCascades ) ) {
930
- Collections . addAll ( cascadeTypes , hibernateCascades );
914
+ addAll ( cascadeTypes , hibernateCascades );
931
915
}
932
916
if ( orphanRemoval ) {
933
917
cascadeTypes .add ( CascadeType .DELETE_ORPHAN );
934
918
cascadeTypes .add ( CascadeType .REMOVE );
935
919
}
920
+ if ( cascadeTypes .contains ( CascadeType .REPLICATE ) ) {
921
+ warnAboutDeprecatedCascadeType ( CascadeType .REPLICATE );
922
+ }
936
923
cascadeTypes .addAll ( context .getEffectiveDefaults ().getDefaultCascadeTypes () );
937
924
return renderCascadeTypeList ( cascadeTypes );
938
925
}
@@ -960,68 +947,31 @@ private static CascadeType convertCascadeType(jakarta.persistence.CascadeType ca
960
947
961
948
private static String renderCascadeTypeList (EnumSet <CascadeType > cascadeTypes ) {
962
949
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
+ } );
994
963
}
995
964
return cascade .isEmpty () ? "none" : cascade .substring (1 );
996
965
}
997
966
998
967
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 () );
1014
969
}
1015
970
1016
971
static boolean isGlobalGeneratorNameGlobal (MetadataBuildingContext context ) {
1017
972
return context .getBootstrapContext ().getJpaCompliance ().isGlobalGeneratorScopeEnabled ();
1018
973
}
1019
974
1020
- static boolean isCompositeId (ClassDetails idClass , MemberDetails idProperty ) {
1021
- return idClass .hasDirectAnnotationUsage ( Embeddable .class )
1022
- || idProperty .hasDirectAnnotationUsage ( EmbeddedId .class );
1023
- }
1024
-
1025
975
public static boolean isDefault (ClassDetails clazz ) {
1026
976
return clazz == ClassDetails .VOID_CLASS_DETAILS ;
1027
977
}
@@ -1036,33 +986,38 @@ public static void checkMappedByType(
1036
986
String propertyName ,
1037
987
PropertyHolder propertyHolder ,
1038
988
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 );
1042
992
}
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 );
1049
995
}
996
+ }
997
+
998
+ private static void checkMappedByType (
999
+ String mappedBy ,
1000
+ String propertyName ,
1001
+ PropertyHolder propertyHolder ,
1002
+ Map <String , PersistentClass > persistentClasses ,
1003
+ ToOne toOne ) {
1050
1004
final String referencedEntityName = toOne .getReferencedEntityName ();
1051
1005
final PersistentClass referencedClass = persistentClasses .get ( referencedEntityName );
1052
1006
PersistentClass ownerClass = propertyHolder .getPersistentClass ();
1053
1007
while ( ownerClass != null ) {
1054
1008
if ( checkReferencedClass ( ownerClass , referencedClass ) ) {
1009
+ // the two entities map to the same table
1010
+ // so we are good
1055
1011
return ;
1056
1012
}
1057
- else {
1058
- ownerClass = ownerClass .getSuperPersistentClass ();
1059
- }
1013
+ ownerClass = ownerClass .getSuperPersistentClass ();
1060
1014
}
1015
+ // we could not find any entity mapping to the same table
1061
1016
throw new AnnotationException (
1062
1017
"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 () + "'"
1066
1021
);
1067
1022
}
1068
1023
@@ -1111,21 +1066,20 @@ public static <A extends Annotation> A extractFromPackage(
1111
1066
1112
1067
final String declaringClassName = classDetails .getName ();
1113
1068
final String packageName = qualifier ( declaringClassName );
1114
-
1115
1069
if ( isEmpty ( packageName ) ) {
1116
1070
return null ;
1117
1071
}
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
+ }
1127
1083
}
1128
-
1129
- return null ;
1130
1084
}
1131
1085
}
0 commit comments