DATACMNS-1066 - ClassGeneratingPropertyAccessorFactory now opts out on failed access to ClassLoader.

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.
This commit is contained in:
Oliver Gierke
2017-05-16 19:11:12 +02:00
parent f558a6c4d5
commit 679f30e109

View File

@@ -91,8 +91,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
@@ -104,6 +104,12 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
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 class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
* accessed from a class in the same class loader.
*
* @author Mark Paluch
* @author Oliver Gierke
*/
@UtilityClass
private static class Evil {
@@ -1460,25 +1467,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<? extends PersistentEntity> 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);
}
}
}