From 679f30e109a94127e536c43f2397a7c8c6212682 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 | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 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 8b0f965d94..402dd0a908 100644 --- a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java +++ b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingPropertyAccessorFactory.java @@ -91,8 +91,8 @@ public PersistentPropertyAccessor getPropertyAccessor(PersistentEntity ent * 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 @@ -104,6 +104,12 @@ public boolean isSupported(PersistentEntity entity) { return false; } + try { + Evil.getClassLoaderMethod(entity); + } catch (Exception o_O) { + return false; + } + if (entity.getType().getClassLoader() == null || entity.getType().getPackage().getName().startsWith("java")) { return false; } @@ -1446,6 +1452,7 @@ public int compareTo(PropertyStackAddress o) { * accessed from a class in the same class loader. * * @author Mark Paluch + * @author Oliver Gierke */ @UtilityClass private static class Evil { @@ -1460,25 +1467,30 @@ private static class Evil { * @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); + } } }