diff --git a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiator.java b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiator.java index 2c8022da1..11b04c496 100644 --- a/src/main/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiator.java +++ b/src/main/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiator.java @@ -130,6 +130,13 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator { try { return doCreateEntityInstantiator(entity); } catch (Throwable ex) { + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + String.format("Cannot create entity instantiator for %s. Falling back to ReflectionEntityInstantiator.", + entity.getName()), + ex); + } return ReflectionEntityInstantiator.INSTANCE; } } @@ -376,12 +383,22 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator { @Nullable PreferredConstructor constructor) { String className = generateClassName(entity); + Class type = entity.getType(); + ClassLoader classLoader = type.getClassLoader(); + + if (ClassUtils.isPresent(className, classLoader)) { + + try { + return ClassUtils.forName(className, classLoader); + } catch (Exception o_O) { + throw new IllegalStateException(o_O); + } + } + byte[] bytecode = generateBytecode(className, entity, constructor); - Class type = entity.getType(); - try { - return ReflectUtils.defineClass(className, bytecode, type.getClassLoader(), type.getProtectionDomain(), type); + return ReflectUtils.defineClass(className, bytecode, classLoader, type.getProtectionDomain(), type); } catch (Exception e) { throw new IllegalStateException(e); } diff --git a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiatorUnitTests.java b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiatorUnitTests.java index 00f82f88d..de5e139a9 100755 --- a/src/test/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiatorUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/model/ClassGeneratingEntityInstantiatorUnitTests.java @@ -23,6 +23,7 @@ import static org.springframework.data.util.ClassTypeInformation.from; import java.lang.reflect.Constructor; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.stream.IntStream; import org.junit.jupiter.api.Test; @@ -40,6 +41,8 @@ import org.springframework.data.mapping.PreferredConstructor.Parameter; import org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.ObjectInstantiator; import org.springframework.data.mapping.model.ClassGeneratingEntityInstantiatorUnitTests.Outer.Inner; import org.springframework.data.util.ClassTypeInformation; +import org.springframework.data.util.TypeInformation; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.ReflectionUtils; /** @@ -211,6 +214,9 @@ class ClassGeneratingEntityInstantiatorUnitTests

assertThat(instance).isInstanceOf(ObjCtorNoArgs.class); assertThat(((ObjCtorNoArgs) instance).ctorInvoked).isTrue(); }); + + ClassGeneratingEntityInstantiator classGeneratingEntityInstantiator = new ClassGeneratingEntityInstantiator(); + classGeneratingEntityInstantiator.createInstance(entity, provider); } @Test // DATACMNS-578, DATACMNS-1126 @@ -361,6 +367,26 @@ class ClassGeneratingEntityInstantiatorUnitTests

assertThat(this.instance.shouldUseReflectionEntityInstantiator(entity)).isTrue(); } + @Test // GH-2446 + void shouldReuseGeneratedClasses() { + + prepareMocks(ProtectedInnerClass.class); + + this.instance.createInstance(entity, provider); + + ClassGeneratingEntityInstantiator instantiator = new ClassGeneratingEntityInstantiator(); + instantiator.createInstance(entity, provider); + + Map, EntityInstantiator> first = (Map, EntityInstantiator>) ReflectionTestUtils + .getField(this.instance, "entityInstantiators"); + + Map, EntityInstantiator> second = (Map, EntityInstantiator>) ReflectionTestUtils + .getField(instantiator, "entityInstantiators"); + + assertThat(first.get(null)).isNotNull().isNotInstanceOf(Enum.class); + assertThat(second.get(null)).isNotNull().isNotInstanceOf(Enum.class); + } + @Test // DATACMNS-1422 void shouldUseReflectionIfFrameworkTypesNotVisible() throws Exception {