Skip to content

Commit f67a0d2

Browse files
committed
invert the default for hibernate.query.immutable_entity_update_query_handling_mode
The "default to warn but error when explicitly disabled" semantics for this were entirely backwards and hostile to the user. "Safety" features should always be on by default. Also, you all know what I think about WARNings, and here we had the most annoying kind of WARN, the one that couldn't be suppressed, except in log settings, even though it's probably intentional that the user is updating an immutable entity. Ugh.
1 parent 89dab7d commit f67a0d2

File tree

13 files changed

+96
-48
lines changed

13 files changed

+96
-48
lines changed

hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,8 +1139,8 @@ public ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandl
11391139
}
11401140

11411141
@Override
1142-
public boolean disallowImmutableEntityUpdate() {
1143-
return immutableEntityUpdateQueryHandlingMode == ImmutableEntityUpdateQueryHandlingMode.EXCEPTION;
1142+
public boolean allowImmutableEntityUpdate() {
1143+
return immutableEntityUpdateQueryHandlingMode != ImmutableEntityUpdateQueryHandlingMode.EXCEPTION;
11441144
}
11451145

11461146
@Override

hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,8 @@ public ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandl
414414
}
415415

416416
@Override
417-
public boolean disallowImmutableEntityUpdate() {
418-
return delegate.disallowImmutableEntityUpdate();
417+
public boolean allowImmutableEntityUpdate() {
418+
return delegate.allowImmutableEntityUpdate();
419419
}
420420

421421
@Override

hibernate-core/src/main/java/org/hibernate/cfg/QuerySettings.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -216,19 +216,19 @@ public interface QuerySettings {
216216
String FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH = "hibernate.query.fail_on_pagination_over_collection_fetch";
217217

218218
/**
219-
* This setting defines how {@link org.hibernate.annotations.Immutable} entities
220-
* are handled when executing a bulk update query. Valid options are enumerated
221-
* by {@link ImmutableEntityUpdateQueryHandlingMode}:
219+
* Controls how {@linkplain org.hibernate.annotations.Immutable immutable}
220+
* entities are handled when executing a bulk update or delete query. Valid
221+
* options are enumerated by {@link ImmutableEntityUpdateQueryHandlingMode}:
222222
* <ul>
223-
* <li>{@link ImmutableEntityUpdateQueryHandlingMode#WARNING "warning"}
224-
* specifies that a warning log message is issued when an
225-
* {@linkplain org.hibernate.annotations.Immutable immutable} entity is to be
226-
* updated via a bulk update statement, and
223+
* <li>{@link ImmutableEntityUpdateQueryHandlingMode#ALLOW "allow"} specifies
224+
* that bulk updates and deletes of immutable entities are allowed, and
227225
* <li>{@link ImmutableEntityUpdateQueryHandlingMode#EXCEPTION "exception"}
228-
* specifies that a {@link org.hibernate.HibernateException} should be thrown.
226+
* specifies that a {@link org.hibernate.HibernateException} is thrown.
229227
* </ul>
230228
*
231-
* @settingDefault {@link ImmutableEntityUpdateQueryHandlingMode#WARNING "warning"}
229+
* @settingDefault {@link ImmutableEntityUpdateQueryHandlingMode#EXCEPTION "exception"}
230+
*
231+
* @apiNote The default for this setting was inverted in Hibernate 7.
232232
*
233233
* @since 5.2
234234
*

hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,10 +636,15 @@ void cannotResolveNonNullableTransientDependencies(
636636
void attemptToAssociateProxyWithTwoOpenSessions(String entityName, Object id);
637637

638638
@LogMessage(level = WARN)
639-
@Message(value = "The query: [%s] attempts to update an immutable entity: %s",
639+
@Message(value = "The query [%s] updates an immutable entity: %s",
640640
id = 487)
641641
void immutableEntityUpdateQuery(String sourceQuery, String querySpaces);
642642

643+
@LogMessage(level = DEBUG)
644+
@Message(value = "The query [%s] updates an immutable entity: %s",
645+
id = 488)
646+
void immutableEntityUpdateQueryAllowed(String sourceQuery, String querySpaces);
647+
643648
@LogMessage(level = INFO)
644649
@Message(value = "No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)", id = 489)
645650
void noJtaPlatform();

hibernate-core/src/main/java/org/hibernate/query/spi/ImmutableEntityUpdateQueryHandlingMode.java

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,14 @@
88
import org.hibernate.cfg.AvailableSettings;
99

1010
/**
11-
* Controls for how {@linkplain org.hibernate.annotations.Immutable immutable} entities
12-
* are handled when executing a bulk update statement.
13-
* <ul>
14-
* <li>By default, the {@link #WARNING} mode is used, and a warning log message is issued
15-
* when an immutable entity is updated via a bulk update statement.
16-
* <li>If the {@link #EXCEPTION} mode is configured, then a {@link HibernateException} is
17-
* thrown instead.
18-
* </ul>
11+
* Controls how {@linkplain org.hibernate.annotations.Immutable immutable}
12+
* entities are handled when executing a bulk update or delete statement.
13+
* <p>
14+
* By default, the {@link #EXCEPTION} mode is used, and so bulk update or
15+
* delete queries affecting immutable entities are disallowed.
1916
*
20-
* @deprecated This enumeration is isomorphic to {@code boolean}. It will be removed.
17+
* @deprecated This enumeration will be removed, and replaced with a simpler
18+
* boolean-valued switch.
2119
*
2220
* @see org.hibernate.cfg.AvailableSettings#IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE
2321
*
@@ -26,7 +24,19 @@
2624
@Deprecated(since = "7.0", forRemoval = true)
2725
public enum ImmutableEntityUpdateQueryHandlingMode {
2826

27+
/**
28+
* Allow update or delete queries for immutable entities.
29+
*/
30+
ALLOW,
31+
/**
32+
* Log a warning when an immutable entity is affected by a bulk update or
33+
* delete statement.
34+
*/
2935
WARNING,
36+
/**
37+
* Throw a {@link HibernateException} when an immutable entity is affected
38+
* by a bulk update or delete statement.
39+
*/
3040
EXCEPTION;
3141

3242
/**
@@ -35,27 +45,27 @@ public enum ImmutableEntityUpdateQueryHandlingMode {
3545
* <p>
3646
* Valid values are an instance of {@link ImmutableEntityUpdateQueryHandlingMode}
3747
* or its string representation. For string values, the matching is case-insensitive,
38-
* so {@code warning} or {@code exception} are legal values.
48+
* so {@code allow}, {@code warning}, or {@code exception} are legal values.
3949
*
4050
* @param setting the configuration setting.
4151
* @return the associated {@link ImmutableEntityUpdateQueryHandlingMode} object
4252
*/
4353
public static ImmutableEntityUpdateQueryHandlingMode interpret(Object setting) {
4454
if ( setting == null ) {
45-
return WARNING;
55+
return EXCEPTION;
4656
}
4757
else if ( setting instanceof ImmutableEntityUpdateQueryHandlingMode mode ) {
4858
return mode;
4959
}
5060
else if ( setting instanceof String string ) {
51-
for ( ImmutableEntityUpdateQueryHandlingMode value : values() ) {
61+
for ( var value : values() ) {
5262
if ( value.name().equalsIgnoreCase( string ) ) {
5363
return value;
5464
}
5565
}
5666
}
5767
throw new HibernateException( "Unrecognized value '" + setting
5868
+ "' specified via '" + AvailableSettings.IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE
59-
+ "' (should be 'warning' or 'exception')" );
69+
+ "' (should be 'allow', 'warning', or 'exception')" );
6070
}
6171
}

hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngineOptions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,15 @@ public interface QueryEngineOptions {
8989
* @see org.hibernate.cfg.QuerySettings#IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE
9090
*
9191
* @deprecated Since {@link ImmutableEntityUpdateQueryHandlingMode} is deprecated.
92-
* Use {@link #disallowImmutableEntityUpdate} instead.
92+
* Use {@link #allowImmutableEntityUpdate} instead.
9393
*/
9494
@Deprecated(since = "7.0", forRemoval = true)
9595
ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode();
9696

9797
/**
9898
* @see org.hibernate.cfg.QuerySettings#IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE
9999
*/
100-
boolean disallowImmutableEntityUpdate();
100+
boolean allowImmutableEntityUpdate();
101101

102102
/**
103103
* @see org.hibernate.cfg.AvailableSettings#JSON_FUNCTIONS_ENABLED

hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1502,5 +1502,5 @@ default SqmSortSpecification sort(
15021502
@Deprecated(since = "7.0", forRemoval = true)
15031503
ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode();
15041504

1505-
boolean disallowImmutableEntityUpdate();
1505+
boolean allowImmutableEntityUpdate();
15061506
}

hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, Serializable {
190190
private final transient JpaCompliance jpaCompliance;
191191
private final transient QueryEngine queryEngine;
192192
private final transient ValueHandlingMode criteriaValueHandlingMode;
193-
private final transient boolean disallowImmutableEntityUpdate;
193+
private final transient ImmutableEntityUpdateQueryHandlingMode immutableEntityUpdateQueryHandlingMode;
194194
private final transient BindingContext bindingContext;
195195
private transient BasicType<Boolean> booleanType;
196196
private transient BasicType<Integer> integerType;
@@ -211,7 +211,7 @@ public SqmCriteriaNodeBuilder(
211211
this.name = name;
212212
this.jpaCompliance = options.getJpaCompliance();
213213
this.criteriaValueHandlingMode = options.getCriteriaValueHandlingMode();
214-
this.disallowImmutableEntityUpdate = options.disallowImmutableEntityUpdate();
214+
this.immutableEntityUpdateQueryHandlingMode = options.getImmutableEntityUpdateQueryHandlingMode();
215215
this.bindingContext = bindingContext;
216216
this.extensions = loadExtensions();
217217
}
@@ -245,16 +245,14 @@ public JpaCompliance getJpaCompliance() {
245245
return jpaCompliance;
246246
}
247247

248-
@Override
248+
@Override @Deprecated
249249
public ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode() {
250-
return disallowImmutableEntityUpdate
251-
? ImmutableEntityUpdateQueryHandlingMode.EXCEPTION
252-
: ImmutableEntityUpdateQueryHandlingMode.WARNING;
250+
return immutableEntityUpdateQueryHandlingMode;
253251
}
254252

255253
@Override
256-
public boolean disallowImmutableEntityUpdate() {
257-
return disallowImmutableEntityUpdate;
254+
public boolean allowImmutableEntityUpdate() {
255+
return immutableEntityUpdateQueryHandlingMode != ImmutableEntityUpdateQueryHandlingMode.EXCEPTION;
258256
}
259257

260258
@Override

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/update/SqmUpdateStatement.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.Set;
1111

1212
import org.hibernate.HibernateException;
13+
import org.hibernate.cfg.AvailableSettings;
1314
import org.hibernate.internal.CoreLogging;
1415
import org.hibernate.internal.CoreMessageLogger;
1516
import org.hibernate.persister.entity.EntityPersister;
@@ -133,11 +134,19 @@ private void verifyImmutableEntityUpdate(String hql) {
133134
nodeBuilder().getMappingMetamodel().getEntityDescriptor( getTarget().getEntityName() );
134135
if ( !persister.isMutable() ) {
135136
final String querySpaces = Arrays.toString( persister.getQuerySpaces() );
136-
if ( nodeBuilder().disallowImmutableEntityUpdate() ) {
137-
throw new HibernateException( "The query attempts to update an immutable entity: " + querySpaces );
138-
}
139-
else {
140-
LOG.immutableEntityUpdateQuery( hql, querySpaces );
137+
switch ( nodeBuilder().getImmutableEntityUpdateQueryHandlingMode() ) {
138+
case ALLOW :
139+
LOG.immutableEntityUpdateQueryAllowed( hql, querySpaces );
140+
break;
141+
case WARNING:
142+
LOG.immutableEntityUpdateQuery( hql, querySpaces );
143+
break;
144+
case EXCEPTION:
145+
throw new HibernateException( "The query attempts to update an immutable entity: "
146+
+ querySpaces
147+
+ " (set '"
148+
+ AvailableSettings.IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE
149+
+ "' to suppress)");
141150
}
142151
}
143152
}

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/immutable/ImmutableEntityUpdateQueryHandlingModeExceptionTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
import org.hibernate.HibernateException;
1616
import org.hibernate.annotations.Immutable;
17-
import org.hibernate.cfg.AvailableSettings;
1817

1918
import org.hibernate.query.Query;
2019
import org.hibernate.testing.orm.junit.JiraKey;
@@ -40,7 +39,7 @@ protected Class[] getAnnotatedClasses() {
4039

4140
@Override
4241
protected void addSettings(Map<String,Object> settings) {
43-
settings.put( AvailableSettings.IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE, "exception" );
42+
// settings.put( AvailableSettings.IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE, "exception" );
4443
}
4544

4645
@Test
@@ -62,7 +61,7 @@ public void testBulkUpdate(){
6261
catch (PersistenceException e) {
6362
assertTrue( e instanceof HibernateException );
6463
assertEquals(
65-
"Error interpreting query [The query attempts to update an immutable entity: [Country]] [update Country set name = :name]",
64+
"Error interpreting query [The query attempts to update an immutable entity: [Country] (set 'hibernate.query.immutable_entity_update_query_handling_mode' to suppress)] [update Country set name = :name]",
6665
e.getMessage()
6766
);
6867
}

0 commit comments

Comments
 (0)