Browse Source

Polishing.

Add generic signature, skip static initializer if not required, access classes in static initializer through constants instead of using forName(…).

See #3365
pull/3363/head
Mark Paluch 3 months ago
parent
commit
1a454588ff
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 79
      src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java

79
src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java

@ -384,13 +384,22 @@ public class ClassGeneratingPropertyAccessorFactory @@ -384,13 +384,22 @@ public class ClassGeneratingPropertyAccessorFactory
static byte[] generateBytecode(String internalClassName, PersistentEntity<?, ?> entity) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cw.visit(Opcodes.V1_8, ACC_PUBLIC + ACC_SUPER, internalClassName, null, JAVA_LANG_OBJECT, IMPLEMENTED_INTERFACES);
String signature = referenceName(JAVA_LANG_OBJECT) + String.format("L%s<%s>;",
Type.getInternalName(PersistentPropertyAccessor.class), referenceName(entity.getType()));
cw.visit(Opcodes.V1_8, ACC_PUBLIC + ACC_SUPER, internalClassName, signature, JAVA_LANG_OBJECT,
IMPLEMENTED_INTERFACES);
List<PersistentProperty<?>> persistentProperties = getPersistentProperties(entity);
visitFields(entity, persistentProperties, cw);
visitDefaultConstructor(entity, internalClassName, cw);
visitStaticInitializer(entity, persistentProperties, internalClassName, cw);
if (requiresMethodHandleSetup(entity, persistentProperties)) {
visitStaticInitializer(entity, persistentProperties, internalClassName, cw);
}
visitBeanGetter(entity, internalClassName, cw);
visitSetProperty(entity, persistentProperties, internalClassName, cw);
visitGetProperty(entity, persistentProperties, internalClassName, cw);
@ -515,9 +524,7 @@ public class ClassGeneratingPropertyAccessorFactory @@ -515,9 +524,7 @@ public class ClassGeneratingPropertyAccessorFactory
* Method getter;
* Method setter;
* MethodHandles.Lookup lookup = MethodHandles.lookup();
* Class class_1 = Class.forName("org.springframework.data.mapping.Person");
* Class class_2 = Class.forName("org.springframework.data.mapping.PersonWithId");
* Field field = class_2.getDeclaredField("id");
* Field field = org.springframework.data.mapping.PersonWithId.class.getDeclaredField("id");
* field.setAccessible(true);
* $id_fieldGetter = lookup.unreflectGetter(field);
* $id_fieldSetter = lookup.unreflectSetter(field);
@ -539,37 +546,27 @@ public class ClassGeneratingPropertyAccessorFactory @@ -539,37 +546,27 @@ public class ClassGeneratingPropertyAccessorFactory
String.format("()%s", referenceName(JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP)), false);
mv.visitVarInsn(ASTORE, 0);
List<Class<?>> entityClasses = getPropertyDeclaratingClasses(persistentProperties);
for (Class<?> entityClass : entityClasses) {
mv.visitLdcInsn(entityClass.getName());
mv.visitMethodInsn(INVOKESTATIC, JAVA_LANG_CLASS, "forName",
String.format("(%s)%s", referenceName(JAVA_LANG_STRING), referenceName(JAVA_LANG_CLASS)), false);
mv.visitVarInsn(ASTORE, classVariableIndex5(entityClasses, entityClass));
}
for (PersistentProperty<?> property : persistentProperties) {
if (property.usePropertyAccess()) {
if (generateMethodHandle(entity, property.getGetter())) {
visitPropertyGetterInitializer(property, mv, entityClasses, internalClassName);
visitPropertyGetterInitializer(property, mv, internalClassName);
}
if (generateMethodHandle(entity, property.getSetter())) {
visitPropertySetterInitializer(property.getSetter(), property, mv, entityClasses, internalClassName,
visitPropertySetterInitializer(property.getSetter(), property, mv, internalClassName,
PropertyAccessorClassGenerator::setterName, 2);
}
}
if (property.isImmutable() && generateMethodHandle(entity, property.getWither())) {
visitPropertySetterInitializer(property.getWither(), property, mv, entityClasses, internalClassName,
visitPropertySetterInitializer(property.getWither(), property, mv, internalClassName,
PropertyAccessorClassGenerator::witherName, 4);
}
if (generateSetterMethodHandle(entity, property.getField())) {
visitFieldGetterSetterInitializer(property, mv, entityClasses, internalClassName);
visitFieldGetterSetterInitializer(property, mv, internalClassName);
}
}
@ -582,14 +579,36 @@ public class ClassGeneratingPropertyAccessorFactory @@ -582,14 +579,36 @@ public class ClassGeneratingPropertyAccessorFactory
mv.visitLocalVariable("getter", referenceName(JAVA_LANG_REFLECT_METHOD), null, l0, l1, 3);
mv.visitLocalVariable("wither", referenceName(JAVA_LANG_REFLECT_METHOD), null, l0, l1, 4);
for (Class<?> entityClass : entityClasses) {
mv.visitMaxs(0, 0);
mv.visitEnd();
}
static boolean requiresMethodHandleSetup(PersistentEntity<?, ?> entity,
List<PersistentProperty<?>> persistentProperties) {
for (PersistentProperty<?> property : persistentProperties) {
if (property.usePropertyAccess()) {
if (generateMethodHandle(entity, property.getGetter())) {
return true;
}
if (generateMethodHandle(entity, property.getSetter())) {
return true;
}
}
if (property.isImmutable() && generateMethodHandle(entity, property.getWither())) {
return true;
}
int index = classVariableIndex5(entityClasses, entityClass);
mv.visitLocalVariable(String.format("class_%d", index), referenceName(JAVA_LANG_CLASS), null, l0, l1, index);
if (generateSetterMethodHandle(entity, property.getField())) {
return true;
}
}
mv.visitMaxs(0, 0);
mv.visitEnd();
return false;
}
/**
@ -617,14 +636,14 @@ public class ClassGeneratingPropertyAccessorFactory @@ -617,14 +636,14 @@ public class ClassGeneratingPropertyAccessorFactory
* Generate property getter initializer.
*/
private static void visitPropertyGetterInitializer(PersistentProperty<?> property, MethodVisitor mv,
List<Class<?>> entityClasses, String internalClassName) {
String internalClassName) {
// getter = <entity>.class.getDeclaredMethod()
Method getter = property.getGetter();
if (getter != null) {
mv.visitVarInsn(ALOAD, classVariableIndex5(entityClasses, getter.getDeclaringClass()));
mv.visitLdcInsn(Type.getObjectType(Type.getInternalName(getter.getDeclaringClass())));
mv.visitLdcInsn(getter.getName());
mv.visitInsn(ICONST_0);
mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_CLASS);
@ -657,14 +676,14 @@ public class ClassGeneratingPropertyAccessorFactory @@ -657,14 +676,14 @@ public class ClassGeneratingPropertyAccessorFactory
* Generate property setter/wither initializer.
*/
private static void visitPropertySetterInitializer(@Nullable Method method, PersistentProperty<?> property,
MethodVisitor mv, List<Class<?>> entityClasses, String internalClassName,
MethodVisitor mv, String internalClassName,
Function<PersistentProperty<?>, String> setterNameFunction, int localVariableIndex) {
// method = <entity>.class.getDeclaredMethod()
if (method != null) {
mv.visitVarInsn(ALOAD, classVariableIndex5(entityClasses, method.getDeclaringClass()));
mv.visitLdcInsn(Type.getObjectType(Type.getInternalName(method.getDeclaringClass())));
mv.visitLdcInsn(method.getName());
mv.visitInsn(ICONST_1);
@ -711,14 +730,14 @@ public class ClassGeneratingPropertyAccessorFactory @@ -711,14 +730,14 @@ public class ClassGeneratingPropertyAccessorFactory
* Generate field getter and setter initializers.
*/
private static void visitFieldGetterSetterInitializer(PersistentProperty<?> property, MethodVisitor mv,
List<Class<?>> entityClasses, String internalClassName) {
String internalClassName) {
// field = <entity>.class.getDeclaredField()
Field field = property.getField();
if (field != null) {
mv.visitVarInsn(ALOAD, classVariableIndex5(entityClasses, field.getDeclaringClass()));
mv.visitLdcInsn(Type.getObjectType(Type.getInternalName(field.getDeclaringClass())));
mv.visitLdcInsn(field.getName());
mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_CLASS, "getDeclaredField",
String.format("(%s)%s", referenceName(JAVA_LANG_STRING), referenceName(JAVA_LANG_REFLECT_FIELD)), false);

Loading…
Cancel
Save