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:
@@ -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<? 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user