Polishing of annotation model for object creators.
Move to @PersistenceCreator as canonical annotation to explicitly express constructors and methods to be used to create domain object instances from persistence operations. Removed @FactoryMethod as it's not needed anymore. @PersistenceConstructor is now deprecated. Renamed EntityCreatorMetadata(Support|Discoverer) to InstanceCreatorMetadata(Support|Discoverer) to avoid further manifestation of the notion of an entity in the metamodel as it's not used to only handle entities. Issue #2476.
This commit is contained in:
@@ -17,9 +17,9 @@ This means we need two fundamental steps:
|
||||
Spring Data automatically tries to detect a persistent entity's constructor to be used to materialize objects of that type.
|
||||
The resolution algorithm works as follows:
|
||||
|
||||
1. If there is a single static factory method annotated with `@FactoryMethod` then it is used.
|
||||
1. If there is a single static factory method annotated with `@PersistenceCreator` then it is used.
|
||||
2. If there is a single constructor, it is used.
|
||||
3. If there are multiple constructors and exactly one is annotated with `@PersistenceConstructor`, it is used.
|
||||
3. If there are multiple constructors and exactly one is annotated with `@PersistenceCreator`, it is used.
|
||||
4. If there's a no-argument constructor, it is used.
|
||||
Other constructors will be ignored.
|
||||
|
||||
@@ -205,9 +205,9 @@ Even if the intent is that the calculation should be preferred, it's important t
|
||||
<4> The `comment` property is mutable is populated by setting its field directly.
|
||||
<5> The `remarks` properties are mutable and populated by setting the `comment` field directly or by invoking the setter method for
|
||||
<6> The class exposes a factory method and a constructor for object creation.
|
||||
The core idea here is to use factory methods instead of additional constructors to avoid the need for constructor disambiguation through `@PersistenceConstructor`.
|
||||
The core idea here is to use factory methods instead of additional constructors to avoid the need for constructor disambiguation through `@PersistenceCreator`.
|
||||
Instead, defaulting of properties is handled within the factory method.
|
||||
If you want Spring Data to use the factory method for object instantiation, annotate it with `@FactoryMethod`.
|
||||
If you want Spring Data to use the factory method for object instantiation, annotate it with `@PersistenceCreator`.
|
||||
|
||||
[[mapping.general-recommendations]]
|
||||
== General recommendations
|
||||
@@ -217,7 +217,7 @@ Also, this avoids your domain objects to be littered with setter methods that al
|
||||
If you need those, prefer to make them package protected so that they can only be invoked by a limited amount of co-located types.
|
||||
Constructor-only materialization is up to 30% faster than properties population.
|
||||
* _Provide an all-args constructor_ -- Even if you cannot or don't want to model your entities as immutable values, there's still value in providing a constructor that takes all properties of the entity as arguments, including the mutable ones, as this allows the object mapping to skip the property population for optimal performance.
|
||||
* _Use factory methods instead of overloaded constructors to avoid ``@PersistenceConstructor``_ -- With an all-argument constructor needed for optimal performance, we usually want to expose more application use case specific constructors that omit things like auto-generated identifiers etc.
|
||||
* _Use factory methods instead of overloaded constructors to avoid ``@PersistenceCreator``_ -- With an all-argument constructor needed for optimal performance, we usually want to expose more application use case specific constructors that omit things like auto-generated identifiers etc.
|
||||
It's an established pattern to rather use static factory methods to expose these variants of the all-args constructor.
|
||||
* _Make sure you adhere to the constraints that allow the generated instantiator and property accessor classes to be used_ --
|
||||
* _For identifiers to be generated, still use a final field in combination with an all-arguments persistence constructor (preferred) or a `with…` method_ --
|
||||
@@ -307,14 +307,14 @@ data class Person(val id: String, val name: String)
|
||||
----
|
||||
====
|
||||
|
||||
The class above compiles to a typical class with an explicit constructor.We can customize this class by adding another constructor and annotate it with `@PersistenceConstructor` to indicate a constructor preference:
|
||||
The class above compiles to a typical class with an explicit constructor.We can customize this class by adding another constructor and annotate it with `@PersistenceCreator` to indicate a constructor preference:
|
||||
|
||||
====
|
||||
[source,kotlin]
|
||||
----
|
||||
data class Person(var id: String, val name: String) {
|
||||
|
||||
@PersistenceConstructor
|
||||
@PersistenceCreator
|
||||
constructor(id: String) : this(id, "unknown")
|
||||
}
|
||||
----
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to declare a {@code static} method as factory method for class instantiation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@EntityCreatorAnnotation
|
||||
public @interface FactoryMethod {
|
||||
}
|
||||
@@ -25,9 +25,11 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Drotbohm
|
||||
* @deprecated in favor of {@link PersistenceCreator} since 3.0, to be removed in 3.1
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE })
|
||||
@EntityCreatorAnnotation
|
||||
public @interface PersistenceConstructor {
|
||||
}
|
||||
@PersistenceCreator
|
||||
@Deprecated
|
||||
public @interface PersistenceConstructor {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2021 the original author or authors.
|
||||
* Copyright 2011-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,9 +24,9 @@ import java.lang.annotation.Target;
|
||||
* Marker annotation to declare a constructor or factory method annotation as factory/preferred constructor annotation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Drotbohm
|
||||
* @since 3.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.ANNOTATION_TYPE })
|
||||
public @interface EntityCreatorAnnotation {
|
||||
}
|
||||
@Target({ ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface PersistenceCreator {}
|
||||
@@ -26,7 +26,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class FactoryMethod<T, P extends PersistentProperty<P>> extends EntityCreatorMetadataSupport<T, P> {
|
||||
public final class FactoryMethod<T, P extends PersistentProperty<P>> extends InstanceCreatorMetadataSupport<T, P> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link FactoryMethod} from the given {@link Constructor} and {@link Parameter}s.
|
||||
@@ -49,5 +49,4 @@ public final class FactoryMethod<T, P extends PersistentProperty<P>> extends Ent
|
||||
public Method getFactoryMethod() {
|
||||
return (Method) getExecutable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
* Copyright 2021-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,12 +18,13 @@ package org.springframework.data.mapping;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Metadata describing a mechanism to create an entity instance.
|
||||
* Metadata describing a mechanism to create instances of persistent types.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Drotbohm
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface EntityCreatorMetadata<P extends PersistentProperty<P>> {
|
||||
public interface InstanceCreatorMetadata<P extends PersistentProperty<P>> {
|
||||
|
||||
/**
|
||||
* Check whether the given {@link PersistentProperty} is being used as creator parameter.
|
||||
@@ -28,22 +28,23 @@ import org.springframework.util.Assert;
|
||||
* persistent data to objects.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Drotbohm
|
||||
* @since 3.0
|
||||
*/
|
||||
class EntityCreatorMetadataSupport<T, P extends PersistentProperty<P>> implements EntityCreatorMetadata<P> {
|
||||
class InstanceCreatorMetadataSupport<T, P extends PersistentProperty<P>> implements InstanceCreatorMetadata<P> {
|
||||
|
||||
private final Executable executable;
|
||||
private final List<Parameter<Object, P>> parameters;
|
||||
private final Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link EntityCreatorMetadataSupport} from the given {@link Executable} and {@link Parameter}s.
|
||||
* Creates a new {@link InstanceCreatorMetadataSupport} from the given {@link Executable} and {@link Parameter}s.
|
||||
*
|
||||
* @param executable must not be {@literal null}.
|
||||
* @param parameters must not be {@literal null}.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public EntityCreatorMetadataSupport(Executable executable, Parameter<Object, P>... parameters) {
|
||||
public InstanceCreatorMetadataSupport(Executable executable, Parameter<Object, P>... parameters) {
|
||||
|
||||
Assert.notNull(executable, "Executable must not be null!");
|
||||
Assert.notNull(parameters, "Parameters must not be null!");
|
||||
@@ -72,7 +73,7 @@ class EntityCreatorMetadataSupport<T, P extends PersistentProperty<P>> implement
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is referenced in a creator argument of the
|
||||
* {@link PersistentEntity} backing this {@link EntityCreatorMetadataSupport}.
|
||||
* {@link PersistentEntity} backing this {@link InstanceCreatorMetadataSupport}.
|
||||
* <p>
|
||||
* Results of this call are cached and reused on the next invocation. Calling this method for a
|
||||
* {@link PersistentProperty} that was not yet added to its owning {@link PersistentEntity} will capture that state
|
||||
@@ -49,14 +49,14 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> extends It
|
||||
* indicates that the instantiation of the object of that persistent entity is done through either a customer
|
||||
* {@link org.springframework.data.mapping.model.EntityInstantiator} or handled by custom conversion
|
||||
* mechanisms entirely.
|
||||
* @deprecated since 3.0, use {@link #getEntityCreator()}.
|
||||
* @deprecated since 3.0, use {@link #getInstanceCreatorMetadata()}.
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
PreferredConstructor<T, P> getPersistenceConstructor();
|
||||
|
||||
/**
|
||||
* Returns the {@link EntityCreatorMetadata} to be used to instantiate objects of this {@link PersistentEntity}.
|
||||
* Returns the {@link InstanceCreatorMetadata} to be used to instantiate objects of this {@link PersistentEntity}.
|
||||
*
|
||||
* @return {@literal null} in case no suitable creation mechanism for automatic construction can be found. This
|
||||
* usually indicates that the instantiation of the object of that persistent entity is done through either a
|
||||
@@ -65,7 +65,7 @@ public interface PersistentEntity<T, P extends PersistentProperty<P>> extends It
|
||||
* @since 3.0
|
||||
*/
|
||||
@Nullable
|
||||
EntityCreatorMetadata<P> getEntityCreator();
|
||||
InstanceCreatorMetadata<P> getInstanceCreatorMetadata();
|
||||
|
||||
/**
|
||||
* Returns whether the given {@link PersistentProperty} is referred to by a constructor argument of the
|
||||
|
||||
@@ -35,7 +35,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @author Myeonghyeon Lee
|
||||
* @author Xeno Amess
|
||||
*/
|
||||
public final class PreferredConstructor<T, P extends PersistentProperty<P>> extends EntityCreatorMetadataSupport<T, P> {
|
||||
public final class PreferredConstructor<T, P extends PersistentProperty<P>> extends InstanceCreatorMetadataSupport<T, P> {
|
||||
|
||||
private final List<Parameter<Object, P>> parameters;
|
||||
|
||||
|
||||
@@ -17,16 +17,7 @@ package org.springframework.data.mapping.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
@@ -63,7 +54,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
|
||||
private static final String TYPE_MISMATCH = "Target bean of type %s is not of type of the persistent entity (%s)!";
|
||||
|
||||
private final @Nullable EntityCreatorMetadata<P> creator;
|
||||
private final @Nullable InstanceCreatorMetadata<P> creator;
|
||||
private final TypeInformation<T> information;
|
||||
private final List<P> properties;
|
||||
private final List<P> persistentPropertiesCache;
|
||||
@@ -109,7 +100,7 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
this.properties = new ArrayList<>();
|
||||
this.persistentPropertiesCache = new ArrayList<>();
|
||||
this.comparator = comparator;
|
||||
this.creator = EntityCreatorMetadataDiscoverer.discover(this);
|
||||
this.creator = InstanceCreatorMetadataDiscoverer.discover(this);
|
||||
this.associations = comparator == null ? new HashSet<>() : new TreeSet<>(new AssociationComparator<>(comparator));
|
||||
|
||||
this.propertyCache = new HashMap<>(16, 1f);
|
||||
@@ -129,12 +120,14 @@ public class BasicPersistentEntity<T, P extends PersistentProperty<P>> implement
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public PreferredConstructor<T, P> getPersistenceConstructor() {
|
||||
return creator instanceof PreferredConstructor ? (PreferredConstructor<T, P>) creator : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public EntityCreatorMetadata<P> getEntityCreator() {
|
||||
public InstanceCreatorMetadata<P> getInstanceCreatorMetadata() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.asm.ClassWriter;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
@@ -33,8 +32,8 @@ import org.springframework.asm.Type;
|
||||
import org.springframework.beans.BeanInstantiationException;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.core.NativeDetector;
|
||||
import org.springframework.data.mapping.EntityCreatorMetadata;
|
||||
import org.springframework.data.mapping.FactoryMethod;
|
||||
import org.springframework.data.mapping.InstanceCreatorMetadata;
|
||||
import org.springframework.data.mapping.Parameter;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -159,7 +158,7 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
*/
|
||||
protected EntityInstantiator doCreateEntityInstantiator(PersistentEntity<?, ?> entity) {
|
||||
return new EntityInstantiatorAdapter(
|
||||
createObjectInstantiator(entity, entity.getEntityCreator()));
|
||||
createObjectInstantiator(entity, entity.getInstanceCreatorMetadata()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,20 +186,20 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
return true;
|
||||
}
|
||||
|
||||
var entityCreator = entity.getEntityCreator();
|
||||
var creatorMetadata = entity.getInstanceCreatorMetadata();
|
||||
|
||||
if (entityCreator == null) {
|
||||
if (creatorMetadata == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entityCreator instanceof PreferredConstructor<?, ?> persistenceConstructor) {
|
||||
if (creatorMetadata instanceof PreferredConstructor<?, ?> persistenceConstructor) {
|
||||
|
||||
if (Modifier.isPrivate(persistenceConstructor.getConstructor().getModifiers())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (entityCreator instanceof FactoryMethod<?, ?> factoryMethod) {
|
||||
if (creatorMetadata instanceof FactoryMethod<?, ?> factoryMethod) {
|
||||
|
||||
if (Modifier.isPrivate(factoryMethod.getFactoryMethod().getModifiers())) {
|
||||
return true;
|
||||
@@ -227,7 +226,7 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
|
||||
/**
|
||||
* Creates a dynamically generated {@link ObjectInstantiator} for the given {@link PersistentEntity} and
|
||||
* {@link EntityCreatorMetadata}. There will always be exactly one {@link ObjectInstantiator} instance per
|
||||
* {@link InstanceCreatorMetadata}. There will always be exactly one {@link ObjectInstantiator} instance per
|
||||
* {@link PersistentEntity}.
|
||||
*
|
||||
* @param entity
|
||||
@@ -235,7 +234,7 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
* @return
|
||||
*/
|
||||
ObjectInstantiator createObjectInstantiator(PersistentEntity<?, ?> entity,
|
||||
@Nullable EntityCreatorMetadata<?> constructor) {
|
||||
@Nullable InstanceCreatorMetadata<?> constructor) {
|
||||
|
||||
try {
|
||||
return (ObjectInstantiator) this.generator.generateCustomInstantiatorClass(entity, constructor).newInstance();
|
||||
@@ -269,7 +268,7 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
var params = extractInvocationArguments(entity.getEntityCreator(), provider);
|
||||
var params = extractInvocationArguments(entity.getInstanceCreatorMetadata(), provider);
|
||||
|
||||
try {
|
||||
return (T) instantiator.newInstance(params);
|
||||
@@ -287,7 +286,7 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
* @return
|
||||
*/
|
||||
static <P extends PersistentProperty<P>, T> Object[] extractInvocationArguments(
|
||||
@Nullable EntityCreatorMetadata<P> constructor, ParameterValueProvider<P> provider) {
|
||||
@Nullable InstanceCreatorMetadata<P> constructor, ParameterValueProvider<P> provider) {
|
||||
|
||||
if (constructor == null || !constructor.hasParameters()) {
|
||||
return allocateArguments(0);
|
||||
@@ -336,7 +335,7 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
var params = extractInvocationArguments(entity.getEntityCreator(), provider);
|
||||
var params = extractInvocationArguments(entity.getInstanceCreatorMetadata(), provider);
|
||||
|
||||
throw new MappingInstantiationException(entity, Arrays.asList(params),
|
||||
new BeanInstantiationException(typeToCreate, "Class is abstract"));
|
||||
@@ -400,7 +399,7 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
* @return
|
||||
*/
|
||||
public Class<?> generateCustomInstantiatorClass(PersistentEntity<?, ?> entity,
|
||||
@Nullable EntityCreatorMetadata<?> constructor) {
|
||||
@Nullable InstanceCreatorMetadata<?> constructor) {
|
||||
|
||||
var className = generateClassName(entity);
|
||||
var type = entity.getType();
|
||||
@@ -441,7 +440,7 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
* @return
|
||||
*/
|
||||
public byte[] generateBytecode(String internalClassName, PersistentEntity<?, ?> entity,
|
||||
@Nullable EntityCreatorMetadata<?> entityCreator) {
|
||||
@Nullable InstanceCreatorMetadata<?> entityCreator) {
|
||||
|
||||
var cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
|
||||
@@ -476,7 +475,7 @@ class ClassGeneratingEntityInstantiator implements EntityInstantiator {
|
||||
* @param entityCreator
|
||||
*/
|
||||
private void visitCreateMethod(ClassWriter cw, PersistentEntity<?, ?> entity,
|
||||
@Nullable EntityCreatorMetadata<?> entityCreator) {
|
||||
@Nullable InstanceCreatorMetadata<?> entityCreator) {
|
||||
|
||||
var entityTypeResourcePath = Type.getInternalName(entity.getType());
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ import java.util.List;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.data.annotation.EntityCreatorAnnotation;
|
||||
import org.springframework.data.mapping.EntityCreatorMetadata;
|
||||
import org.springframework.data.annotation.PersistenceCreator;
|
||||
import org.springframework.data.mapping.InstanceCreatorMetadata;
|
||||
import org.springframework.data.mapping.FactoryMethod;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.Parameter;
|
||||
@@ -40,7 +40,7 @@ import org.springframework.lang.Nullable;
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
*/
|
||||
class EntityCreatorMetadataDiscoverer {
|
||||
class InstanceCreatorMetadataDiscoverer {
|
||||
|
||||
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
|
||||
|
||||
@@ -53,13 +53,13 @@ class EntityCreatorMetadataDiscoverer {
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public static <T, P extends PersistentProperty<P>> EntityCreatorMetadata<P> discover(PersistentEntity<T, P> entity) {
|
||||
public static <T, P extends PersistentProperty<P>> InstanceCreatorMetadata<P> discover(PersistentEntity<T, P> entity) {
|
||||
|
||||
var declaredConstructors = entity.getType().getDeclaredConstructors();
|
||||
var declaredMethods = entity.getType().getDeclaredMethods();
|
||||
|
||||
var hasAnnotatedFactoryMethod = findAnnotation(EntityCreatorAnnotation.class, declaredMethods);
|
||||
var hasAnnotatedConstructor = findAnnotation(EntityCreatorAnnotation.class, declaredConstructors);
|
||||
var hasAnnotatedFactoryMethod = findAnnotation(PersistenceCreator.class, declaredMethods);
|
||||
var hasAnnotatedConstructor = findAnnotation(PersistenceCreator.class, declaredConstructors);
|
||||
|
||||
if (hasAnnotatedConstructor && hasAnnotatedFactoryMethod) {
|
||||
throw new MappingException(
|
||||
@@ -92,7 +92,7 @@ class EntityCreatorMetadataDiscoverer {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (findAnnotation(EntityCreatorAnnotation.class, method)) {
|
||||
if (findAnnotation(PersistenceCreator.class, method)) {
|
||||
candidates.add(method);
|
||||
}
|
||||
}
|
||||
@@ -124,11 +124,11 @@ class EntityCreatorMetadataDiscoverer {
|
||||
|
||||
private static void validateMethod(Method method) {
|
||||
|
||||
if (MergedAnnotations.from(method).isPresent(EntityCreatorAnnotation.class)) {
|
||||
if (MergedAnnotations.from(method).isPresent(PersistenceCreator.class)) {
|
||||
|
||||
if (!Modifier.isStatic(method.getModifiers())) {
|
||||
throw new MappingException(
|
||||
"@Factory can only be used on static methods. Offending method: %s".formatted(method));
|
||||
"@PersistenceCreator can only be used on static methods. Offending method: %s".formatted(method));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ public class InstantiationAwarePropertyAccessor<T> implements PersistentProperty
|
||||
return;
|
||||
}
|
||||
|
||||
var creator = owner.getEntityCreator();
|
||||
var creator = owner.getInstanceCreatorMetadata();
|
||||
|
||||
if (creator == null) {
|
||||
throw new IllegalStateException(String.format(NO_SETTER_OR_CONSTRUCTOR, property.getName(), owner.getType()));
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.springframework.data.mapping.EntityCreatorMetadata;
|
||||
import org.springframework.data.mapping.InstanceCreatorMetadata;
|
||||
import org.springframework.data.mapping.Parameter;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -46,7 +46,7 @@ class KotlinClassGeneratingEntityInstantiator extends ClassGeneratingEntityInsta
|
||||
@Override
|
||||
protected EntityInstantiator doCreateEntityInstantiator(PersistentEntity<?, ?> entity) {
|
||||
|
||||
var creator = entity.getEntityCreator();
|
||||
var creator = entity.getInstanceCreatorMetadata();
|
||||
|
||||
if (KotlinReflectionUtils.isSupportedKotlinClass(entity.getType())
|
||||
&& creator instanceof PreferredConstructor<?, ?> constructor) {
|
||||
@@ -80,9 +80,9 @@ class KotlinClassGeneratingEntityInstantiator extends ClassGeneratingEntityInsta
|
||||
DefaultingKotlinConstructorResolver(PersistentEntity<?, ?> entity) {
|
||||
|
||||
var hit = resolveDefaultConstructor(entity);
|
||||
var creator = entity.getEntityCreator();
|
||||
var creator = entity.getInstanceCreatorMetadata();
|
||||
|
||||
if (hit != null && creator instanceof PreferredConstructor<?, ?> persistenceConstructor) {
|
||||
if ((hit != null) && creator instanceof PreferredConstructor<?, ?> persistenceConstructor) {
|
||||
this.defaultConstructor = new PreferredConstructor<>(hit,
|
||||
persistenceConstructor.getParameters().toArray(new Parameter[0]));
|
||||
} else {
|
||||
@@ -93,7 +93,7 @@ class KotlinClassGeneratingEntityInstantiator extends ClassGeneratingEntityInsta
|
||||
@Nullable
|
||||
private static Constructor<?> resolveDefaultConstructor(PersistentEntity<?, ?> entity) {
|
||||
|
||||
if (!(entity.getEntityCreator()instanceof PreferredConstructor<?, ?> persistenceConstructor)) {
|
||||
if (!(entity.getInstanceCreatorMetadata() instanceof PreferredConstructor<?, ?> persistenceConstructor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ class KotlinClassGeneratingEntityInstantiator extends ClassGeneratingEntityInsta
|
||||
var syntheticParameters = KotlinDefaultMask.getMaskCount(constructor.getParameterCount())
|
||||
+ /* DefaultConstructorMarker */ 1;
|
||||
|
||||
if (constructor.getParameterCount() + syntheticParameters != candidate.getParameterCount()) {
|
||||
if ((constructor.getParameterCount() + syntheticParameters) != candidate.getParameterCount()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ class KotlinClassGeneratingEntityInstantiator extends ClassGeneratingEntityInsta
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
var params = extractInvocationArguments(entity.getEntityCreator(), provider);
|
||||
var params = extractInvocationArguments(entity.getInstanceCreatorMetadata(), provider);
|
||||
|
||||
try {
|
||||
return (T) instantiator.newInstance(params);
|
||||
@@ -201,7 +201,7 @@ class KotlinClassGeneratingEntityInstantiator extends ClassGeneratingEntityInsta
|
||||
}
|
||||
|
||||
private <P extends PersistentProperty<P>, T> Object[] extractInvocationArguments(
|
||||
@Nullable EntityCreatorMetadata<P> entityCreator, ParameterValueProvider<P> provider) {
|
||||
@Nullable InstanceCreatorMetadata<P> entityCreator, ParameterValueProvider<P> provider) {
|
||||
|
||||
if (entityCreator == null) {
|
||||
throw new IllegalArgumentException("EntityCreator must not be null!");
|
||||
@@ -227,7 +227,7 @@ class KotlinClassGeneratingEntityInstantiator extends ClassGeneratingEntityInsta
|
||||
var parameter = parameters.get(index);
|
||||
var type = parameter.getType().getType();
|
||||
|
||||
if (it.isOptional() && params[index] == null) {
|
||||
if (it.isOptional() && (params[index] == null)) {
|
||||
if (type.isPrimitive()) {
|
||||
|
||||
// apply primitive defaulting to prevent NPE on primitive downcast
|
||||
|
||||
@@ -22,8 +22,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.mapping.EntityCreatorMetadata;
|
||||
import org.springframework.data.mapping.FactoryMethod;
|
||||
import org.springframework.data.mapping.InstanceCreatorMetadata;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.util.KotlinReflectionUtils;
|
||||
@@ -44,7 +44,7 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
private static final String TEXT_TEMPLATE = "Failed to instantiate %s using constructor %s with arguments %s";
|
||||
|
||||
private final Class<?> entityType;
|
||||
private final EntityCreatorMetadata<?> entityCreator;
|
||||
private final InstanceCreatorMetadata<?> entityCreator;
|
||||
private final List<Object> constructorArguments;
|
||||
|
||||
/**
|
||||
@@ -75,7 +75,7 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
super(buildExceptionMessage(entity, arguments, message), cause);
|
||||
|
||||
this.entityType = entity.map(PersistentEntity::getType).orElse(null);
|
||||
this.entityCreator = entity.map(PersistentEntity::getEntityCreator).orElse(null);
|
||||
this.entityCreator = entity.map(PersistentEntity::getInstanceCreatorMetadata).orElse(null);
|
||||
this.constructorArguments = arguments;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
|
||||
return entity.map(it -> {
|
||||
|
||||
Optional<? extends EntityCreatorMetadata<?>> constructor = Optional.ofNullable(it.getEntityCreator());
|
||||
Optional<? extends InstanceCreatorMetadata<?>> constructor = Optional.ofNullable(it.getInstanceCreatorMetadata());
|
||||
List<String> toStringArgs = new ArrayList<>(arguments.size());
|
||||
|
||||
for (var o : arguments) {
|
||||
@@ -98,7 +98,7 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
}).orElse(defaultMessage);
|
||||
}
|
||||
|
||||
private static String toString(EntityCreatorMetadata<?> creator) {
|
||||
private static String toString(InstanceCreatorMetadata<?> creator) {
|
||||
|
||||
if (creator instanceof PreferredConstructor<?, ?> c) {
|
||||
return toString(c);
|
||||
@@ -170,7 +170,7 @@ public class MappingInstantiationException extends RuntimeException {
|
||||
* @return the entity creator
|
||||
* @since 3.0
|
||||
*/
|
||||
public Optional<EntityCreatorMetadata<?>> getEntityCreator() {
|
||||
public Optional<InstanceCreatorMetadata<?>> getEntityCreator() {
|
||||
return Optional.ofNullable(entityCreator);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,10 @@ public class PersistentEntityParameterValueProvider<P extends PersistentProperty
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getParameterValue(Parameter<T, P> parameter) {
|
||||
|
||||
var creator = entity.getEntityCreator();
|
||||
var creator = entity.getInstanceCreatorMetadata();
|
||||
|
||||
if (creator.isParentParameter(parameter)) {
|
||||
return (T) parent;
|
||||
if (creator != null && creator.isParentParameter(parameter)) {
|
||||
return (T) parent;
|
||||
}
|
||||
|
||||
var name = parameter.getName();
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.List;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.annotation.EntityCreatorAnnotation;
|
||||
import org.springframework.data.annotation.PersistenceCreator;
|
||||
import org.springframework.data.mapping.Parameter;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -111,7 +111,7 @@ public interface PreferredConstructorDiscoverer<T, P extends PersistentProperty<
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AnnotationUtils.findAnnotation(candidate, EntityCreatorAnnotation.class) != null) {
|
||||
if (AnnotationUtils.findAnnotation(candidate, PersistenceCreator.class) != null) {
|
||||
return buildPreferredConstructor(candidate, type, entity);
|
||||
}
|
||||
|
||||
@@ -145,11 +145,8 @@ public interface PreferredConstructorDiscoverer<T, P extends PersistentProperty<
|
||||
|
||||
return Arrays.stream(rawOwningType.getDeclaredConstructors()) //
|
||||
.filter(it -> !it.isSynthetic()) // Synthetic constructors should not be considered
|
||||
.filter(it -> AnnotationUtils.findAnnotation(it, EntityCreatorAnnotation.class) != null) // Explicitly
|
||||
// defined
|
||||
// constructor
|
||||
// trumps
|
||||
// all
|
||||
// Explicitly defined creator trumps all
|
||||
.filter(it -> AnnotationUtils.findAnnotation(it, PersistenceCreator.class) != null)
|
||||
.map(it -> buildPreferredConstructor(it, type, entity)) //
|
||||
.findFirst() //
|
||||
.orElseGet(() -> {
|
||||
|
||||
@@ -46,7 +46,7 @@ enum ReflectionEntityInstantiator implements EntityInstantiator {
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
var creator = entity.getEntityCreator();
|
||||
var creator = entity.getInstanceCreatorMetadata();
|
||||
|
||||
if (creator == null) {
|
||||
return instantiateClass(entity);
|
||||
@@ -59,7 +59,7 @@ enum ReflectionEntityInstantiator implements EntityInstantiator {
|
||||
params[i++] = provider.getParameterValue(parameter);
|
||||
}
|
||||
|
||||
if (creator instanceof FactoryMethod method) {
|
||||
if (creator instanceof FactoryMethod<?, ?> method) {
|
||||
|
||||
try {
|
||||
var t = (T) ReflectionUtils.invokeMethod(method.getFactoryMethod(), null, params);
|
||||
@@ -80,6 +80,7 @@ enum ReflectionEntityInstantiator implements EntityInstantiator {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T instantiateClass(
|
||||
E entity) {
|
||||
|
||||
|
||||
@@ -32,8 +32,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import org.springframework.data.annotation.FactoryMethod;
|
||||
import org.springframework.data.annotation.PersistenceCreator;
|
||||
import org.springframework.data.classloadersupport.HidingClassLoader;
|
||||
import org.springframework.data.mapping.Parameter;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
@@ -84,7 +83,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
PreferredConstructor<Foo, P> constructor = PreferredConstructorDiscoverer.discover(Foo.class);
|
||||
|
||||
doReturn(Foo.class).when(entity).getType();
|
||||
doReturn(constructor).when(entity).getEntityCreator();
|
||||
doReturn(constructor).when(entity).getInstanceCreatorMetadata();
|
||||
|
||||
assertThat(instance.createInstance(entity, provider)).isInstanceOf(Foo.class);
|
||||
|
||||
@@ -106,7 +105,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
void createsInnerClassInstanceCorrectly() {
|
||||
|
||||
var entity = new BasicPersistentEntity<Inner, P>(from(Inner.class));
|
||||
assertThat(entity.getEntityCreator()).satisfies(constructor -> {
|
||||
assertThat(entity.getInstanceCreatorMetadata()).satisfies(constructor -> {
|
||||
|
||||
var parameter = constructor.getParameters().iterator().next();
|
||||
|
||||
@@ -226,7 +225,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
|
||||
doReturn(ObjCtorDefault.class).when(entity).getType();
|
||||
doReturn(PreferredConstructorDiscoverer.discover(ObjCtorDefault.class))//
|
||||
.when(entity).getEntityCreator();
|
||||
.when(entity).getInstanceCreatorMetadata();
|
||||
|
||||
IntStream.range(0, 2)
|
||||
.forEach(i -> assertThat(this.instance.createInstance(entity, provider)).isInstanceOf(ObjCtorDefault.class));
|
||||
@@ -237,7 +236,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
|
||||
doReturn(ObjCtorNoArgs.class).when(entity).getType();
|
||||
doReturn(PreferredConstructorDiscoverer.discover(ObjCtorNoArgs.class))//
|
||||
.when(entity).getEntityCreator();
|
||||
.when(entity).getInstanceCreatorMetadata();
|
||||
|
||||
IntStream.range(0, 2).forEach(i -> {
|
||||
|
||||
@@ -256,7 +255,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
|
||||
doReturn(ObjCtor1ParamString.class).when(entity).getType();
|
||||
doReturn(PreferredConstructorDiscoverer.discover(ObjCtor1ParamString.class))//
|
||||
.when(entity).getEntityCreator();
|
||||
.when(entity).getInstanceCreatorMetadata();
|
||||
doReturn("FOO").when(provider).getParameterValue(any());
|
||||
|
||||
IntStream.range(0, 2).forEach(i -> {
|
||||
@@ -274,7 +273,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
|
||||
doReturn(ObjCtor2ParamStringString.class).when(entity).getType();
|
||||
doReturn(PreferredConstructorDiscoverer.discover(ObjCtor2ParamStringString.class))//
|
||||
.when(entity).getEntityCreator();
|
||||
.when(entity).getInstanceCreatorMetadata();
|
||||
|
||||
IntStream.range(0, 2).forEach(i -> {
|
||||
|
||||
@@ -294,7 +293,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
|
||||
doReturn(ObjectCtor1ParamInt.class).when(entity).getType();
|
||||
doReturn(PreferredConstructorDiscoverer.discover(ObjectCtor1ParamInt.class))//
|
||||
.when(entity).getEntityCreator();
|
||||
.when(entity).getInstanceCreatorMetadata();
|
||||
|
||||
IntStream.range(0, 2).forEach(i -> {
|
||||
|
||||
@@ -312,7 +311,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
|
||||
doReturn(ObjectCtor1ParamInt.class).when(entity).getType();
|
||||
doReturn(PreferredConstructorDiscoverer.discover(ObjectCtor1ParamInt.class))//
|
||||
.when(entity).getEntityCreator();
|
||||
.when(entity).getInstanceCreatorMetadata();
|
||||
|
||||
assertThatThrownBy(() -> this.instance.createInstance(entity, provider)) //
|
||||
.hasCauseInstanceOf(IllegalArgumentException.class);
|
||||
@@ -324,7 +323,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
|
||||
doReturn(ObjectCtor7ParamsString5IntsString.class).when(entity).getType();
|
||||
doReturn(PreferredConstructorDiscoverer.discover(ObjectCtor7ParamsString5IntsString.class))//
|
||||
.when(entity).getEntityCreator();
|
||||
.when(entity).getInstanceCreatorMetadata();
|
||||
|
||||
IntStream.range(0, 2).forEach(i -> {
|
||||
|
||||
@@ -444,7 +443,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
|
||||
doReturn(type).when(entity).getType();
|
||||
doReturn(PreferredConstructorDiscoverer.discover(type))//
|
||||
.when(entity).getEntityCreator();
|
||||
.when(entity).getInstanceCreatorMetadata();
|
||||
}
|
||||
|
||||
static class Foo {
|
||||
@@ -472,7 +471,7 @@ class ClassGeneratingEntityInstantiatorUnitTests<P extends PersistentProperty<P>
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@FactoryMethod
|
||||
@PersistenceCreator
|
||||
public static WithFactoryMethod create(Long id, String name) {
|
||||
return new WithFactoryMethod(id, "Hello " + name);
|
||||
}
|
||||
|
||||
@@ -18,14 +18,13 @@ package org.springframework.data.mapping.model;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.data.annotation.FactoryMethod;
|
||||
import org.springframework.data.annotation.PersistenceCreator;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link EntityCreatorMetadataDiscoverer}.
|
||||
* Unit tests for {@link InstanceCreatorMetadataDiscoverer}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@@ -35,7 +34,7 @@ class EntityCreatorMetadataDiscovererUnitTests {
|
||||
void shouldDiscoverAnnotatedFactoryMethod() {
|
||||
|
||||
var entity = new BasicPersistentEntity<>(ClassTypeInformation.from(FactoryMethodsPerson.class));
|
||||
var creator = EntityCreatorMetadataDiscoverer.discover(entity);
|
||||
var creator = InstanceCreatorMetadataDiscoverer.discover(entity);
|
||||
|
||||
assertThat(creator).isInstanceOf(org.springframework.data.mapping.FactoryMethod.class);
|
||||
assertThat(((org.springframework.data.mapping.FactoryMethod<?, ?>) creator).getFactoryMethod().getParameterCount())
|
||||
@@ -46,7 +45,7 @@ class EntityCreatorMetadataDiscovererUnitTests {
|
||||
void shouldDiscoverAnnotatedConstructor() {
|
||||
|
||||
var entity = new BasicPersistentEntity<>(ClassTypeInformation.from(ConstructorPerson.class));
|
||||
var creator = EntityCreatorMetadataDiscoverer.discover(entity);
|
||||
var creator = InstanceCreatorMetadataDiscoverer.discover(entity);
|
||||
|
||||
assertThat(creator).isInstanceOf(PreferredConstructor.class);
|
||||
}
|
||||
@@ -55,7 +54,7 @@ class EntityCreatorMetadataDiscovererUnitTests {
|
||||
void shouldDiscoverDefaultConstructor() {
|
||||
|
||||
var entity = new BasicPersistentEntity<>(ClassTypeInformation.from(Person.class));
|
||||
var creator = EntityCreatorMetadataDiscoverer.discover(entity);
|
||||
var creator = InstanceCreatorMetadataDiscoverer.discover(entity);
|
||||
|
||||
assertThat(creator).isInstanceOf(PreferredConstructor.class);
|
||||
}
|
||||
@@ -79,7 +78,7 @@ class EntityCreatorMetadataDiscovererUnitTests {
|
||||
|
||||
static class NonStaticFactoryMethod {
|
||||
|
||||
@FactoryMethod
|
||||
@PersistenceCreator
|
||||
public ConstructorPerson of(String firstname, String lastname) {
|
||||
return new ConstructorPerson(firstname, lastname);
|
||||
}
|
||||
@@ -99,7 +98,7 @@ class EntityCreatorMetadataDiscovererUnitTests {
|
||||
return new FactoryMethodsPerson(firstname, "unknown");
|
||||
}
|
||||
|
||||
@FactoryMethod
|
||||
@PersistenceCreator
|
||||
public static FactoryMethodsPerson of(String firstname, String lastname) {
|
||||
return new FactoryMethodsPerson(firstname, lastname);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ package org.springframework.data.mapping.model;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.data.annotation.FactoryMethod;
|
||||
import org.springframework.data.annotation.PersistenceCreator;
|
||||
import org.springframework.data.mapping.Parameter;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
|
||||
@@ -67,7 +66,7 @@ class FactoryMethodUnitTests {
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
@FactoryMethod
|
||||
@PersistenceCreator
|
||||
public static FactoryPerson of(String firstname, String lastname) {
|
||||
return new FactoryPerson(firstname, "Mr. " + lastname);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -55,7 +54,7 @@ class PersistentEntityParameterValueProviderUnitTests<P extends PersistentProper
|
||||
}
|
||||
};
|
||||
|
||||
assertThat(entity.getEntityCreator()).satisfies(constructor -> {
|
||||
assertThat(entity.getInstanceCreatorMetadata()).satisfies(constructor -> {
|
||||
|
||||
var iterator = constructor.getParameters().iterator();
|
||||
ParameterValueProvider<P> provider = new PersistentEntityParameterValueProvider<>(entity, propertyValueProvider,
|
||||
@@ -74,7 +73,7 @@ class PersistentEntityParameterValueProviderUnitTests<P extends PersistentProper
|
||||
ParameterValueProvider<P> provider = new PersistentEntityParameterValueProvider<>(entity, propertyValueProvider,
|
||||
Optional.of(property));
|
||||
|
||||
assertThat(entity.getEntityCreator())
|
||||
assertThat(entity.getInstanceCreatorMetadata())
|
||||
.satisfies(constructor -> assertThatExceptionOfType(MappingException.class)//
|
||||
.isThrownBy(() -> provider.getParameterValue(constructor.getParameters().iterator().next()))//
|
||||
.withMessageContaining("bar")//
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.data.mapping.Parameter;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -69,7 +68,7 @@ class ReflectionEntityInstantiatorUnitTests<P extends PersistentProperty<P>> {
|
||||
|
||||
PreferredConstructor<Foo, P> constructor = PreferredConstructorDiscoverer.discover(Foo.class);
|
||||
|
||||
doReturn(constructor).when(entity).getEntityCreator();
|
||||
doReturn(constructor).when(entity).getInstanceCreatorMetadata();
|
||||
|
||||
var instance = INSTANCE.createInstance(entity, provider);
|
||||
|
||||
@@ -92,7 +91,7 @@ class ReflectionEntityInstantiatorUnitTests<P extends PersistentProperty<P>> {
|
||||
void createsInnerClassInstanceCorrectly() {
|
||||
|
||||
var entity = new BasicPersistentEntity<Inner, P>(from(Inner.class));
|
||||
assertThat(entity.getEntityCreator()).satisfies(it -> {
|
||||
assertThat(entity.getInstanceCreatorMetadata()).satisfies(it -> {
|
||||
|
||||
var parameter = it.getParameters().iterator().next();
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests {
|
||||
)
|
||||
|
||||
every { provider.getParameterValue<String>(any()) }.returnsMany("Walter", "White")
|
||||
every { entity.entityCreator } returns constructor
|
||||
every { entity.instanceCreatorMetadata } returns constructor
|
||||
every { entity.type } returns constructor.constructor.declaringClass
|
||||
every { entity.typeInformation } returns mockk()
|
||||
|
||||
@@ -73,7 +73,7 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests {
|
||||
null, "Walter", null, "Junior", null
|
||||
)
|
||||
|
||||
every { entity.entityCreator } returns constructor
|
||||
every { entity.instanceCreatorMetadata } returns constructor
|
||||
every { entity.type } returns constructor.constructor.declaringClass
|
||||
every { entity.typeInformation } returns mockk()
|
||||
|
||||
@@ -97,7 +97,7 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests {
|
||||
)
|
||||
|
||||
every { provider.getParameterValue<Boolean>(any()) } returns null
|
||||
every { entity.entityCreator } returns constructor
|
||||
every { entity.instanceCreatorMetadata } returns constructor
|
||||
every { entity.type } returns constructor.constructor.declaringClass
|
||||
every { entity.typeInformation } returns mockk()
|
||||
|
||||
@@ -130,7 +130,7 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests {
|
||||
every { provider.getParameterValue<Double>(any()) } returns null
|
||||
every { provider.getParameterValue<Char>(any()) } returns null
|
||||
every { provider.getParameterValue<Boolean>(any()) } returns null
|
||||
every { entity.entityCreator } returns constructor
|
||||
every { entity.instanceCreatorMetadata } returns constructor
|
||||
every { entity.type } returns constructor.constructor.declaringClass
|
||||
every { entity.typeInformation } returns mockk()
|
||||
|
||||
@@ -156,7 +156,7 @@ class KotlinClassGeneratingEntityInstantiatorUnitTests {
|
||||
)
|
||||
|
||||
every { provider.getParameterValue<String>(any()) } returns "Walter"
|
||||
every { entity.entityCreator } returns constructor
|
||||
every { entity.instanceCreatorMetadata } returns constructor
|
||||
every { entity.type } returns constructor.constructor.declaringClass
|
||||
every { entity.typeInformation } returns mockk()
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class ReflectionEntityInstantiatorDataClassUnitTests {
|
||||
)
|
||||
|
||||
every { provider.getParameterValue<String>(any()) }.returnsMany("Walter", "White")
|
||||
every { entity.entityCreator } returns constructor
|
||||
every { entity.instanceCreatorMetadata } returns constructor
|
||||
|
||||
val instance: Contact =
|
||||
ReflectionEntityInstantiator.INSTANCE.createInstance(entity, provider)
|
||||
@@ -63,7 +63,7 @@ class ReflectionEntityInstantiatorDataClassUnitTests {
|
||||
)
|
||||
|
||||
every { provider.getParameterValue<String>(any()) }.returnsMany("Walter", null)
|
||||
every { entity.entityCreator } returns constructor
|
||||
every { entity.instanceCreatorMetadata } returns constructor
|
||||
|
||||
val instance: ContactWithDefaulting =
|
||||
ReflectionEntityInstantiator.INSTANCE.createInstance(entity, provider)
|
||||
|
||||
Reference in New Issue
Block a user