From 461acf3bd1068c50df03dfe2524a5545a7aba4a0 Mon Sep 17 00:00:00 2001 From: Martin Panzer Date: Fri, 25 Feb 2022 22:39:05 +0100 Subject: [PATCH 1/5] prevent duplicate getParameterTypes call --- .../bytecode/internal/bytebuddy/BytecodeProviderImpl.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BytecodeProviderImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BytecodeProviderImpl.java index 814d8c293b64..bfcbccd77879 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BytecodeProviderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BytecodeProviderImpl.java @@ -197,17 +197,18 @@ public Size apply( methodVisitor.visitVarInsn( Opcodes.ALOAD, 2 ); methodVisitor.visitLdcInsn( index++ ); methodVisitor.visitInsn( Opcodes.AALOAD ); - if ( setter.getParameterTypes()[0].isPrimitive() ) { + Class firstParameterType = setter.getParameterTypes()[0]; + if ( firstParameterType.isPrimitive() ) { PrimitiveUnboxingDelegate.forReferenceType( TypeDescription.Generic.OBJECT ) .assignUnboxedTo( - new TypeDescription.Generic.OfNonGenericType.ForLoadedType( setter.getParameterTypes()[0] ), + new TypeDescription.Generic.OfNonGenericType.ForLoadedType( firstParameterType ), ReferenceTypeAwareAssigner.INSTANCE, Assigner.Typing.DYNAMIC ) .apply( methodVisitor, implementationContext ); } else { - methodVisitor.visitTypeInsn( Opcodes.CHECKCAST, Type.getInternalName( setter.getParameterTypes()[0] ) ); + methodVisitor.visitTypeInsn( Opcodes.CHECKCAST, Type.getInternalName( firstParameterType ) ); } methodVisitor.visitMethodInsn( Opcodes.INVOKEVIRTUAL, From 3661932f315df727b1d2d627659cbdde91b66dc0 Mon Sep 17 00:00:00 2001 From: Martin Panzer Date: Fri, 25 Feb 2022 20:58:47 +0100 Subject: [PATCH 2/5] search in already retrieved array of declared method for getter / is methods --- .../internal/util/ReflectHelper.java | 54 +++++++++++-------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java index 66e82fd20800..6fcd51c556f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java @@ -490,7 +490,8 @@ private static Method getGetterOrNull(Class[] interfaces, String propertyName) { } private static Method getGetterOrNull(Class containerClass, String propertyName) { - for ( Method method : containerClass.getDeclaredMethods() ) { + Method[] declaredMethods = containerClass.getDeclaredMethods(); + for ( Method method : declaredMethods) { // if the method has parameters, skip it if ( method.getParameterCount() != 0 ) { continue; @@ -516,7 +517,7 @@ private static Method getGetterOrNull(Class containerClass, String propertyName) final String stemName = methodName.substring( 3 ); final String decapitalizedStemName = Introspector.decapitalize( stemName ); if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) { - verifyNoIsVariantExists( containerClass, propertyName, method, stemName ); + verifyNoIsVariantExists( containerClass, propertyName, method, stemName, declaredMethods); return method; } @@ -527,7 +528,7 @@ private static Method getGetterOrNull(Class containerClass, String propertyName) final String stemName = methodName.substring( 2 ); String decapitalizedStemName = Introspector.decapitalize( stemName ); if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) { - verifyNoGetVariantExists( containerClass, propertyName, method, stemName ); + verifyNoGetVariantExists( containerClass, propertyName, method, stemName, declaredMethods); return method; } } @@ -536,21 +537,30 @@ private static Method getGetterOrNull(Class containerClass, String propertyName) return null; } + private static Method findAnyMatch(String name, Method[] methods) { + for (Method method : methods) { + if (method.getName().equals(name)) { + return method; + } + } + return null; + } + private static void verifyNoIsVariantExists( Class containerClass, String propertyName, Method getMethod, - String stemName) { - // verify that the Class does not also define a method with the same stem name with 'is' - try { - final Method isMethod = containerClass.getDeclaredMethod( "is" + stemName ); - if ( !Modifier.isStatic( isMethod.getModifiers() ) && isMethod.getAnnotation( Transient.class ) == null ) { - // No such method should throw the caught exception. So if we get here, there was - // such a method. - checkGetAndIsVariants( containerClass, propertyName, getMethod, isMethod ); - } + String stemName, + Method[] declaredMethods) { + + Method isMethod = findAnyMatch( "is" + stemName, declaredMethods); + if (isMethod == null) { + return; } - catch (NoSuchMethodException ignore) { + + // verify that the Class does not also define a method with the same stem name with 'is' + if ( !Modifier.isStatic( isMethod.getModifiers() ) && isMethod.getAnnotation( Transient.class ) == null ) { + checkGetAndIsVariants( containerClass, propertyName, getMethod, isMethod ); } } @@ -580,17 +590,15 @@ private static void verifyNoGetVariantExists( Class containerClass, String propertyName, Method isMethod, - String stemName) { - // verify that the Class does not also define a method with the same stem name with 'is' - try { - final Method getMethod = containerClass.getDeclaredMethod( "get" + stemName ); - // No such method should throw the caught exception. So if we get here, there was - // such a method. - if ( !Modifier.isStatic( getMethod.getModifiers() ) && getMethod.getAnnotation( Transient.class ) == null ) { - checkGetAndIsVariants( containerClass, propertyName, getMethod, isMethod ); - } + String stemName, + Method[] declaredMethods) { + Method getMethod = findAnyMatch( "get" + stemName, declaredMethods); + if (getMethod == null) { + return; } - catch (NoSuchMethodException ignore) { + // verify that the Class does not also define a method with the same stem name with 'get' + if ( !Modifier.isStatic( getMethod.getModifiers() ) && getMethod.getAnnotation( Transient.class ) == null ) { + checkGetAndIsVariants( containerClass, propertyName, getMethod, isMethod ); } } From 92c6077317cb67909e88abb6651ecd402da13e44 Mon Sep 17 00:00:00 2001 From: Martin Panzer Date: Sat, 26 Feb 2022 07:43:56 +0100 Subject: [PATCH 3/5] Prevent getDeclaredField calls by iterating over all fields This saves on throwing exceptions everytime a field was not found, for the cost of copying the fields arrays on each invocation. This is still magnitudes faster though. --- .../internal/util/ReflectHelper.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java index 6fcd51c556f4..8130611d4b1d 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java @@ -423,16 +423,14 @@ private static Field locateField(Class clazz, String propertyName) { return null; } - try { - Field field = clazz.getDeclaredField( propertyName ); - if ( !isStaticField( field ) ) { - return field; - } + Field field = findField(propertyName, clazz.getDeclaredFields()); + if (field == null) { return locateField( clazz.getSuperclass(), propertyName ); } - catch ( NoSuchFieldException nsfe ) { - return locateField( clazz.getSuperclass(), propertyName ); + if ( !isStaticField( field ) ) { + return field; } + return locateField( clazz.getSuperclass(), propertyName ); } public static boolean isStaticField(Field field) { @@ -546,6 +544,15 @@ private static Method findAnyMatch(String name, Method[] methods) { return null; } + private static Field findField(String name, Field[] methods) { + for (Field field : methods) { + if (field.getName().equals(name)) { + return field; + } + } + return null; + } + private static void verifyNoIsVariantExists( Class containerClass, String propertyName, From ed8519effb84d80e00661946f3fd96f97ea6db9d Mon Sep 17 00:00:00 2001 From: Martin Panzer Date: Sat, 26 Feb 2022 16:41:59 +0100 Subject: [PATCH 4/5] Only decapitalize if needed --- .../hibernate/internal/util/ReflectHelper.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java index 8130611d4b1d..edac0df2dd38 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java @@ -513,8 +513,7 @@ private static Method getGetterOrNull(Class containerClass, String propertyName) // try "get" if ( methodName.startsWith( "get" ) ) { final String stemName = methodName.substring( 3 ); - final String decapitalizedStemName = Introspector.decapitalize( stemName ); - if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) { + if ( stemName.equals( propertyName ) || Introspector.decapitalize( stemName ).equals( propertyName ) ) { verifyNoIsVariantExists( containerClass, propertyName, method, stemName, declaredMethods); return method; } @@ -524,8 +523,7 @@ private static Method getGetterOrNull(Class containerClass, String propertyName) // if not "get", then try "is" if ( methodName.startsWith( "is" ) ) { final String stemName = methodName.substring( 2 ); - String decapitalizedStemName = Introspector.decapitalize( stemName ); - if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) { + if ( stemName.equals( propertyName ) || Introspector.decapitalize( stemName ).equals( propertyName ) ) { verifyNoGetVariantExists( containerClass, propertyName, method, stemName, declaredMethods); return method; } @@ -678,8 +676,7 @@ private static Method setterOrNull(Class theClass, String propertyName, Class pr final String methodName = method.getName(); if ( method.getParameterCount() == 1 && methodName.startsWith( "set" ) ) { final String testOldMethod = methodName.substring( 3 ); - final String testStdMethod = Introspector.decapitalize( testOldMethod ); - if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) { + if (testOldMethod.equals( propertyName ) || Introspector.decapitalize( testOldMethod ).equals( propertyName )) { potentialSetter = method; if ( propertyType == null || method.getParameterTypes()[0].equals( propertyType ) ) { break; @@ -718,8 +715,7 @@ public static Method findGetterMethodForFieldAccess(Field field, String property // try "get" if ( methodName.startsWith( "get" ) ) { final String stemName = methodName.substring( 3 ); - final String decapitalizedStemName = Introspector.decapitalize( stemName ); - if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) { + if ( stemName.equals( propertyName ) || Introspector.decapitalize( stemName ).equals( propertyName ) ) { return method; } @@ -728,8 +724,7 @@ public static Method findGetterMethodForFieldAccess(Field field, String property // if not "get", then try "is" if ( methodName.startsWith( "is" ) ) { final String stemName = methodName.substring( 2 ); - String decapitalizedStemName = Introspector.decapitalize( stemName ); - if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) { + if ( stemName.equals( propertyName ) || Introspector.decapitalize( stemName ).equals( propertyName ) ) { return method; } } From e7f01fff3c0f4ae971c0baaf69cbdb7139c12b75 Mon Sep 17 00:00:00 2001 From: Martin Panzer Date: Sun, 27 Feb 2022 07:54:56 +0100 Subject: [PATCH 5/5] Prevent substring call if the result would be an empty string --- .../main/java/org/hibernate/internal/util/StringHelper.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java index 1299b5648b90..3a086b6cb627 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java @@ -128,7 +128,10 @@ public static String replace( return template; } else { - String beforePlaceholder = template.substring( 0, loc ); + String beforePlaceholder = ""; + if (loc > 0) { + beforePlaceholder = template.substring(0, loc); + } String afterPlaceholder = template.substring( loc + placeholder.length() ); return replace( beforePlaceholder,