From 0e29af3a15c8774f863d0f7597cd16cbe8375804 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 23 Sep 2016 14:12:26 +0200 Subject: [PATCH] DATACMNS-916 - Fix setter lookup in ClassGeneratingPropertyAccessorFactory. Previously, ClassGeneratingPropertyAccessorFactory uses boxed types for primitive type setters. This threw NoSuchMethodExceptions and caused ExceptionInInitializerError as the generated class could not be initialized. We now use the appropriate argument type to look up setters. Also, we now only generate accessor usage if the property is configured to use property access in the first place. Original pull request: #178. --- ...lassGeneratingPropertyAccessorFactory.java | 23 +++- ...gPropertyAccessorFactoryDatatypeTests.java | 109 +++++++++++++++++- ...eneratingPropertyAccessorFactoryTests.java | 4 +- 3 files changed, 126 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java index afe545c75..bdbe7a2e1 100644 --- a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java +++ b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java @@ -511,12 +511,15 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert for (PersistentProperty property : persistentProperties) { - if (property.getGetter() != null && generateMethodHandle(entity, property.getGetter())) { - visitPropertyGetterInitializer(property, mv, entityClasses, internalClassName); - } + if(property.usePropertyAccess()) { - if (property.getSetter() != null && generateMethodHandle(entity, property.getSetter())) { - visitPropertySetterInitializer(property, mv, entityClasses, internalClassName); + if (property.getGetter() != null && generateMethodHandle(entity, property.getGetter())) { + visitPropertyGetterInitializer(property, mv, entityClasses, internalClassName); + } + + if (property.getSetter() != null && generateMethodHandle(entity, property.getSetter())) { + visitPropertySetterInitializer(property, mv, entityClasses, internalClassName); + } } if (property.getField() != null && generateSetterMethodHandle(entity, property.getField())) { @@ -636,7 +639,15 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_CLASS); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); - mv.visitLdcInsn(Type.getType(referenceName(Type.getInternalName(autoboxType(setter.getParameterTypes()[0]))))); + + Class parameterType = setter.getParameterTypes()[0]; + if (parameterType.isPrimitive()) { + mv.visitFieldInsn(GETSTATIC, Type.getInternalName(autoboxType(setter.getParameterTypes()[0])), "TYPE", + referenceName(JAVA_LANG_CLASS)); + } else { + mv.visitLdcInsn(Type.getType(referenceName(parameterType))); + } + mv.visitInsn(AASTORE); mv.visitMethodInsn(INVOKEVIRTUAL, JAVA_LANG_CLASS, "getDeclaredMethod", String.format("(%s[%s)%s", diff --git a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryDatatypeTests.java b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryDatatypeTests.java index 018477770..c9a6925f2 100644 --- a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryDatatypeTests.java +++ b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryDatatypeTests.java @@ -22,6 +22,7 @@ import static org.junit.Assert.*; import lombok.Data; +import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -68,7 +69,7 @@ public class ClassGeneratingPropertyAccessorFactoryDatatypeTests { public static List parameters() throws Exception { List parameters = new ArrayList(); - List> types = Arrays.asList(FieldAccess.class, PropertyAccess.class); + List> types = Arrays.asList(FieldAccess.class, PropertyAccess.class, PrivateFinalFieldAccess.class, PrivateFinalPropertyAccess.class); parameters.addAll(parameters(types, "primitiveInteger", Integer.valueOf(1))); parameters.addAll(parameters(types, "primitiveIntegerArray", new int[] { 1, 2, 3 })); @@ -113,8 +114,11 @@ public class ClassGeneratingPropertyAccessorFactoryDatatypeTests { List parameters = new ArrayList(); for (Class type : types) { + + Constructor[] constructors = type.getDeclaredConstructors(); + constructors[0].setAccessible(true); parameters - .add(new Object[] { type.newInstance(), propertyName, value, type.getSimpleName() + "/" + propertyName }); + .add(new Object[] { constructors[0].newInstance(), propertyName, value, type.getSimpleName() + "/" + propertyName }); } return parameters; @@ -257,4 +261,105 @@ public class ClassGeneratingPropertyAccessorFactoryDatatypeTests { String string; String stringArray[]; } + + /** + * @see DATACMNS-916 + */ + @AccessType(Type.FIELD) + private final static class PrivateFinalFieldAccess { + + int primitiveInteger; + int primitiveIntegerArray[]; + Integer boxedInteger; + Integer boxedIntegerArray[]; + + short primitiveShort; + short primitiveShortArray[]; + Short boxedShort; + Short boxedShortArray[]; + + byte primitiveByte; + byte primitiveByteArray[]; + Byte boxedByte; + Byte boxedByteArray[]; + + char primitiveChar; + char primitiveCharArray[]; + Character boxedChar; + Character boxedCharArray[]; + + boolean primitiveBoolean; + boolean primitiveBooleanArray[]; + Boolean boxedBoolean; + Boolean boxedBooleanArray[]; + + float primitiveFloat; + float primitiveFloatArray[]; + Float boxedFloat; + Float boxedFloatArray[]; + + double primitiveDouble; + double primitiveDoubleArray[]; + Double boxedDouble; + Double boxedDoubleArray[]; + + long primitiveLong; + long primitiveLongArray[]; + Long boxedLong; + Long boxedLongArray[]; + + String string; + String stringArray[]; + } + + /** + * @see DATACMNS-916 + */ + @AccessType(Type.PROPERTY) + @Data + private final static class PrivateFinalPropertyAccess { + + int primitiveInteger; + int primitiveIntegerArray[]; + Integer boxedInteger; + Integer boxedIntegerArray[]; + + short primitiveShort; + short primitiveShortArray[]; + Short boxedShort; + Short boxedShortArray[]; + + byte primitiveByte; + byte primitiveByteArray[]; + Byte boxedByte; + Byte boxedByteArray[]; + + char primitiveChar; + char primitiveCharArray[]; + Character boxedChar; + Character boxedCharArray[]; + + boolean primitiveBoolean; + boolean primitiveBooleanArray[]; + Boolean boxedBoolean; + Boolean boxedBooleanArray[]; + + float primitiveFloat; + float primitiveFloatArray[]; + Float boxedFloat; + Float boxedFloatArray[]; + + double primitiveDouble; + double primitiveDoubleArray[]; + Double boxedDouble; + Double boxedDoubleArray[]; + + long primitiveLong; + long primitiveLongArray[]; + Long boxedLong; + Long boxedLongArray[]; + + String string; + String stringArray[]; + } } diff --git a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryTests.java b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryTests.java index 61ffed0c8..a10b915c4 100644 --- a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryTests.java +++ b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryTests.java @@ -71,7 +71,7 @@ public class ClassGeneratingPropertyAccessorFactoryTests { "privateProperty", "packageDefaultProperty", "protectedProperty", "publicProperty", "syntheticProperty"); parameters.addAll(parameters(new InnerPrivateType(), propertyNames, Object.class)); - parameters.addAll(parameters(new InnerTypeWithPrivateAncesor(), propertyNames, InnerTypeWithPrivateAncesor.class)); + parameters.addAll(parameters(new InnerTypeWithPrivateAncestor(), propertyNames, InnerTypeWithPrivateAncestor.class)); parameters.addAll(parameters(new InnerPackageDefaultType(), propertyNames, InnerPackageDefaultType.class)); parameters.addAll(parameters(new InnerProtectedType(), propertyNames, InnerProtectedType.class)); parameters.addAll(parameters(new InnerPublicType(), propertyNames, InnerPublicType.class)); @@ -247,7 +247,7 @@ public class ClassGeneratingPropertyAccessorFactoryTests { /** * @see DATACMNS-809 */ - public static class InnerTypeWithPrivateAncesor extends InnerPrivateType { + public static class InnerTypeWithPrivateAncestor extends InnerPrivateType { }