DATACMNS-1175 - Remove argument array caching from EntityInstantiators.

We no longer cache argument arrays in our EntityInstantiators to prevent changes to shared mutable state caused by reentrant calls.

Previously, a re-entrant call requesting an argument array of the same size as a previous call in the call stack reused the same array instance. Changes to this shared mutable state by multiple invocations caused an invalid state rendering wrong parameters for object instantiation. Removing the caching and only reusing an empty array for zero-arg constructors is the only safe approach for now.

Re-instantiation of object allocations results in a higher GC pressure but guarantee side effect-free instantiation and should be on-par with previous versions performance profile.

Original pull request: #247.
This commit is contained in:
Mark Paluch
2017-09-26 14:58:56 +02:00
committed by Oliver Gierke
parent cc0ab54c38
commit 2b4ef1a555
4 changed files with 54 additions and 53 deletions

View File

@@ -147,6 +147,40 @@ public class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProp
}
}
@Test // DATACMNS-1175
@SuppressWarnings({ "unchecked", "rawtypes" })
public void createsInstancesWithRecursionAndSameCtorArgCountCorrectly() {
PersistentEntity<SampleWithReference, P> outer = new BasicPersistentEntity<>(from(SampleWithReference.class));
PersistentEntity<Sample, P> inner = new BasicPersistentEntity<>(from(Sample.class));
doReturn(2L, "FOO").when(provider).getParameterValue(any(Parameter.class));
ParameterValueProvider<P> recursive = new ParameterValueProvider<P>() {
@Override
public <T> T getParameterValue(Parameter<T, P> parameter) {
if (parameter.getName().equals("id")) {
return (T) Long.valueOf(1);
}
if (parameter.getName().equals("sample")) {
return (T) instance.createInstance(inner, provider);
}
throw new UnsupportedOperationException(parameter.getName());
}
};
SampleWithReference reference = this.instance.createInstance(outer, recursive);
assertThat(reference.id).isEqualTo(1L);
assertThat(reference.sample).isNotNull();
assertThat(reference.sample.id).isEqualTo(2L);
assertThat(reference.sample.name).isEqualTo("FOO");
}
@Test // DATACMNS-578, DATACMNS-1126
public void instantiateObjCtorDefault() {
@@ -154,7 +188,8 @@ public class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProp
doReturn(PreferredConstructorDiscoverer.discover(ObjCtorDefault.class))//
.when(entity).getPersistenceConstructor();
IntStream.range(0, 2).forEach(i -> assertThat(this.instance.createInstance(entity, provider)).isInstanceOf(ObjCtorDefault.class));
IntStream.range(0, 2)
.forEach(i -> assertThat(this.instance.createInstance(entity, provider)).isInstanceOf(ObjCtorDefault.class));
}
@Test // DATACMNS-578, DATACMNS-1126
@@ -283,6 +318,18 @@ public class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProp
}
}
static class SampleWithReference {
final Long id;
final Sample sample;
public SampleWithReference(Long id, Sample sample) {
this.id = id;
this.sample = sample;
}
}
/**
* @author Thomas Darimont
*/