DATACMNS-1710 - Avoid potentially expensive constructor parameter creation where possible.
Reorder constructor filtering with the goal to delay/avoid potentially expensive PersistenceConstructor creation with parameter lookup as much as possible.
The lookup is (in a default setup) only done once per domain type, but depending on the number of entities to inspect the change can help save some cycles for larger domains.
Before:
Benchmark Mode Cnt Score Error Units
EntityMetadataBenchmark.alwaysNew thrpt 10 224318,163 ± 42542,453 ops/s
After:
Benchmark Mode Cnt Score Error Units
EtityMetadataBenchmark.alwaysNew thrpt 10 420053,505 ± 9288,093 ops/s
public class DomainType {
private String id;
private @Id String theId;
private String firstname, lastname;
private Integer age;
public DomainType(String id, String theId, String firstname, String lastname, Integer age) {
this.id = id;
this.theId = theId;
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
}
@PersistenceConstructor
public DomainType(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
}
Original pull request: #440.
This commit is contained in:
committed by
Mark Paluch
parent
03d5498c22
commit
03832c36a4
@@ -22,11 +22,13 @@ import kotlin.reflect.jvm.ReflectJvmMapping;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
@@ -102,42 +104,33 @@ public interface PreferredConstructorDiscoverer<T, P extends PersistentProperty<
|
||||
<T, P extends PersistentProperty<P>> PreferredConstructor<T, P> discover(TypeInformation<T> type,
|
||||
@Nullable PersistentEntity<T, P> entity) {
|
||||
|
||||
boolean noArgConstructorFound = false;
|
||||
int numberOfArgConstructors = 0;
|
||||
Class<?> rawOwningType = type.getType();
|
||||
PreferredConstructor<T, P> constructor = null;
|
||||
|
||||
List<Constructor<?>> candidates = new ArrayList<>();
|
||||
Constructor<?> noArg = null;
|
||||
for (Constructor<?> candidate : rawOwningType.getDeclaredConstructors()) {
|
||||
|
||||
PreferredConstructor<T, P> preferredConstructor = buildPreferredConstructor(candidate, type, entity);
|
||||
|
||||
// Synthetic constructors should not be considered
|
||||
if (preferredConstructor.getConstructor().isSynthetic()) {
|
||||
if (candidate.isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Explicitly defined constructor trumps all
|
||||
if (preferredConstructor.isExplicitlyAnnotated()) {
|
||||
return preferredConstructor;
|
||||
if(candidate.isAnnotationPresent(PersistenceConstructor.class)) {
|
||||
return buildPreferredConstructor(candidate, type, entity);
|
||||
}
|
||||
|
||||
// No-arg constructor trumps custom ones
|
||||
if (constructor == null || preferredConstructor.isNoArgConstructor()) {
|
||||
constructor = preferredConstructor;
|
||||
}
|
||||
|
||||
if (preferredConstructor.isNoArgConstructor()) {
|
||||
noArgConstructorFound = true;
|
||||
if(candidate.getParameterCount() == 0) {
|
||||
noArg = candidate;
|
||||
} else {
|
||||
numberOfArgConstructors++;
|
||||
candidates.add(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
if (!noArgConstructorFound && numberOfArgConstructors > 1) {
|
||||
constructor = null;
|
||||
if(noArg != null) {
|
||||
return buildPreferredConstructor(noArg, type, entity);
|
||||
}
|
||||
|
||||
return constructor;
|
||||
return candidates.size() > 1 || candidates.isEmpty() ? null : buildPreferredConstructor(candidates.iterator().next(), type, entity);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -158,9 +151,9 @@ public interface PreferredConstructorDiscoverer<T, P extends PersistentProperty<
|
||||
Class<?> rawOwningType = type.getType();
|
||||
|
||||
return Arrays.stream(rawOwningType.getDeclaredConstructors()) //
|
||||
.filter(it -> !it.isSynthetic()) // Synthetic constructors should not be considered
|
||||
.filter(it -> it.isAnnotationPresent(PersistenceConstructor.class)) // Explicitly defined constructor trumps all
|
||||
.map(it -> buildPreferredConstructor(it, type, entity)) //
|
||||
.filter(it -> !it.getConstructor().isSynthetic()) // Synthetic constructors should not be considered
|
||||
.filter(PreferredConstructor::isExplicitlyAnnotated) // Explicitly defined constructor trumps all
|
||||
.findFirst() //
|
||||
.orElseGet(() -> {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user