DATACMNS-1422 - Fall back to reflection-based PropertyAccessor/EntityInstantiator on inaccessible framework types.

We now fall back to reflection-based PropertyAccessor/EntityInstantiator strategies when framework types are not visible by the entity's ClassLoader.

Typically, we use class generation to create and load PropertyAccessor and EntityInstantiator classes to bypass reflection. Generated types are injected into the ClassLoader that has loaded the actual entity. Generated classes implement framework types such as ObjectInstantiator and these interfaces must be visible to the ClassLoader that hosts the generated class. Some arrangements, such as OSGi isolate class repositories so the OSGi class loader cannot load our own types which prevents loading the generated class.

Original pull request: #324.
This commit is contained in:
Mark Paluch
2018-11-23 14:42:03 +01:00
committed by Oliver Drotbohm
parent 9791bb9354
commit 596b0d8177
4 changed files with 45 additions and 2 deletions

View File

@@ -55,6 +55,7 @@ import org.springframework.data.util.Optionals;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -139,7 +140,9 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
Class<?> type = entity.getType();
return type.getClassLoader() != null
&& (type.getPackage() == null || !type.getPackage().getName().startsWith("java"));
&& (type.getPackage() == null || !type.getPackage().getName().startsWith("java"))
&& ClassUtils.isPresent(PersistentPropertyAccessor.class.getName(), type.getClassLoader())
&& ClassUtils.isPresent(Assert.class.getName(), type.getClassLoader());
}
private boolean hasUniquePropertyHashCodes(PersistentEntity<?, ?> entity) {
@@ -1080,7 +1083,6 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
if (kotlinCopyMethod.shouldUsePublicCopyMethod(entity)) {
// PersonWithId.copy$(value)
mv.visitVarInsn(ALOAD, 3);
mv.visitVarInsn(ALOAD, 2);