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.
`*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]]
=== 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.CHECK_NULLABILITY;
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.CUSTOM_ENTITY_DIRTINESS_STRATEGY;
import static org.hibernate.cfg.AvailableSettings.DEFAULT_BATCH_FETCH_SIZE;
@ -220,7 +219,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
private SqmTranslatorFactory sqmTranslatorFactory;
private Boolean useOfJdbcNamedParametersEnabled;
private boolean namedQueryStartupCheckingEnabled;
private boolean conventionalJavaConstants;
private final boolean omitJoinOfSuperclassTablesEnabled;
private final int preferredSqlTypeCodeForBoolean;
private final TimeZoneStorageStrategy defaultTimeZoneStorageStrategy;
@ -441,14 +439,12 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
this.useOfJdbcNamedParametersEnabled = cfgService.getSetting( CALLABLE_NAMED_PARAMS_ENABLED, 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.preferredSqlTypeCodeForBoolean = ConfigurationHelper.getPreferredSqlTypeCodeForBoolean( serviceRegistry );
this.defaultTimeZoneStorageStrategy = context.getMetadataBuildingOptions().getDefaultTimeZoneStorage();
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.queryCacheEnabled = cfgService.getSetting( USE_QUERY_CACHE, BOOLEAN, false );
this.timestampsCacheFactory = strategySelector.resolveDefaultableStrategy(
@ -1047,11 +1043,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
return namedQueryStartupCheckingEnabled;
}
@Override
public boolean isConventionalJavaConstants() {
return conventionalJavaConstants;
}
@Override
public boolean isSecondLevelCacheEnabled() {
return secondLevelCacheEnabled;

View File

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

View File

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

View File

@ -985,18 +985,6 @@ public interface AvailableSettings {
*/
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
*/

View File

@ -254,28 +254,6 @@ public final class ReflectHelper {
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.
*

View File

@ -122,82 +122,6 @@ public class ReflectHelperTest {
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
public void test_getMethod_nestedInterfaces() {
assertNotNull( ReflectHelper.findGetterMethod( C.class, "id" ) );
@ -231,15 +155,4 @@ public class ReflectHelperTest {
public void test_setMethod_nestedInterfaces_on_superclasses() {
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") );
}
}