remove hibernate.query.conventional_java_constants

this was apparently a sorta nasty bandaid to a performance problem in query compilation
and it caused problems for some users, breaking interpretation of enum values
This commit is contained in:
Gavin King 2022-01-20 21:22:40 +01:00
parent a84793bd6d
commit a59bf70ccf
7 changed files with 1 additions and 148 deletions

View File

@ -564,16 +564,6 @@ It follows a pattern similar to the ANSI SQL definition of the global temporary
+ +
This configuration property defines the database catalog used for storing the temporary tables used for bulk HQL operations. This configuration property defines the database catalog used for storing the temporary tables used for bulk HQL operations.
`*hibernate.query.conventional_java_constants*` (e.g. `true` (default value) or `false`)::
Setting which indicates whether or not Java constants follow the https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html[Java Naming conventions].
+
The default is `true`.
Existing applications may want to disable this (set it `false`) if non-conventional Java constants are used.
However, there is a significant performance overhead for using non-conventional Java constants
since Hibernate cannot determine if aliases should be treated as Java constants or not.
+
Check out https://hibernate.atlassian.net/browse/HHH-4959[HHH-4959] for more details.
[[configurations-batch]] [[configurations-batch]]
=== Batching properties === Batching properties

View File

@ -90,7 +90,6 @@ import static org.hibernate.cfg.AvailableSettings.CACHE_REGION_PREFIX;
import static org.hibernate.cfg.AvailableSettings.CALLABLE_NAMED_PARAMS_ENABLED; import static org.hibernate.cfg.AvailableSettings.CALLABLE_NAMED_PARAMS_ENABLED;
import static org.hibernate.cfg.AvailableSettings.CHECK_NULLABILITY; import static org.hibernate.cfg.AvailableSettings.CHECK_NULLABILITY;
import static org.hibernate.cfg.AvailableSettings.CONNECTION_HANDLING; import static org.hibernate.cfg.AvailableSettings.CONNECTION_HANDLING;
import static org.hibernate.cfg.AvailableSettings.CONVENTIONAL_JAVA_CONSTANTS;
import static org.hibernate.cfg.AvailableSettings.CRITERIA_VALUE_HANDLING_MODE; import static org.hibernate.cfg.AvailableSettings.CRITERIA_VALUE_HANDLING_MODE;
import static org.hibernate.cfg.AvailableSettings.CUSTOM_ENTITY_DIRTINESS_STRATEGY; import static org.hibernate.cfg.AvailableSettings.CUSTOM_ENTITY_DIRTINESS_STRATEGY;
import static org.hibernate.cfg.AvailableSettings.DEFAULT_BATCH_FETCH_SIZE; import static org.hibernate.cfg.AvailableSettings.DEFAULT_BATCH_FETCH_SIZE;
@ -220,7 +219,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
private SqmTranslatorFactory sqmTranslatorFactory; private SqmTranslatorFactory sqmTranslatorFactory;
private Boolean useOfJdbcNamedParametersEnabled; private Boolean useOfJdbcNamedParametersEnabled;
private boolean namedQueryStartupCheckingEnabled; private boolean namedQueryStartupCheckingEnabled;
private boolean conventionalJavaConstants;
private final boolean omitJoinOfSuperclassTablesEnabled; private final boolean omitJoinOfSuperclassTablesEnabled;
private final int preferredSqlTypeCodeForBoolean; private final int preferredSqlTypeCodeForBoolean;
private final TimeZoneStorageStrategy defaultTimeZoneStorageStrategy; private final TimeZoneStorageStrategy defaultTimeZoneStorageStrategy;
@ -441,14 +439,12 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
this.useOfJdbcNamedParametersEnabled = cfgService.getSetting( CALLABLE_NAMED_PARAMS_ENABLED, BOOLEAN, true ); this.useOfJdbcNamedParametersEnabled = cfgService.getSetting( CALLABLE_NAMED_PARAMS_ENABLED, BOOLEAN, true );
this.namedQueryStartupCheckingEnabled = cfgService.getSetting( QUERY_STARTUP_CHECKING, BOOLEAN, true ); this.namedQueryStartupCheckingEnabled = cfgService.getSetting( QUERY_STARTUP_CHECKING, BOOLEAN, true );
this.conventionalJavaConstants = cfgService.getSetting(
CONVENTIONAL_JAVA_CONSTANTS, BOOLEAN, true );
this.omitJoinOfSuperclassTablesEnabled = cfgService.getSetting( OMIT_JOIN_OF_SUPERCLASS_TABLES, BOOLEAN, true ); this.omitJoinOfSuperclassTablesEnabled = cfgService.getSetting( OMIT_JOIN_OF_SUPERCLASS_TABLES, BOOLEAN, true );
this.preferredSqlTypeCodeForBoolean = ConfigurationHelper.getPreferredSqlTypeCodeForBoolean( serviceRegistry ); this.preferredSqlTypeCodeForBoolean = ConfigurationHelper.getPreferredSqlTypeCodeForBoolean( serviceRegistry );
this.defaultTimeZoneStorageStrategy = context.getMetadataBuildingOptions().getDefaultTimeZoneStorage(); this.defaultTimeZoneStorageStrategy = context.getMetadataBuildingOptions().getDefaultTimeZoneStorage();
final RegionFactory regionFactory = serviceRegistry.getService( RegionFactory.class ); final RegionFactory regionFactory = serviceRegistry.getService( RegionFactory.class );
if ( !NoCachingRegionFactory.class.isInstance( regionFactory ) ) { if ( !(regionFactory instanceof NoCachingRegionFactory) ) {
this.secondLevelCacheEnabled = cfgService.getSetting( USE_SECOND_LEVEL_CACHE, BOOLEAN, true ); this.secondLevelCacheEnabled = cfgService.getSetting( USE_SECOND_LEVEL_CACHE, BOOLEAN, true );
this.queryCacheEnabled = cfgService.getSetting( USE_QUERY_CACHE, BOOLEAN, false ); this.queryCacheEnabled = cfgService.getSetting( USE_QUERY_CACHE, BOOLEAN, false );
this.timestampsCacheFactory = strategySelector.resolveDefaultableStrategy( this.timestampsCacheFactory = strategySelector.resolveDefaultableStrategy(
@ -1047,11 +1043,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
return namedQueryStartupCheckingEnabled; return namedQueryStartupCheckingEnabled;
} }
@Override
public boolean isConventionalJavaConstants() {
return conventionalJavaConstants;
}
@Override @Override
public boolean isSecondLevelCacheEnabled() { public boolean isSecondLevelCacheEnabled() {
return secondLevelCacheEnabled; return secondLevelCacheEnabled;

View File

@ -229,11 +229,6 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
return delegate.isNamedQueryStartupCheckingEnabled(); return delegate.isNamedQueryStartupCheckingEnabled();
} }
@Override
public boolean isConventionalJavaConstants() {
return delegate.isConventionalJavaConstants();
}
@Override @Override
public boolean isAllowOutOfTransactionUpdateOperations() { public boolean isAllowOutOfTransactionUpdateOperations() {
return delegate.isAllowOutOfTransactionUpdateOperations(); return delegate.isAllowOutOfTransactionUpdateOperations();

View File

@ -189,8 +189,6 @@ public interface SessionFactoryOptions extends QueryEngineOptions {
boolean isNamedQueryStartupCheckingEnabled(); boolean isNamedQueryStartupCheckingEnabled();
boolean isConventionalJavaConstants();
boolean isSecondLevelCacheEnabled(); boolean isSecondLevelCacheEnabled();
boolean isQueryCacheEnabled(); boolean isQueryCacheEnabled();

View File

@ -985,18 +985,6 @@ public interface AvailableSettings {
*/ */
String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check"; String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check";
/**
* Setting which indicates whether or not Java constant follow the Java Naming conventions.
* <p/>
* Default is {@code true}. Existing applications may want to disable this (set it {@code false})
* if unconventional Java constants are used. However, there is a significant performance overhead
* for using unconventional Java constants since Hibernate cannot determine if aliases should be
* treated as Java constants or not.
*
* @since 5.2
*/
String CONVENTIONAL_JAVA_CONSTANTS = "hibernate.query.conventional_java_constants";
/** /**
* Enable ordering of update statements by primary key value * Enable ordering of update statements by primary key value
*/ */

View File

@ -254,28 +254,6 @@ public final class ReflectHelper {
return PropertyAccessStrategyMixedImpl.INSTANCE.buildPropertyAccess( clazz, name, true ).getGetter(); return PropertyAccessStrategyMixedImpl.INSTANCE.buildPropertyAccess( clazz, name, true ).getGetter();
} }
public static Object getConstantValue(String name, SessionFactoryImplementor factory) {
boolean conventionalJavaConstants = factory.getSessionFactoryOptions().isConventionalJavaConstants();
Class clazz;
try {
if ( conventionalJavaConstants &&
!JAVA_CONSTANT_PATTERN.matcher( name ).find() ) {
return null;
}
ClassLoaderService classLoaderService = factory.getServiceRegistry().getService( ClassLoaderService.class );
clazz = classLoaderService.classForName( StringHelper.qualifier( name ) );
}
catch ( Throwable t ) {
return null;
}
try {
return clazz.getField( StringHelper.unqualify( name ) ).get( null );
}
catch ( Throwable t ) {
return null;
}
}
/** /**
* Retrieve the default (no arg) constructor from the given class. * Retrieve the default (no arg) constructor from the given class.
* *

View File

@ -122,82 +122,6 @@ public class ReflectHelperTest {
when( serviceRegistryMock.getService( eq( ClassLoaderService.class ) ) ).thenReturn( classLoaderServiceMock ); when( serviceRegistryMock.getService( eq( ClassLoaderService.class ) ) ).thenReturn( classLoaderServiceMock );
} }
@Test
public void test_getConstantValue_simpleAlias() {
when( sessionFactoryOptionsMock.isConventionalJavaConstants() ).thenReturn( true );
Object value = ReflectHelper.getConstantValue( "alias.b", sessionFactoryImplementorMock);
assertNull(value);
verify(classLoaderServiceMock, never()).classForName( anyString() );
}
@Test
public void test_getConstantValue_simpleAlias_non_conventional() {
when( sessionFactoryOptionsMock.isConventionalJavaConstants() ).thenReturn( false );
Object value = ReflectHelper.getConstantValue( "alias.b", sessionFactoryImplementorMock);
assertNull(value);
verify(classLoaderServiceMock, times(1)).classForName( eq( "alias" ) );
}
@Test
public void test_getConstantValue_nestedAlias() {
when( sessionFactoryOptionsMock.isConventionalJavaConstants() ).thenReturn( true );
Object value = ReflectHelper.getConstantValue( "alias.b.c", sessionFactoryImplementorMock);
assertNull(value);
verify(classLoaderServiceMock, never()).classForName( anyString() );
}
@Test
public void test_getConstantValue_nestedAlias_non_conventional() {
when( sessionFactoryOptionsMock.isConventionalJavaConstants() ).thenReturn( false );
Object value = ReflectHelper.getConstantValue( "alias.b.c", sessionFactoryImplementorMock);
assertNull(value);
verify(classLoaderServiceMock, times(1)).classForName( eq( "alias.b" ) );
}
@Test
public void test_getConstantValue_outerEnum() {
when( sessionFactoryOptionsMock.isConventionalJavaConstants() ).thenReturn( true );
when( classLoaderServiceMock.classForName( "jakarta.persistence.FetchType" ) ).thenReturn( (Class) FetchType.class );
Object value = ReflectHelper.getConstantValue( "jakarta.persistence.FetchType.LAZY", sessionFactoryImplementorMock);
assertEquals( FetchType.LAZY, value );
verify(classLoaderServiceMock, times(1)).classForName( eq("jakarta.persistence.FetchType") );
}
@Test
public void test_getConstantValue_enumClass() {
when( sessionFactoryOptionsMock.isConventionalJavaConstants() ).thenReturn( true );
when( classLoaderServiceMock.classForName( "org.hibernate.orm.test.internal.util.ReflectHelperTest$Status" ) ).thenReturn( (Class) Status.class );
Object value = ReflectHelper.getConstantValue( "org.hibernate.orm.test.internal.util.ReflectHelperTest$Status", sessionFactoryImplementorMock);
assertNull(value);
verify(classLoaderServiceMock, never()).classForName( eq("org.hibernate.internal.util") );
}
@Test
public void test_getConstantValue_nestedEnum() {
when( sessionFactoryOptionsMock.isConventionalJavaConstants() ).thenReturn( true );
when( classLoaderServiceMock.classForName( "org.hibernate.orm.test.internal.util.ReflectHelperTest$Status" ) ).thenReturn( (Class) Status.class );
Object value = ReflectHelper.getConstantValue( "org.hibernate.orm.test.internal.util.ReflectHelperTest$Status.ON", sessionFactoryImplementorMock);
assertEquals( ON, value );
verify(classLoaderServiceMock, times(1)).classForName( eq("org.hibernate.orm.test.internal.util.ReflectHelperTest$Status") );
}
@Test
public void test_getConstantValue_constant_digits() {
when( sessionFactoryOptionsMock.isConventionalJavaConstants() ).thenReturn( true );
when( classLoaderServiceMock.classForName( "org.hibernate.orm.test.internal.util.hib3rnat3.C0nst4nts३" ) ).thenReturn( (Class) C0nst4nts३.class );
Object value = ReflectHelper.getConstantValue( "org.hibernate.orm.test.internal.util.hib3rnat3.C0nst4nts३.ABC_DEF", sessionFactoryImplementorMock);
assertEquals( C0nst4nts३.ABC_DEF, value );
verify(classLoaderServiceMock, times(1)).classForName( eq("org.hibernate.orm.test.internal.util.hib3rnat3.C0nst4nts३") );
}
@Test @Test
public void test_getMethod_nestedInterfaces() { public void test_getMethod_nestedInterfaces() {
assertNotNull( ReflectHelper.findGetterMethod( C.class, "id" ) ); assertNotNull( ReflectHelper.findGetterMethod( C.class, "id" ) );
@ -231,15 +155,4 @@ public class ReflectHelperTest {
public void test_setMethod_nestedInterfaces_on_superclasses() { public void test_setMethod_nestedInterfaces_on_superclasses() {
assertNotNull( ReflectHelper.findSetterMethod( E.class, "id", String.class ) ); assertNotNull( ReflectHelper.findSetterMethod( E.class, "id", String.class ) );
} }
@TestForIssue(jiraKey = "HHH-14059")
@Test
public void test_getConstantValue_UpperCaseEnum() {
when( sessionFactoryOptionsMock.isConventionalJavaConstants() ).thenReturn( true );
when( classLoaderServiceMock.classForName( "com.example.UStatus" ) ).thenReturn( (Class) Status.class );
Object value = ReflectHelper.getConstantValue( "com.example.UStatus.OFF", sessionFactoryImplementorMock);
assertEquals( OFF, value );
verify(classLoaderServiceMock, times(1)).classForName( eq("com.example.UStatus") );
}
} }