DATACMNS-1126 - Polishing.
Moved PreferredConstructorDiscoverers into PreferredConstructorDiscoverer to hide more API. Renamed ClassGeneratingKotlinEntityInstantiator to KotlinClassGeneratingEntityInstantiator. Use org.springframework.util.Assert instead of com.mysema.commons.lang.Assert. Original pull request: #233.
This commit is contained in:
committed by
Mark Paluch
parent
b05c4e74fb
commit
22b6971318
@@ -57,7 +57,7 @@ public class EntityInstantiators {
|
||||
* @param customInstantiators must not be {@literal null}.
|
||||
*/
|
||||
public EntityInstantiators(Map<Class<?>, EntityInstantiator> customInstantiators) {
|
||||
this(new ClassGeneratingKotlinEntityInstantiator(), customInstantiators);
|
||||
this(new KotlinClassGeneratingEntityInstantiator(), customInstantiators);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,16 +30,16 @@ import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Kotlin-specific extension to {@link ClassGeneratingEntityInstantiator} that adapts Kotlin constructors with
|
||||
* defaulting.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Gierke
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ClassGeneratingKotlinEntityInstantiator extends ClassGeneratingEntityInstantiator {
|
||||
public class KotlinClassGeneratingEntityInstantiator extends ClassGeneratingEntityInstantiator {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -48,14 +48,18 @@ public class ClassGeneratingKotlinEntityInstantiator extends ClassGeneratingEnti
|
||||
@Override
|
||||
protected EntityInstantiator doCreateEntityInstantiator(PersistentEntity<?, ?> entity) {
|
||||
|
||||
if (ReflectionUtils.isKotlinClass(entity.getType()) && entity.getPersistenceConstructor() != null) {
|
||||
PreferredConstructor<?, ?> constructor = entity.getPersistenceConstructor();
|
||||
|
||||
if (ReflectionUtils.isKotlinClass(entity.getType()) && constructor != null) {
|
||||
|
||||
PreferredConstructor<?, ?> defaultConstructor = new DefaultingKotlinConstructorResolver(entity)
|
||||
.getDefaultConstructor();
|
||||
|
||||
if (defaultConstructor != null) {
|
||||
return new DefaultingKotlinClassInstantiatorAdapter(createObjectInstantiator(entity, defaultConstructor),
|
||||
entity.getPersistenceConstructor());
|
||||
|
||||
ObjectInstantiator instantiator = createObjectInstantiator(entity, defaultConstructor);
|
||||
|
||||
return new DefaultingKotlinClassInstantiatorAdapter(instantiator, constructor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +75,7 @@ public class ClassGeneratingKotlinEntityInstantiator extends ClassGeneratingEnti
|
||||
*/
|
||||
static class DefaultingKotlinConstructorResolver {
|
||||
|
||||
@Nullable private final PreferredConstructor<?, ?> defaultConstructor;
|
||||
private final @Nullable PreferredConstructor<?, ?> defaultConstructor;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
DefaultingKotlinConstructorResolver(PersistentEntity<?, ?> entity) {
|
||||
@@ -90,12 +94,14 @@ public class ClassGeneratingKotlinEntityInstantiator extends ClassGeneratingEnti
|
||||
@Nullable
|
||||
private static Constructor<?> resolveDefaultConstructor(PersistentEntity<?, ?> entity) {
|
||||
|
||||
if (entity.getPersistenceConstructor() == null) {
|
||||
PreferredConstructor<?, ?> persistenceConstructor = entity.getPersistenceConstructor();
|
||||
|
||||
if (persistenceConstructor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Constructor<?> hit = null;
|
||||
Constructor<?> constructor = entity.getPersistenceConstructor().getConstructor();
|
||||
Constructor<?> constructor = persistenceConstructor.getConstructor();
|
||||
|
||||
for (Constructor<?> candidate : entity.getType().getDeclaredConstructors()) {
|
||||
|
||||
@@ -192,7 +198,10 @@ public class ClassGeneratingKotlinEntityInstantiator extends ClassGeneratingEnti
|
||||
ParameterValueProvider<P> provider) {
|
||||
|
||||
PreferredConstructor<? extends T, P> preferredConstructor = entity.getPersistenceConstructor();
|
||||
Assert.notNull(preferredConstructor, "PreferredConstructor must not be null!");
|
||||
|
||||
if (preferredConstructor == null) {
|
||||
throw new IllegalArgumentException("PreferredConstructor must not be null!");
|
||||
}
|
||||
|
||||
int[] defaulting = new int[(synthetic.getParameterCount() / 32) + 1];
|
||||
|
||||
|
||||
@@ -15,13 +15,27 @@
|
||||
*/
|
||||
package org.springframework.data.mapping.model;
|
||||
|
||||
import kotlin.jvm.JvmClassMappingKt;
|
||||
import kotlin.reflect.KFunction;
|
||||
import kotlin.reflect.full.KClasses;
|
||||
import kotlin.reflect.jvm.ReflectJvmMapping;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import com.mysema.commons.lang.Assert;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper class to find a {@link PreferredConstructor}.
|
||||
@@ -44,7 +58,8 @@ public interface PreferredConstructorDiscoverer<T, P extends PersistentProperty<
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
|
||||
return PreferredConstructorDiscoverers.findDiscoverer(type).discover(ClassTypeInformation.from(type), null);
|
||||
return Discoverers.findDiscoverer(type) //
|
||||
.discover(ClassTypeInformation.from(type), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,7 +73,154 @@ public interface PreferredConstructorDiscoverer<T, P extends PersistentProperty<
|
||||
|
||||
Assert.notNull(entity, "PersistentEntity must not be null!");
|
||||
|
||||
return PreferredConstructorDiscoverers.findDiscoverer(entity.getType()).discover(entity.getTypeInformation(),
|
||||
entity);
|
||||
return Discoverers.findDiscoverer(entity.getType()) //
|
||||
.discover(entity.getTypeInformation(), entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to find a {@link PreferredConstructor}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Roman Rodov
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
enum Discoverers {
|
||||
|
||||
/**
|
||||
* Discovers a {@link PreferredConstructor} for Java types.
|
||||
*/
|
||||
DEFAULT {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PreferredConstructorDiscoverers#discover(org.springframework.data.util.TypeInformation, org.springframework.data.mapping.PersistentEntity)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
<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;
|
||||
|
||||
for (Constructor<?> candidate : rawOwningType.getDeclaredConstructors()) {
|
||||
|
||||
PreferredConstructor<T, P> preferredConstructor = buildPreferredConstructor(candidate, type, entity);
|
||||
|
||||
// Synthetic constructors should not be considered
|
||||
if (preferredConstructor.getConstructor().isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Explicitly defined constructor trumps all
|
||||
if (preferredConstructor.isExplicitlyAnnotated()) {
|
||||
return preferredConstructor;
|
||||
}
|
||||
|
||||
// No-arg constructor trumps custom ones
|
||||
if (constructor == null || preferredConstructor.isNoArgConstructor()) {
|
||||
constructor = preferredConstructor;
|
||||
}
|
||||
|
||||
if (preferredConstructor.isNoArgConstructor()) {
|
||||
noArgConstructorFound = true;
|
||||
} else {
|
||||
numberOfArgConstructors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!noArgConstructorFound && numberOfArgConstructors > 1) {
|
||||
constructor = null;
|
||||
}
|
||||
|
||||
return constructor;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Discovers a {@link PreferredConstructor} for Kotlin types.
|
||||
*/
|
||||
KOTLIN {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PreferredConstructorDiscoverers#discover(org.springframework.data.util.TypeInformation, org.springframework.data.mapping.PersistentEntity)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
<T, P extends PersistentProperty<P>> PreferredConstructor<T, P> discover(TypeInformation<T> type,
|
||||
@Nullable PersistentEntity<T, P> entity) {
|
||||
|
||||
Class<?> rawOwningType = type.getType();
|
||||
|
||||
return Arrays.stream(rawOwningType.getDeclaredConstructors()) //
|
||||
.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(() -> {
|
||||
|
||||
KFunction<T> primaryConstructor = KClasses
|
||||
.getPrimaryConstructor(JvmClassMappingKt.getKotlinClass(type.getType()));
|
||||
Constructor<T> javaConstructor = ReflectJvmMapping.getJavaConstructor(primaryConstructor);
|
||||
|
||||
return javaConstructor != null ? buildPreferredConstructor(javaConstructor, type, entity) : null;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
|
||||
|
||||
/**
|
||||
* Find the appropriate discoverer for {@code type}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return the appropriate discoverer for {@code type}.
|
||||
*/
|
||||
private static Discoverers findDiscoverer(Class<?> type) {
|
||||
return ReflectionUtils.isKotlinClass(type) ? KOTLIN : DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers a constructor for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param entity may be {@literal null}.
|
||||
* @return the {@link PreferredConstructor} if found or {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
abstract <T, P extends PersistentProperty<P>> PreferredConstructor<T, P> discover(TypeInformation<T> type,
|
||||
@Nullable PersistentEntity<T, P> entity);
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private static <T, P extends PersistentProperty<P>> PreferredConstructor<T, P> buildPreferredConstructor(
|
||||
Constructor<?> constructor, TypeInformation<T> typeInformation, @Nullable PersistentEntity<T, P> entity) {
|
||||
|
||||
List<TypeInformation<?>> parameterTypes = typeInformation.getParameterTypes(constructor);
|
||||
|
||||
if (parameterTypes.isEmpty()) {
|
||||
return new PreferredConstructor<>((Constructor<T>) constructor);
|
||||
}
|
||||
|
||||
String[] parameterNames = PARAMETER_NAME_DISCOVERER.getParameterNames(constructor);
|
||||
|
||||
Parameter<Object, P>[] parameters = new Parameter[parameterTypes.size()];
|
||||
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
|
||||
|
||||
for (int i = 0; i < parameterTypes.size(); i++) {
|
||||
|
||||
String name = parameterNames == null ? null : parameterNames[i];
|
||||
TypeInformation<?> type = parameterTypes.get(i);
|
||||
Annotation[] annotations = parameterAnnotations[i];
|
||||
|
||||
parameters[i] = new Parameter(name, type, annotations, entity);
|
||||
}
|
||||
|
||||
return new PreferredConstructor<>((Constructor<T>) constructor, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2017 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
|
||||
*
|
||||
* http://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.mapping.model;
|
||||
|
||||
import kotlin.jvm.JvmClassMappingKt;
|
||||
import kotlin.reflect.KFunction;
|
||||
import kotlin.reflect.full.KClasses;
|
||||
import kotlin.reflect.jvm.ReflectJvmMapping;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Helper class to find a {@link PreferredConstructor}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Roman Rodov
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
enum PreferredConstructorDiscoverers {
|
||||
|
||||
/**
|
||||
* Discovers a {@link PreferredConstructor} for Java types.
|
||||
*/
|
||||
DEFAULT {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PreferredConstructorDiscoverers#discover(org.springframework.data.util.TypeInformation, org.springframework.data.mapping.PersistentEntity)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <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;
|
||||
|
||||
for (Constructor<?> candidate : rawOwningType.getDeclaredConstructors()) {
|
||||
|
||||
PreferredConstructor<T, P> preferredConstructor = buildPreferredConstructor(candidate, type, entity);
|
||||
|
||||
// Synthetic constructors should not be considered
|
||||
if (preferredConstructor.getConstructor().isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Explicitly defined constructor trumps all
|
||||
if (preferredConstructor.isExplicitlyAnnotated()) {
|
||||
return preferredConstructor;
|
||||
}
|
||||
|
||||
// No-arg constructor trumps custom ones
|
||||
if (constructor == null || preferredConstructor.isNoArgConstructor()) {
|
||||
constructor = preferredConstructor;
|
||||
}
|
||||
|
||||
if (preferredConstructor.isNoArgConstructor()) {
|
||||
noArgConstructorFound = true;
|
||||
} else {
|
||||
numberOfArgConstructors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!noArgConstructorFound && numberOfArgConstructors > 1) {
|
||||
constructor = null;
|
||||
}
|
||||
|
||||
return constructor;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Discovers a {@link PreferredConstructor} for Kotlin types.
|
||||
*/
|
||||
KOTLIN {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PreferredConstructorDiscoverers#discover(org.springframework.data.util.TypeInformation, org.springframework.data.mapping.PersistentEntity)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <T, P extends PersistentProperty<P>> PreferredConstructor<T, P> discover(TypeInformation<T> type,
|
||||
@Nullable PersistentEntity<T, P> entity) {
|
||||
|
||||
Class<?> rawOwningType = type.getType();
|
||||
|
||||
return Arrays.stream(rawOwningType.getDeclaredConstructors()) //
|
||||
.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(() -> {
|
||||
|
||||
KFunction<T> primaryConstructor = KClasses
|
||||
.getPrimaryConstructor(JvmClassMappingKt.getKotlinClass(type.getType()));
|
||||
Constructor<T> javaConstructor = ReflectJvmMapping.getJavaConstructor(primaryConstructor);
|
||||
|
||||
return javaConstructor != null ? buildPreferredConstructor(javaConstructor, type, entity) : null;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private static final ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
|
||||
|
||||
/**
|
||||
* Find the appropriate discoverer for {@code type}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return the appropriate discoverer for {@code type}.
|
||||
*/
|
||||
public static PreferredConstructorDiscoverers findDiscoverer(Class<?> type) {
|
||||
return ReflectionUtils.isKotlinClass(type) ? KOTLIN : DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers a constructor for the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param entity may be {@literal null}.
|
||||
* @return the {@link PreferredConstructor} if found or {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
public abstract <T, P extends PersistentProperty<P>> PreferredConstructor<T, P> discover(TypeInformation<T> type,
|
||||
@Nullable PersistentEntity<T, P> entity);
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private static <T, P extends PersistentProperty<P>> PreferredConstructor<T, P> buildPreferredConstructor(
|
||||
Constructor<?> constructor, TypeInformation<T> typeInformation, @Nullable PersistentEntity<T, P> entity) {
|
||||
|
||||
List<TypeInformation<?>> parameterTypes = typeInformation.getParameterTypes(constructor);
|
||||
|
||||
if (parameterTypes.isEmpty()) {
|
||||
return new PreferredConstructor<>((Constructor<T>) constructor);
|
||||
}
|
||||
|
||||
String[] parameterNames = discoverer.getParameterNames(constructor);
|
||||
|
||||
Parameter<Object, P>[] parameters = new Parameter[parameterTypes.size()];
|
||||
Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
|
||||
|
||||
for (int i = 0; i < parameterTypes.size(); i++) {
|
||||
|
||||
String name = parameterNames == null ? null : parameterNames[i];
|
||||
TypeInformation<?> type = parameterTypes.get(i);
|
||||
Annotation[] annotations = parameterAnnotations[i];
|
||||
|
||||
parameters[i] = new Parameter(name, type, annotations, entity);
|
||||
}
|
||||
|
||||
return new PreferredConstructor<>((Constructor<T>) constructor, parameters);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user