Revised handling of missing data class arguments
Includes unified detection of Kotlin's optional parameters in MethodParameter.isOptional(), reduces BeanUtils.findPrimaryConstructor to Kotlin semantics (for reuse in AutowiredAnnotationBeanPostProcessor), and finally introduces a common KotlinDetector delegate with an isKotlinType(Class) check. Issue: SPR-15877 Issue: SPR-16020
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2002-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.core;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A common delegate for detecting Kotlin's presence and for identifying Kotlin types.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sebastien Deleuze
|
||||
* @since 5.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class KotlinDetector {
|
||||
|
||||
@Nullable
|
||||
private static final Class<? extends Annotation> kotlinMetadata;
|
||||
|
||||
static {
|
||||
Class<?> metadata;
|
||||
try {
|
||||
metadata = ClassUtils.forName("kotlin.Metadata", KotlinDetector.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Kotlin API not available - no Kotlin support
|
||||
metadata = null;
|
||||
}
|
||||
kotlinMetadata = (Class<? extends Annotation>) metadata;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether Kotlin is present in general.
|
||||
*/
|
||||
public static boolean isKotlinPresent() {
|
||||
return (kotlinMetadata != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given {@code Class} is a Kotlin type
|
||||
* (with Kotlin metadata present on it).
|
||||
*/
|
||||
public static boolean isKotlinType(Class<?> clazz) {
|
||||
return (kotlinMetadata != null && clazz.getDeclaredAnnotation(kotlinMetadata) != null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.core;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
@@ -27,7 +26,6 @@ import kotlin.reflect.KParameter;
|
||||
import kotlin.reflect.jvm.ReflectJvmMapping;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link ParameterNameDiscoverer} implementation which uses Kotlin's reflection facilities
|
||||
@@ -41,27 +39,13 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
public class KotlinReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
|
||||
|
||||
@Nullable
|
||||
private static final Class<?> kotlinMetadata;
|
||||
|
||||
static {
|
||||
Class<?> metadata;
|
||||
try {
|
||||
metadata = ClassUtils.forName("kotlin.Metadata", KotlinReflectionParameterNameDiscoverer.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Kotlin API not available - no special support for Kotlin class instantiation
|
||||
metadata = null;
|
||||
}
|
||||
kotlinMetadata = metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String[] getParameterNames(Method method) {
|
||||
if (!useKotlinSupport(method.getDeclaringClass())) {
|
||||
if (!KotlinDetector.isKotlinType(method.getDeclaringClass())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method);
|
||||
return (function != null ? getParameterNames(function.getParameters()) : null);
|
||||
@@ -74,9 +58,10 @@ public class KotlinReflectionParameterNameDiscoverer implements ParameterNameDis
|
||||
@Override
|
||||
@Nullable
|
||||
public String[] getParameterNames(Constructor<?> ctor) {
|
||||
if (!useKotlinSupport(ctor.getDeclaringClass())) {
|
||||
if (!KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(ctor);
|
||||
return (function != null ? getParameterNames(function.getParameters()) : null);
|
||||
@@ -103,13 +88,4 @@ public class KotlinReflectionParameterNameDiscoverer implements ParameterNameDis
|
||||
return parameterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Kotlin is present and if the specified class is a Kotlin one.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static boolean useKotlinSupport(Class<?> clazz) {
|
||||
return (kotlinMetadata != null &&
|
||||
clazz.getDeclaredAnnotation((Class<? extends Annotation>) kotlinMetadata) != null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ import kotlin.reflect.jvm.ReflectJvmMapping;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Helper class that encapsulates the specification of a method parameter, i.e. a {@link Method}
|
||||
@@ -58,22 +57,6 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
public class MethodParameter {
|
||||
|
||||
@Nullable
|
||||
private static final Class<?> kotlinMetadata;
|
||||
|
||||
static {
|
||||
Class<?> metadata;
|
||||
try {
|
||||
metadata = ClassUtils.forName("kotlin.Metadata", MethodParameter.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Kotlin API not available - no Kotlin support
|
||||
metadata = null;
|
||||
}
|
||||
kotlinMetadata = metadata;
|
||||
}
|
||||
|
||||
|
||||
private final Executable executable;
|
||||
|
||||
private final int parameterIndex;
|
||||
@@ -353,16 +336,7 @@ public class MethodParameter {
|
||||
*/
|
||||
public boolean isOptional() {
|
||||
return (getParameterType() == Optional.class || hasNullableAnnotation() ||
|
||||
(useKotlinSupport(this.getContainingClass()) && KotlinDelegate.isNullable(this)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Kotlin is present and if the specified class is a Kotlin one.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static boolean useKotlinSupport(Class<?> clazz) {
|
||||
return (kotlinMetadata != null &&
|
||||
clazz.getDeclaredAnnotation((Class<? extends Annotation>) kotlinMetadata) != null);
|
||||
(KotlinDetector.isKotlinType(getContainingClass()) && KotlinDelegate.isOptional(this)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -754,9 +728,10 @@ public class MethodParameter {
|
||||
private static class KotlinDelegate {
|
||||
|
||||
/**
|
||||
* Check whether the specified {@link MethodParameter} represents a nullable Kotlin type or not.
|
||||
* Check whether the specified {@link MethodParameter} represents a nullable Kotlin type
|
||||
* or an optional parameter (with a default value in the Kotlin declaration).
|
||||
*/
|
||||
public static boolean isNullable(MethodParameter param) {
|
||||
public static boolean isOptional(MethodParameter param) {
|
||||
Method method = param.getMethod();
|
||||
Constructor<?> ctor = param.getConstructor();
|
||||
int index = param.getParameterIndex();
|
||||
@@ -774,13 +749,12 @@ public class MethodParameter {
|
||||
}
|
||||
if (function != null) {
|
||||
List<KParameter> parameters = function.getParameters();
|
||||
return parameters
|
||||
KParameter parameter = parameters
|
||||
.stream()
|
||||
.filter(p -> KParameter.Kind.VALUE.equals(p.getKind()))
|
||||
.collect(Collectors.toList())
|
||||
.get(index)
|
||||
.getType()
|
||||
.isMarkedNullable();
|
||||
.get(index);
|
||||
return (parameter.getType().isMarkedNullable() || parameter.isOptional());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user