From 5f9d90ee3e997623af0d76d9bfe151206e712f99 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 16 May 2017 19:11:12 +0200 Subject: [PATCH] DATACMNS-1066 - ClassGeneratingPropertyAccessorFactory now opts out on failed access to ClassLoader. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now eagerly check the accessibility of the defineClass(…) method on the class loader to be used for a PersistentEntity. This will then cause the clients to use a different PropertyAccessorFactory (as things stand today: the one using reflection) and not fail to create the class later on. --- ...lassGeneratingPropertyAccessorFactory.java | 30 ++++++++++++------- 1 file changed, 20 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 6f4c2ebbf..a34fb18eb 100644 --- a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java +++ b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java @@ -36,7 +36,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; import java.util.stream.Collectors; import org.springframework.asm.ClassWriter; @@ -44,7 +43,6 @@ import org.springframework.asm.Label; import org.springframework.asm.MethodVisitor; import org.springframework.asm.Opcodes; import org.springframework.asm.Type; -import org.springframework.data.mapping.Association; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; @@ -94,8 +92,8 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert * Checks whether an accessor class can be generated. * * @param entity - * @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. + * @return {@literal true} if the runtime is equal or greater to Java 1.7, we can access the ClassLoader, the property + * name hash codes are unique and the type has a class loader we can use to re-inject types. * @see PersistentPropertyAccessorFactory#isSupported(PersistentEntity) */ @Override @@ -103,6 +101,12 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert Assert.notNull(entity, "PersistentEntity must not be null!"); + try { + Evil.getClassLoaderMethod(entity); + } catch (Exception o_O) { + return false; + } + if (entity.getType().getClassLoader() == null || entity.getType().getPackage().getName().startsWith("java")) { return false; } @@ -1432,6 +1436,7 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert * accessed from a class in the same class loader. * * @author Mark Paluch + * @author Oliver Gierke */ @UtilityClass private static class Evil { @@ -1446,25 +1451,30 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert * @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(); - Method defineClass = ReflectionUtils.findMethod(classLoaderClass, "defineClass", String.class, byte[].class, - Integer.TYPE, Integer.TYPE, ProtectionDomain.class); + Method defineClass = getClassLoaderMethod(persistentEntity); defineClass.setAccessible(true); return (Class) defineClass.invoke(classLoader, name, bytes, offset, len, - persistentEntityClass.getProtectionDomain()); + persistentEntity.getClass().getProtectionDomain()); } catch (ReflectiveOperationException e) { throw new IllegalStateException(e); } } + + static Method getClassLoaderMethod(PersistentEntity entity) { + + ClassLoader classLoader = entity.getType().getClassLoader(); + Class classLoaderClass = classLoader.getClass(); + + return ReflectionUtils.findMethod(classLoaderClass, "defineClass", String.class, byte[].class, Integer.TYPE, + Integer.TYPE, ProtectionDomain.class); + } } }