diff --git a/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java b/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java index 281b8cd9b..04774750b 100644 --- a/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java +++ b/src/main/java/org/springframework/data/mapping/model/BasicPersistentEntity.java @@ -15,6 +15,9 @@ */ package org.springframework.data.mapping.model; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + import java.io.Serializable; import java.lang.annotation.Annotation; import java.util.ArrayList; @@ -63,12 +66,11 @@ public class BasicPersistentEntity> implement private final Map propertyCache; private final Map, Annotation> annotationCache; + private final PersistentPropertyAccessorFactory propertyAccessorFactory; private P idProperty; private P versionProperty; - private final PersistentPropertyAccessorFactory propertyAccessorFactory; - /** * Creates a new {@link BasicPersistentEntity} from the given {@link TypeInformation}. * @@ -440,17 +442,17 @@ public class BasicPersistentEntity> implement * * @author Oliver Gierke */ + @RequiredArgsConstructor private static final class AssociationComparator

> implements Comparator>, Serializable { private static final long serialVersionUID = 4508054194886854513L; - private final Comparator

delegate; - - public AssociationComparator(Comparator

delegate) { - Assert.notNull(delegate); - this.delegate = delegate; - } + private final @NonNull Comparator

delegate; + /* + * (non-Javadoc) + * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) + */ public int compare(Association

left, Association

right) { return delegate.compare(left.getInverse(), right.getInverse()); } 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 c4a7713a9..e0fbe3b7d 100644 --- a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java +++ b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java @@ -13,11 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mapping.model; import static org.springframework.asm.Opcodes.*; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.experimental.UtilityClass; + import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; @@ -52,24 +55,17 @@ import org.springframework.util.ReflectionUtils; * to overcome Java visibility issues or directly using field access/getter/setter calls. * * @author Mark Paluch + * @author Oliver Gierke * @since 1.13 */ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccessorFactory { - private static final boolean IS_JAVA_JAVA_7 = org.springframework.util.ClassUtils + private static final boolean IS_JAVA_7_OR_BETTER = org.springframework.util.ClassUtils .isPresent("java.lang.invoke.MethodHandle", ClassGeneratingPropertyAccessorFactory.class.getClassLoader()); - private final PropertyAccessorClassGenerator generator; private volatile Map, Class> propertyAccessorClasses = new HashMap, Class>( 32); - /** - * Creates a new {@link ClassGeneratingPropertyAccessorFactory}. - */ - public ClassGeneratingPropertyAccessorFactory() { - this.generator = new PropertyAccessorClassGenerator(); - } - /* (non-Javadoc) * @see org.springframework.data.mapping.model.PersistentPropertyAccessorFactory#getPropertyAccessor(org.springframework.data.mapping.PersistentEntity, java.lang.Object) */ @@ -93,12 +89,12 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * Checks whether an accessor class can be generated. * * @param entity - * @return true if the runtime is equal or greater to Java 1.7, property name hash codes are unique and the type has a - * class loader we can use to re-inject types. + * @return {@literal true} if the runtime is equal or greater to Java 1.7, property name hash codes are unique and the + * type has a class loader we can use to re-inject types. */ public static boolean canGenerateAccessorClass(PersistentEntity entity) { - if (!IS_JAVA_JAVA_7) { + if (!IS_JAVA_7_OR_BETTER) { return false; } @@ -108,18 +104,24 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess final Set hashCodes = new HashSet(); final AtomicInteger propertyCount = new AtomicInteger(); + entity.doWithProperties(new SimplePropertyHandler() { + @Override public void doWithPersistentProperty(PersistentProperty property) { + hashCodes.add(property.getName().hashCode()); propertyCount.incrementAndGet(); } }); entity.doWithAssociations(new SimpleAssociationHandler() { + @Override public void doWithAssociation(Association> association) { + if (association.getInverse() != null) { + hashCodes.add(association.getInverse().getName().hashCode()); propertyCount.incrementAndGet(); } @@ -130,7 +132,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess } /** - * @param entity + * @param entity must not be {@literal null}. * @return */ private synchronized Class potentiallyCreateAndRegisterPersistentPropertyAccessorClass( @@ -157,7 +159,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess private Class createAccessorClass(PersistentEntity entity) { try { - return (Class) this.generator.generateCustomAccessorClass(entity); + return (Class) PropertyAccessorClassGenerator.generateCustomAccessorClass(entity); } catch (Exception e) { throw new RuntimeException(e); } @@ -260,28 +262,18 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess private static final String[] IMPLEMENTED_INTERFACES = new String[] { Type.getInternalName(PersistentPropertyAccessor.class) }; - public PropertyAccessorClassGenerator() {} - - /** - * @param entity - * @return - */ - private String generateClassName(PersistentEntity entity) { - return entity.getType().getName() + TAG + Integer.toString(entity.hashCode(), 36); - } - /** * Generate a new class for the given {@link PersistentEntity}. * * @param entity * @return */ - public Class generateCustomAccessorClass(PersistentEntity entity) { + public static Class generateCustomAccessorClass(PersistentEntity entity) { String className = generateClassName(entity); byte[] bytecode = generateBytecode(className.replace('.', '/'), entity); - Class accessorClass = Evil.injector.defineClass(className, bytecode, 0, bytecode.length, entity); + Class accessorClass = Evil.defineClass(className, bytecode, 0, bytecode.length, entity); return accessorClass; } @@ -293,7 +285,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param entity * @return */ - public byte[] generateBytecode(String internalClassName, PersistentEntity entity) { + public static byte[] generateBytecode(String internalClassName, PersistentEntity entity) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(Opcodes.V1_6, ACC_PUBLIC + ACC_SUPER, internalClassName, null, JAVA_LANG_OBJECT, IMPLEMENTED_INTERFACES); @@ -312,10 +304,12 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess return cw.toByteArray(); } - private List> getPersistentProperties(PersistentEntity entity) { + private static List> getPersistentProperties(PersistentEntity entity) { final List> persistentProperties = new ArrayList>(); + entity.doWithAssociations(new SimpleAssociationHandler() { + @Override public void doWithAssociation(Association> association) { if (association.getInverse() != null) { @@ -325,11 +319,13 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess }); entity.doWithProperties(new SimplePropertyHandler() { + @Override public void doWithPersistentProperty(PersistentProperty property) { persistentProperties.add(property); } }); + return persistentProperties; } @@ -350,13 +346,14 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param persistentProperties * @param cw */ - private void visitFields(PersistentEntity entity, List> persistentProperties, + private static void visitFields(PersistentEntity entity, List> persistentProperties, ClassWriter cw) { cw.visitInnerClass(JAVA_LANG_INVOKE_METHOD_HANDLES_LOOKUP, JAVA_LANG_INVOKE_METHOD_HANDLES, "Lookup", ACC_PRIVATE + ACC_FINAL + ACC_STATIC); boolean accessibleType = isAccessible(entity); + if (accessibleType) { cw.visitField(ACC_PRIVATE + ACC_FINAL, BEAN_FIELD, referenceName(Type.getInternalName(entity.getType())), null, null).visitEnd(); @@ -367,19 +364,24 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess for (PersistentProperty property : persistentProperties) { Method setter = property.getSetter(); + if (setter != null && generateMethodHandle(entity, setter)) { cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, setterName(property), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd(); } Method getter = property.getGetter(); + if (getter != null && generateMethodHandle(entity, getter)) { + cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, getterName(property), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd(); } Field field = property.getField(); + if (field != null && generateSetterMethodHandle(entity, field)) { + cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, fieldSetterName(property), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE), null, null).visitEnd(); cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, fieldGetterName(property), @@ -404,11 +406,13 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param internalClassName * @param cw */ - private void visitDefaultConstructor(PersistentEntity entity, String internalClassName, ClassWriter cw) { + private static void visitDefaultConstructor(PersistentEntity entity, String internalClassName, + ClassWriter cw) { // public EntityAccessor(Entity bean) or EntityAccessor(Object bean) MethodVisitor mv; boolean accessibleType = isAccessible(entity); + if (accessibleType) { mv = cw.visitMethod(ACC_PUBLIC, INIT, String.format("(%s)V", referenceName(entity.getType())), null, null); } else { @@ -475,8 +479,8 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param internalClassName * @param cw */ - private void visitStaticInitializer(PersistentEntity entity, List> persistentProperties, - String internalClassName, ClassWriter cw) { + private static void visitStaticInitializer(PersistentEntity entity, + List> persistentProperties, String internalClassName, ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_STATIC, CLINIT, "()V", null, null); mv.visitCode(); @@ -492,6 +496,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess List> 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); @@ -522,8 +527,8 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess mv.visitLocalVariable("getter", referenceName(JAVA_LANG_REFLECT_METHOD), null, l0, l1, 3); for (Class entityClass : entityClasses) { - int index = classVariableIndex4(entityClasses, entityClass); + int index = classVariableIndex4(entityClasses, entityClass); mv.visitLocalVariable(String.format("class_%d", index), referenceName(JAVA_LANG_CLASS), null, l0, l1, index); } @@ -538,17 +543,20 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param persistentProperties * @return */ - private List> getPropertyDeclaratingClasses(List> persistentProperties) { + private static List> getPropertyDeclaratingClasses(List> persistentProperties) { Set> entityClassesSet = new HashSet>(); + for (PersistentProperty property : persistentProperties) { if (property.getField() != null) { entityClassesSet.add(property.getField().getDeclaringClass()); } + if (property.getGetter() != null) { entityClassesSet.add(property.getGetter().getDeclaringClass()); } + if (property.getSetter() != null) { entityClassesSet.add(property.getSetter().getDeclaringClass()); } @@ -565,11 +573,12 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param entityClasses * @param internalClassName */ - private void visitPropertyGetterInitializer(PersistentProperty property, MethodVisitor mv, + private static void visitPropertyGetterInitializer(PersistentProperty property, MethodVisitor mv, List> entityClasses, String internalClassName) { // getter = .class.getDeclaredMethod() Method getter = property.getGetter(); + if (getter != null) { mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, getter.getDeclaringClass())); mv.visitLdcInsn(getter.getName()); @@ -593,6 +602,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess } else { mv.visitInsn(ACONST_NULL); } + mv.visitFieldInsn(PUTSTATIC, internalClassName, getterName(property), referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)); } @@ -605,11 +615,12 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param entityClasses * @param internalClassName */ - private void visitPropertySetterInitializer(PersistentProperty property, MethodVisitor mv, + private static void visitPropertySetterInitializer(PersistentProperty property, MethodVisitor mv, List> entityClasses, String internalClassName) { // setter = .class.getDeclaredMethod() Method setter = property.getSetter(); + if (setter != null) { mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, setter.getDeclaringClass())); @@ -652,8 +663,9 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param entityClasses * @param internalClassName */ - private void visitFieldGetterSetterInitializer(PersistentProperty property, MethodVisitor mv, + private static void visitFieldGetterSetterInitializer(PersistentProperty property, MethodVisitor mv, List> entityClasses, String internalClassName) { + // field = .class.getDeclaredField() Field field = property.getField(); mv.visitVarInsn(ALOAD, classVariableIndex4(entityClasses, field.getDeclaringClass())); @@ -684,7 +696,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess referenceName(JAVA_LANG_INVOKE_METHOD_HANDLE)); } - private void visitBeanGetter(PersistentEntity entity, String internalClassName, ClassWriter cw) { + private static void visitBeanGetter(PersistentEntity entity, String internalClassName, ClassWriter cw) { // public Object getBean() MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getBean", String.format("()%s", referenceName(JAVA_LANG_OBJECT)), @@ -695,11 +707,13 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess // return this.bean mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 0); + if (isAccessible(entity)) { mv.visitFieldInsn(GETFIELD, internalClassName, BEAN_FIELD, referenceName(entity.getType())); } else { mv.visitFieldInsn(GETFIELD, internalClassName, BEAN_FIELD, referenceName(JAVA_LANG_OBJECT)); } + mv.visitInsn(ARETURN); Label l1 = new Label(); @@ -738,8 +752,8 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param internalClassName * @param cw */ - private void visitGetProperty(PersistentEntity entity, List> persistentProperties, - String internalClassName, ClassWriter cw) { + private static void visitGetProperty(PersistentEntity entity, + List> persistentProperties, String internalClassName, ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getProperty", "(Lorg/springframework/data/mapping/PersistentProperty;)Ljava/lang/Object;", @@ -754,6 +768,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess visitAssertNotNull(mv); mv.visitVarInsn(ALOAD, 0); + if (isAccessible(entity)) { mv.visitFieldInsn(GETFIELD, internalClassName, BEAN_FIELD, referenceName(entity.getType())); } else { @@ -788,8 +803,8 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param internalClassName * @param mv */ - private void visitGetPropertySwitch(PersistentEntity entity, List> persistentProperties, - String internalClassName, MethodVisitor mv) { + private static void visitGetPropertySwitch(PersistentEntity entity, + List> persistentProperties, String internalClassName, MethodVisitor mv) { Map propertyStackMap = createPropertyStackMap(persistentProperties); @@ -799,6 +814,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess Collections.sort(stackmap); for (int i = 0; i < stackmap.size(); i++) { + PropertyStackAddress propertyStackAddress = stackmap.get(i); hashes[i] = propertyStackAddress.hash; switchJumpLabels[i] = propertyStackAddress.label; @@ -838,8 +854,8 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param mv * @param internalClassName */ - private void visitGetProperty0(PersistentEntity entity, PersistentProperty property, MethodVisitor mv, - String internalClassName) { + private static void visitGetProperty0(PersistentEntity entity, PersistentProperty property, + MethodVisitor mv, String internalClassName) { Method getter = property.getGetter(); if (property.usePropertyAccess() && getter != null) { @@ -905,8 +921,8 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param internalClassName * @param cw */ - private void visitSetProperty(PersistentEntity entity, List> persistentProperties, - String internalClassName, ClassWriter cw) { + private static void visitSetProperty(PersistentEntity entity, + List> persistentProperties, String internalClassName, ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "setProperty", "(Lorg/springframework/data/mapping/PersistentProperty;Ljava/lang/Object;)V", @@ -919,6 +935,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess visitAssertNotNull(mv); mv.visitVarInsn(ALOAD, 0); + if (isAccessible(entity)) { mv.visitFieldInsn(GETFIELD, internalClassName, BEAN_FIELD, referenceName(entity.getType())); } else { @@ -957,8 +974,8 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param internalClassName * @param mv */ - private void visitSetPropertySwitch(PersistentEntity entity, List> persistentProperties, - String internalClassName, MethodVisitor mv) { + private static void visitSetPropertySwitch(PersistentEntity entity, + List> persistentProperties, String internalClassName, MethodVisitor mv) { Map propertyStackMap = createPropertyStackMap(persistentProperties); @@ -1006,8 +1023,8 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param mv * @param internalClassName */ - private void visitSetProperty0(PersistentEntity entity, PersistentProperty property, MethodVisitor mv, - String internalClassName) { + private static void visitSetProperty0(PersistentEntity entity, PersistentProperty property, + MethodVisitor mv, String internalClassName) { Method setter = property.getSetter(); if (property.usePropertyAccess() && setter != null) { @@ -1061,7 +1078,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess mv.visitInsn(RETURN); } - private void visitAssertNotNull(MethodVisitor mv) { + private static void visitAssertNotNull(MethodVisitor mv) { // Assert.notNull(property) mv.visitVarInsn(ALOAD, 1); @@ -1070,7 +1087,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess String.format("(%s%s)V", referenceName(JAVA_LANG_OBJECT), referenceName(JAVA_LANG_STRING)), false); } - private void visitThrowUnsupportedOperationException(MethodVisitor mv, String message) { + private static void visitThrowUnsupportedOperationException(MethodVisitor mv, String message) { // throw new UnsupportedOperationException(msg) mv.visitTypeInsn(NEW, JAVA_LANG_UNSUPPORTED_OPERATION_EXCEPTION); @@ -1089,40 +1106,35 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess mv.visitInsn(ATHROW); } - private String fieldSetterName(PersistentProperty property) { + private static String fieldSetterName(PersistentProperty property) { return String.format("$%s_fieldSetter", property.getName()); } - private String fieldGetterName(PersistentProperty property) { + private static String fieldGetterName(PersistentProperty property) { return String.format("$%s_fieldGetter", property.getName()); } - private String setterName(PersistentProperty property) { + private static String setterName(PersistentProperty property) { return String.format("$%s_setter", property.getName()); } - private String getterName(PersistentProperty property) { + private static String getterName(PersistentProperty property) { return String.format("$%s_getter", property.getName()); } - private boolean isAccessible(PersistentEntity entity) { + private static boolean isAccessible(PersistentEntity entity) { return isAccessible(entity.getType()); } - private boolean isAccessible(Class theClass) { + private static boolean isAccessible(Class theClass) { return isAccessible(theClass.getModifiers()); } - private boolean isAccessible(int modifiers) { - - if (Modifier.isPrivate(modifiers)) { - return false; - } - - return true; + private static boolean isAccessible(int modifiers) { + return !Modifier.isPrivate(modifiers); } - private boolean isDefault(int modifiers) { + private static boolean isDefault(int modifiers) { if (Modifier.isPrivate(modifiers) || Modifier.isProtected(modifiers) || Modifier.isPublic(modifiers)) { return false; @@ -1131,7 +1143,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess return true; } - private boolean generateSetterMethodHandle(PersistentEntity entity, Field field) { + private static boolean generateSetterMethodHandle(PersistentEntity entity, Field field) { return generateMethodHandle(entity, field) || Modifier.isFinal(field.getModifiers()); } @@ -1144,7 +1156,7 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param member * @return */ - private boolean generateMethodHandle(PersistentEntity entity, Member member) { + private static boolean generateMethodHandle(PersistentEntity entity, Member member) { if (isAccessible(entity)) { @@ -1168,10 +1180,17 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param item * @return */ - private int classVariableIndex4(List> list, Class item) { + private static int classVariableIndex4(List> list, Class item) { return 4 + list.indexOf(item); } + /** + * @param entity + * @return + */ + private static String generateClassName(PersistentEntity entity) { + return entity.getType().getName() + TAG + Integer.toString(entity.hashCode(), 36); + } } private static String referenceName(Class type) { @@ -1244,83 +1263,83 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess } /** - * Autobox/Auto-unbox primitives to object and vice versa. + * Auto-box/Auto-unbox primitives to object and vice versa. * * @param in the input type * @param out the expected output type - * @param mv + * @param visitor */ - private static void autoboxIfNeeded(Class in, Class out, MethodVisitor mv) { + private static void autoboxIfNeeded(Class in, Class out, MethodVisitor visitor) { if (in.equals(Boolean.class) && out.equals(Boolean.TYPE)) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); + visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); } if (in.equals(Boolean.TYPE) && out.equals(Boolean.class)) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); + visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); } if (in.equals(Byte.class) && out.equals(Byte.TYPE)) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); + visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); } if (in.equals(Byte.TYPE) && out.equals(Byte.class)) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); + visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); } if (in.equals(Character.class) && out.equals(Character.TYPE)) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false); + visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false); } if (in.equals(Character.TYPE) && out.equals(Character.class)) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); + visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); } if (in.equals(Double.class) && out.equals(Double.TYPE)) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); + visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); } if (in.equals(Double.TYPE) && out.equals(Double.class)) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); + visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); } if (in.equals(Float.class) && out.equals(Float.TYPE)) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); + visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); } if (in.equals(Float.TYPE) && out.equals(Float.class)) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); + visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); } if (in.equals(Integer.class) && out.equals(Integer.TYPE)) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); } if (in.equals(Integer.TYPE) && out.equals(Integer.class)) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); } if (in.equals(Long.class) && out.equals(Long.TYPE)) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); + visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); } if (in.equals(Long.TYPE) && out.equals(Long.class)) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); + visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); } if (in.equals(Short.class) && out.equals(Short.TYPE)) { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false); + visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false); } if (in.equals(Short.TYPE) && out.equals(Short.class)) { - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); + visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); } } /** * Returns the signature type for a {@link Class} including primitives. * - * @param type + * @param type must not be {@literal null}. * @return */ private static String signatureTypeName(Class type) { @@ -1369,16 +1388,16 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * * @author Mark Paluch */ + @RequiredArgsConstructor static class PropertyStackAddress implements Comparable { - final int hash; - final Label label; - - public PropertyStackAddress(Label label, int hash) { - this.label = label; - this.hash = hash; - } + private final @NonNull Label label; + private final int hash; + /* + * (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ @Override public int compareTo(PropertyStackAddress o) { return (hash < o.hash) ? -1 : ((hash == o.hash) ? 0 : 1); @@ -1392,12 +1411,9 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * * @author Mark Paluch */ + @UtilityClass private static class Evil { - final static Evil injector = new Evil(); - - private Evil() {} - /** * Define a Class in the {@link ClassLoader} of the {@link PersistentEntity} type. * @@ -1408,10 +1424,12 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess * @param persistentEntity * @return */ + @SuppressWarnings("rawtypes") Class defineClass(String name, byte[] bytes, int offset, int len, PersistentEntity persistentEntity) { ClassLoader classLoader = persistentEntity.getType().getClassLoader(); Class classLoaderClass = classLoader.getClass(); + try { Class persistentEntityClass = persistentEntity.getClass(); @@ -1421,10 +1439,10 @@ class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccess return (Class) defineClass.invoke(classLoader, name, bytes, offset, len, persistentEntityClass.getProtectionDomain()); + } catch (ReflectiveOperationException e) { throw new IllegalStateException(e); } } } - } diff --git a/src/main/java/org/springframework/data/mapping/model/DefaultPersistentPropertyAccessorFactory.java b/src/main/java/org/springframework/data/mapping/model/DefaultPersistentPropertyAccessorFactory.java index 2c7e33eaa..baca16172 100644 --- a/src/main/java/org/springframework/data/mapping/model/DefaultPersistentPropertyAccessorFactory.java +++ b/src/main/java/org/springframework/data/mapping/model/DefaultPersistentPropertyAccessorFactory.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mapping.model; import org.springframework.data.mapping.PersistentEntity; @@ -24,22 +23,21 @@ import org.springframework.data.mapping.PersistentPropertyAccessor; * reflection or use generated classes with direct field/method access. * * @author Mark Paluch + * @author Oliver Gierke * @since 1.13 */ public class DefaultPersistentPropertyAccessorFactory implements PersistentPropertyAccessorFactory { private final ClassGeneratingPropertyAccessorFactory classGeneratingPropertyAccessorFactory = new ClassGeneratingPropertyAccessorFactory(); - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.mapping.model.PersistentPropertyAccessorFactory#getPropertyAccessor(org.springframework.data.mapping.PersistentEntity, java.lang.Object) */ @Override public PersistentPropertyAccessor getPropertyAccessor(PersistentEntity entity, Object bean) { - if (ClassGeneratingPropertyAccessorFactory.canGenerateAccessorClass(entity)) { - return classGeneratingPropertyAccessorFactory.getPropertyAccessor(entity, bean); - } - return new BeanWrapper(bean); + return ClassGeneratingPropertyAccessorFactory.canGenerateAccessorClass(entity) + ? classGeneratingPropertyAccessorFactory.getPropertyAccessor(entity, bean) : new BeanWrapper(bean); } - } diff --git a/src/main/java/org/springframework/data/mapping/model/PersistentPropertyAccessorFactory.java b/src/main/java/org/springframework/data/mapping/model/PersistentPropertyAccessorFactory.java index ae5b5b292..b68ad0dc4 100644 --- a/src/main/java/org/springframework/data/mapping/model/PersistentPropertyAccessorFactory.java +++ b/src/main/java/org/springframework/data/mapping/model/PersistentPropertyAccessorFactory.java @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mapping.model; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentPropertyAccessor; /** - * Factory to create {@link PersistentPropertyAccessor} for a given {@link PersistentEntity} and {@code bean}. + * Factory to create {@link PersistentPropertyAccessor} for a given {@link PersistentEntity} and bean instance. * * @author Mark Paluch + * @author Oliver Gierke * @since 1.13 */ public interface PersistentPropertyAccessorFactory { @@ -30,9 +30,9 @@ public interface PersistentPropertyAccessorFactory { /** * Returns a {@link PersistentPropertyAccessor} for a given {@link PersistentEntity} and {@code bean}. * - * @param bean - * @return + * @param entity must not be {@literal null}. + * @param bean must not be {@literal null}. + * @return will never be {@literal null}. */ PersistentPropertyAccessor getPropertyAccessor(PersistentEntity entity, Object bean); - } 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 5e5065aec..31d2eeda4 100644 --- a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryDatatypeTests.java +++ b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryDatatypeTests.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mapping.model; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.*; +import lombok.Data; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -35,12 +36,11 @@ import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.context.SampleMappingContext; import org.springframework.data.mapping.context.SamplePersistentProperty; -import lombok.Data; - /** * Unit tests for {@link ClassGeneratingPropertyAccessorFactory} * * @author Mark Paluch + * @author Oliver Gierke * @see DATACMNS-809 */ @RunWith(Parameterized.class) @@ -49,9 +49,9 @@ public class ClassGeneratingPropertyAccessorFactoryDatatypeTests { private final ClassGeneratingPropertyAccessorFactory factory = new ClassGeneratingPropertyAccessorFactory(); private final SampleMappingContext mappingContext = new SampleMappingContext(); - private Object bean; - private String propertyName; - private Object value; + private final Object bean; + private final String propertyName; + private final Object value; public ClassGeneratingPropertyAccessorFactoryDatatypeTests(Object bean, String propertyName, Object value, String displayName) { @@ -62,10 +62,10 @@ public class ClassGeneratingPropertyAccessorFactoryDatatypeTests { } @Parameters(name = "{3}") + @SuppressWarnings("unchecked") public static List parameters() throws Exception { List parameters = new ArrayList(); - List> types = Arrays.asList(FieldAccess.class, PropertyAccess.class); parameters.addAll(parameters(types, "primitiveInteger", Integer.valueOf(1))); @@ -120,7 +120,6 @@ public class ClassGeneratingPropertyAccessorFactoryDatatypeTests { /** * @see DATACMNS-809 - * @throws Exception */ @Test public void shouldSetAndGetProperty() throws Exception { @@ -243,5 +242,4 @@ public class ClassGeneratingPropertyAccessorFactoryDatatypeTests { 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 a8f5d6586..aa59226b9 100644 --- a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryTests.java +++ b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactoryTests.java @@ -49,9 +49,9 @@ public class ClassGeneratingPropertyAccessorFactoryTests { private final ClassGeneratingPropertyAccessorFactory factory = new ClassGeneratingPropertyAccessorFactory(); private final SampleMappingContext mappingContext = new SampleMappingContext(); - private Object bean; - private String propertyName; - private Class expectedConstructorType; + private final Object bean; + private final String propertyName; + private final Class expectedConstructorType; public ClassGeneratingPropertyAccessorFactoryTests(Object bean, String propertyName, Class expectedConstructorType, String displayName) { @@ -65,9 +65,9 @@ public class ClassGeneratingPropertyAccessorFactoryTests { public static List parameters() { List parameters = new ArrayList(); - List propertyNames = Arrays.asList("privateField", "packageDefaultField", "protectedField", "publicField", "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 InnerPackageDefaultType(), propertyNames, InnerPackageDefaultType.class)); @@ -77,8 +77,7 @@ public class ClassGeneratingPropertyAccessorFactoryTests { ClassGeneratingPropertyAccessorPackageDefaultType.class)); parameters.addAll(parameters(new ClassGeneratingPropertyAccessorPublicType(), propertyNames, ClassGeneratingPropertyAccessorPublicType.class)); - parameters.addAll(parameters(new SubtypeOfTypeInOtherPackage(), propertyNames, - SubtypeOfTypeInOtherPackage.class)); + parameters.addAll(parameters(new SubtypeOfTypeInOtherPackage(), propertyNames, SubtypeOfTypeInOtherPackage.class)); return parameters; } @@ -114,6 +113,7 @@ public class ClassGeneratingPropertyAccessorFactoryTests { * @throws Exception */ @Test + @SuppressWarnings("rawtypes") public void accessorShouldDeclareConstructor() throws Exception { PersistentPropertyAccessor persistentPropertyAccessor = getPersistentPropertyAccessor(bean); @@ -170,6 +170,7 @@ public class ClassGeneratingPropertyAccessorFactoryTests { /** * @see DATACMNS-809 */ + @SuppressWarnings("unused") private static class InnerPrivateType { private String privateField; @@ -238,6 +239,7 @@ public class ClassGeneratingPropertyAccessorFactoryTests { /** * @see DATACMNS-809 */ + @SuppressWarnings("unused") static class InnerPackageDefaultType { private String privateField; @@ -299,6 +301,7 @@ public class ClassGeneratingPropertyAccessorFactoryTests { /** * @see DATACMNS-809 */ + @SuppressWarnings("unused") protected static class InnerProtectedType { private String privateField; @@ -360,6 +363,7 @@ public class ClassGeneratingPropertyAccessorFactoryTests { /** * @see DATACMNS-809 */ + @SuppressWarnings("unused") public static class InnerPublicType { private String privateField; @@ -418,16 +422,15 @@ public class ClassGeneratingPropertyAccessorFactoryTests { } } - public static class SubtypeOfTypeInOtherPackage extends TypeInOtherPackage{ - - } + public static class SubtypeOfTypeInOtherPackage extends TypeInOtherPackage {} /** * @see DATACMNS-809 */ + @SuppressWarnings("unused") private static class Dummy { + private String dummy; public String publicField; } - } diff --git a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPackageDefaultType.java b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPackageDefaultType.java index f10d540b9..bcc934bb8 100644 --- a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPackageDefaultType.java +++ b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPackageDefaultType.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mapping.model; import org.springframework.data.annotation.AccessType; @@ -21,8 +20,10 @@ import org.springframework.data.annotation.AccessType.Type; /** * @author Mark Paluch + * @author Oliver Gierke * @see DATACMNS-809 */ +@SuppressWarnings("unused") class ClassGeneratingPropertyAccessorPackageDefaultType { private String privateField; @@ -79,5 +80,4 @@ class ClassGeneratingPropertyAccessorPackageDefaultType { public void setSyntheticProperty(String syntheticProperty) { backing = syntheticProperty; } - } diff --git a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPublicType.java b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPublicType.java index d098a684d..45b447f8e 100644 --- a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPublicType.java +++ b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorPublicType.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mapping.model; import org.springframework.data.annotation.AccessType; @@ -21,8 +20,10 @@ import org.springframework.data.annotation.AccessType.Type; /** * @author Mark Paluch + * @author Oliver Gierke * @see DATACMNS-809 */ +@SuppressWarnings("unused") public class ClassGeneratingPropertyAccessorPublicType { private String privateField; @@ -83,12 +84,12 @@ public class ClassGeneratingPropertyAccessorPublicType { } public Object set(Object e) { + aa = (Integer) e; bb = (Integer) e; + return bb; } - public static void main(String[] args) { - - } + public static void main(String[] args) {} }