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:
Oliver Gierke
2017-08-25 13:03:07 +02:00
committed by Mark Paluch
parent b05c4e74fb
commit 22b6971318
5 changed files with 190 additions and 202 deletions

View File

@@ -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);
}
/**

View File

@@ -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];

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}