/*
 * Copyright 2002-2020 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.beans;

import java.beans.ConstructorProperties;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URL;
import java.time.temporal.Temporal;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import kotlin.jvm.JvmClassMappingKt;
import kotlin.reflect.KFunction;
import kotlin.reflect.KParameter;
import kotlin.reflect.full.KClasses;
import kotlin.reflect.jvm.KCallablesJvm;
import kotlin.reflect.jvm.ReflectJvmMapping;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.KotlinDetector;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

Static convenience methods for JavaBeans: for instantiating beans, checking bean property types, copying bean properties, etc.

Mainly for internal use within the framework, but to some degree also useful for application classes. Consider Apache Commons BeanUtils, BULL - Bean Utils Light Library, or similar third-party frameworks for more comprehensive bean utilities.

Author:Rod Johnson, Juergen Hoeller, Rob Harrop, Sam Brannen, Sebastien Deleuze
/** * Static convenience methods for JavaBeans: for instantiating beans, * checking bean property types, copying bean properties, etc. * * <p>Mainly for internal use within the framework, but to some degree also * useful for application classes. Consider * <a href="https://commons.apache.org/proper/commons-beanutils/">Apache Commons BeanUtils</a>, * <a href="https://hotelsdotcom.github.io/bull/">BULL - Bean Utils Light Library</a>, * or similar third-party frameworks for more comprehensive bean utilities. * * @author Rod Johnson * @author Juergen Hoeller * @author Rob Harrop * @author Sam Brannen * @author Sebastien Deleuze */
public abstract class BeanUtils { private static final Log logger = LogFactory.getLog(BeanUtils.class); private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); private static final Set<Class<?>> unknownEditorTypes = Collections.newSetFromMap(new ConcurrentReferenceHashMap<>(64)); private static final Map<Class<?>, Object> DEFAULT_TYPE_VALUES; static { Map<Class<?>, Object> values = new HashMap<>(); values.put(boolean.class, false); values.put(byte.class, (byte) 0); values.put(short.class, (short) 0); values.put(int.class, 0); values.put(long.class, (long) 0); DEFAULT_TYPE_VALUES = Collections.unmodifiableMap(values); }
Convenience method to instantiate a class using its no-arg constructor.
Params:
  • clazz – class to instantiate
Throws:
See Also:
Returns:the new instance
Deprecated:as of Spring 5.0, following the deprecation of Class.newInstance() in JDK 9
/** * Convenience method to instantiate a class using its no-arg constructor. * @param clazz class to instantiate * @return the new instance * @throws BeanInstantiationException if the bean cannot be instantiated * @deprecated as of Spring 5.0, following the deprecation of * {@link Class#newInstance()} in JDK 9 * @see Class#newInstance() */
@Deprecated public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException { Assert.notNull(clazz, "Class must not be null"); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { return clazz.newInstance(); } catch (InstantiationException ex) { throw new BeanInstantiationException(clazz, "Is it an abstract class?", ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(clazz, "Is the constructor accessible?", ex); } }
Instantiate a class using its 'primary' constructor (for Kotlin classes, potentially having default arguments declared) or its default constructor (for regular Java classes, expecting a standard no-arg setup).

Note that this method tries to set the constructor accessible if given a non-accessible (that is, non-public) constructor.

Params:
  • clazz – the class to instantiate
Throws:
See Also:
Returns:the new instance
/** * Instantiate a class using its 'primary' constructor (for Kotlin classes, * potentially having default arguments declared) or its default constructor * (for regular Java classes, expecting a standard no-arg setup). * <p>Note that this method tries to set the constructor accessible * if given a non-accessible (that is, non-public) constructor. * @param clazz the class to instantiate * @return the new instance * @throws BeanInstantiationException if the bean cannot be instantiated. * The cause may notably indicate a {@link NoSuchMethodException} if no * primary/default constructor was found, a {@link NoClassDefFoundError} * or other {@link LinkageError} in case of an unresolvable class definition * (e.g. due to a missing dependency at runtime), or an exception thrown * from the constructor invocation itself. * @see Constructor#newInstance */
public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException { Assert.notNull(clazz, "Class must not be null"); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { return instantiateClass(clazz.getDeclaredConstructor()); } catch (NoSuchMethodException ex) { Constructor<T> ctor = findPrimaryConstructor(clazz); if (ctor != null) { return instantiateClass(ctor); } throw new BeanInstantiationException(clazz, "No default constructor found", ex); } catch (LinkageError err) { throw new BeanInstantiationException(clazz, "Unresolvable class definition", err); } }
Instantiate a class using its no-arg constructor and return the new instance as the specified assignable type.

Useful in cases where the type of the class to instantiate (clazz) is not available, but the type desired (assignableTo) is known.

Note that this method tries to set the constructor accessible if given a non-accessible (that is, non-public) constructor.

Params:
  • clazz – class to instantiate
  • assignableTo – type that clazz must be assignableTo
Throws:
See Also:
Returns:the new instance
/** * Instantiate a class using its no-arg constructor and return the new instance * as the specified assignable type. * <p>Useful in cases where the type of the class to instantiate (clazz) is not * available, but the type desired (assignableTo) is known. * <p>Note that this method tries to set the constructor accessible if given a * non-accessible (that is, non-public) constructor. * @param clazz class to instantiate * @param assignableTo type that clazz must be assignableTo * @return the new instance * @throws BeanInstantiationException if the bean cannot be instantiated * @see Constructor#newInstance */
@SuppressWarnings("unchecked") public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) throws BeanInstantiationException { Assert.isAssignable(assignableTo, clazz); return (T) instantiateClass(clazz); }
Convenience method to instantiate a class using the given constructor.

Note that this method tries to set the constructor accessible if given a non-accessible (that is, non-public) constructor, and supports Kotlin classes with optional parameters and default values.

Params:
  • ctor – the constructor to instantiate
  • args – the constructor arguments to apply (use null for an unspecified parameter, Kotlin optional parameters and Java primitive types are supported)
Throws:
See Also:
Returns:the new instance
/** * Convenience method to instantiate a class using the given constructor. * <p>Note that this method tries to set the constructor accessible if given a * non-accessible (that is, non-public) constructor, and supports Kotlin classes * with optional parameters and default values. * @param ctor the constructor to instantiate * @param args the constructor arguments to apply (use {@code null} for an unspecified * parameter, Kotlin optional parameters and Java primitive types are supported) * @return the new instance * @throws BeanInstantiationException if the bean cannot be instantiated * @see Constructor#newInstance */
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { Assert.notNull(ctor, "Constructor must not be null"); try { ReflectionUtils.makeAccessible(ctor); if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { return KotlinDelegate.instantiateClass(ctor, args); } else { Class<?>[] parameterTypes = ctor.getParameterTypes(); Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters"); Object[] argsWithDefaultValues = new Object[args.length]; for (int i = 0 ; i < args.length; i++) { if (args[i] == null) { Class<?> parameterType = parameterTypes[i]; argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null); } else { argsWithDefaultValues[i] = args[i]; } } return ctor.newInstance(argsWithDefaultValues); } } catch (InstantiationException ex) { throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex); } catch (IllegalArgumentException ex) { throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex); } catch (InvocationTargetException ex) { throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException()); } }
Return a resolvable constructor for the provided class, either a primary constructor or single public constructor or simply a default constructor. Callers have to be prepared to resolve arguments for the returned constructor's parameters, if any.
Params:
  • clazz – the class to check
See Also:
Since:5.3
/** * Return a resolvable constructor for the provided class, either a primary constructor * or single public constructor or simply a default constructor. Callers have to be * prepared to resolve arguments for the returned constructor's parameters, if any. * @param clazz the class to check * @since 5.3 * @see #findPrimaryConstructor */
@SuppressWarnings("unchecked") public static <T> Constructor<T> getResolvableConstructor(Class<T> clazz) { Constructor<T> ctor = findPrimaryConstructor(clazz); if (ctor == null) { Constructor<?>[] ctors = clazz.getConstructors(); if (ctors.length == 1) { ctor = (Constructor<T>) ctors[0]; } else { try { ctor = clazz.getDeclaredConstructor(); } catch (NoSuchMethodException ex) { throw new IllegalStateException("No primary or single public constructor found for " + clazz + " - and no default constructor found either"); } } } return ctor; }
Return the primary constructor of the provided class. For Kotlin classes, this returns the Java constructor corresponding to the Kotlin primary constructor (as defined in the Kotlin specification). Otherwise, in particular for non-Kotlin classes, this simply returns null.
Params:
  • clazz – the class to check
See Also:
Since:5.0
/** * Return the primary constructor of the provided class. For Kotlin classes, this * returns the Java constructor corresponding to the Kotlin primary constructor * (as defined in the Kotlin specification). Otherwise, in particular for non-Kotlin * classes, this simply returns {@code null}. * @param clazz the class to check * @since 5.0 * @see <a href="https://kotlinlang.org/docs/reference/classes.html#constructors">Kotlin docs</a> */
@Nullable public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) { Assert.notNull(clazz, "Class must not be null"); if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(clazz)) { Constructor<T> kotlinPrimaryConstructor = KotlinDelegate.findPrimaryConstructor(clazz); if (kotlinPrimaryConstructor != null) { return kotlinPrimaryConstructor; } } return null; }
Find a method with the given method name and the given parameter types, declared on the given class or one of its superclasses. Prefers public methods, but will return a protected, package access, or private method too.

Checks Class.getMethod first, falling back to findDeclaredMethod. This allows to find public methods without issues even in environments with restricted Java security settings.

Params:
  • clazz – the class to check
  • methodName – the name of the method to find
  • paramTypes – the parameter types of the method to find
See Also:
Returns:the Method object, or null if not found
/** * Find a method with the given method name and the given parameter types, * declared on the given class or one of its superclasses. Prefers public methods, * but will return a protected, package access, or private method too. * <p>Checks {@code Class.getMethod} first, falling back to * {@code findDeclaredMethod}. This allows to find public methods * without issues even in environments with restricted Java security settings. * @param clazz the class to check * @param methodName the name of the method to find * @param paramTypes the parameter types of the method to find * @return the Method object, or {@code null} if not found * @see Class#getMethod * @see #findDeclaredMethod */
@Nullable public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) { try { return clazz.getMethod(methodName, paramTypes); } catch (NoSuchMethodException ex) { return findDeclaredMethod(clazz, methodName, paramTypes); } }
Find a method with the given method name and the given parameter types, declared on the given class or one of its superclasses. Will return a public, protected, package access, or private method.

Checks Class.getDeclaredMethod, cascading upwards to all superclasses.

Params:
  • clazz – the class to check
  • methodName – the name of the method to find
  • paramTypes – the parameter types of the method to find
See Also:
Returns:the Method object, or null if not found
/** * Find a method with the given method name and the given parameter types, * declared on the given class or one of its superclasses. Will return a public, * protected, package access, or private method. * <p>Checks {@code Class.getDeclaredMethod}, cascading upwards to all superclasses. * @param clazz the class to check * @param methodName the name of the method to find * @param paramTypes the parameter types of the method to find * @return the Method object, or {@code null} if not found * @see Class#getDeclaredMethod */
@Nullable public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) { try { return clazz.getDeclaredMethod(methodName, paramTypes); } catch (NoSuchMethodException ex) { if (clazz.getSuperclass() != null) { return findDeclaredMethod(clazz.getSuperclass(), methodName, paramTypes); } return null; } }
Find a method with the given method name and minimal parameters (best case: none), declared on the given class or one of its superclasses. Prefers public methods, but will return a protected, package access, or private method too.

Checks Class.getMethods first, falling back to findDeclaredMethodWithMinimalParameters. This allows for finding public methods without issues even in environments with restricted Java security settings.

Params:
  • clazz – the class to check
  • methodName – the name of the method to find
Throws:
  • IllegalArgumentException – if methods of the given name were found but could not be resolved to a unique method with minimal parameters
See Also:
Returns:the Method object, or null if not found
/** * Find a method with the given method name and minimal parameters (best case: none), * declared on the given class or one of its superclasses. Prefers public methods, * but will return a protected, package access, or private method too. * <p>Checks {@code Class.getMethods} first, falling back to * {@code findDeclaredMethodWithMinimalParameters}. This allows for finding public * methods without issues even in environments with restricted Java security settings. * @param clazz the class to check * @param methodName the name of the method to find * @return the Method object, or {@code null} if not found * @throws IllegalArgumentException if methods of the given name were found but * could not be resolved to a unique method with minimal parameters * @see Class#getMethods * @see #findDeclaredMethodWithMinimalParameters */
@Nullable public static Method findMethodWithMinimalParameters(Class<?> clazz, String methodName) throws IllegalArgumentException { Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName); if (targetMethod == null) { targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName); } return targetMethod; }
Find a method with the given method name and minimal parameters (best case: none), declared on the given class or one of its superclasses. Will return a public, protected, package access, or private method.

Checks Class.getDeclaredMethods, cascading upwards to all superclasses.

Params:
  • clazz – the class to check
  • methodName – the name of the method to find
Throws:
  • IllegalArgumentException – if methods of the given name were found but could not be resolved to a unique method with minimal parameters
See Also:
Returns:the Method object, or null if not found
/** * Find a method with the given method name and minimal parameters (best case: none), * declared on the given class or one of its superclasses. Will return a public, * protected, package access, or private method. * <p>Checks {@code Class.getDeclaredMethods}, cascading upwards to all superclasses. * @param clazz the class to check * @param methodName the name of the method to find * @return the Method object, or {@code null} if not found * @throws IllegalArgumentException if methods of the given name were found but * could not be resolved to a unique method with minimal parameters * @see Class#getDeclaredMethods */
@Nullable public static Method findDeclaredMethodWithMinimalParameters(Class<?> clazz, String methodName) throws IllegalArgumentException { Method targetMethod = findMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName); if (targetMethod == null && clazz.getSuperclass() != null) { targetMethod = findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName); } return targetMethod; }
Find a method with the given method name and minimal parameters (best case: none) in the given list of methods.
Params:
  • methods – the methods to check
  • methodName – the name of the method to find
Throws:
  • IllegalArgumentException – if methods of the given name were found but could not be resolved to a unique method with minimal parameters
Returns:the Method object, or null if not found
/** * Find a method with the given method name and minimal parameters (best case: none) * in the given list of methods. * @param methods the methods to check * @param methodName the name of the method to find * @return the Method object, or {@code null} if not found * @throws IllegalArgumentException if methods of the given name were found but * could not be resolved to a unique method with minimal parameters */
@Nullable public static Method findMethodWithMinimalParameters(Method[] methods, String methodName) throws IllegalArgumentException { Method targetMethod = null; int numMethodsFoundWithCurrentMinimumArgs = 0; for (Method method : methods) { if (method.getName().equals(methodName)) { int numParams = method.getParameterCount(); if (targetMethod == null || numParams < targetMethod.getParameterCount()) { targetMethod = method; numMethodsFoundWithCurrentMinimumArgs = 1; } else if (!method.isBridge() && targetMethod.getParameterCount() == numParams) { if (targetMethod.isBridge()) { // Prefer regular method over bridge... targetMethod = method; } else { // Additional candidate with same length numMethodsFoundWithCurrentMinimumArgs++; } } } } if (numMethodsFoundWithCurrentMinimumArgs > 1) { throw new IllegalArgumentException("Cannot resolve method '" + methodName + "' to a unique method. Attempted to resolve to overloaded method with " + "the least number of parameters but there were " + numMethodsFoundWithCurrentMinimumArgs + " candidates."); } return targetMethod; }
Parse a method signature in the form methodName[([arg_list])], where arg_list is an optional, comma-separated list of fully-qualified type names, and attempts to resolve that signature against the supplied Class.

When not supplying an argument list (methodName) the method whose name matches and has the least number of parameters will be returned. When supplying an argument type list, only the method whose name and argument types match will be returned.

Note then that methodName and methodName() are not resolved in the same way. The signature methodName means the method called methodName with the least number of arguments, whereas methodName() means the method called methodName with exactly 0 arguments.

If no method can be found, then null is returned.

Params:
  • signature – the method signature as String representation
  • clazz – the class to resolve the method signature against
See Also:
Returns:the resolved Method
/** * Parse a method signature in the form {@code methodName[([arg_list])]}, * where {@code arg_list} is an optional, comma-separated list of fully-qualified * type names, and attempts to resolve that signature against the supplied {@code Class}. * <p>When not supplying an argument list ({@code methodName}) the method whose name * matches and has the least number of parameters will be returned. When supplying an * argument type list, only the method whose name and argument types match will be returned. * <p>Note then that {@code methodName} and {@code methodName()} are <strong>not</strong> * resolved in the same way. The signature {@code methodName} means the method called * {@code methodName} with the least number of arguments, whereas {@code methodName()} * means the method called {@code methodName} with exactly 0 arguments. * <p>If no method can be found, then {@code null} is returned. * @param signature the method signature as String representation * @param clazz the class to resolve the method signature against * @return the resolved Method * @see #findMethod * @see #findMethodWithMinimalParameters */
@Nullable public static Method resolveSignature(String signature, Class<?> clazz) { Assert.hasText(signature, "'signature' must not be empty"); Assert.notNull(clazz, "Class must not be null"); int startParen = signature.indexOf('('); int endParen = signature.indexOf(')'); if (startParen > -1 && endParen == -1) { throw new IllegalArgumentException("Invalid method signature '" + signature + "': expected closing ')' for args list"); } else if (startParen == -1 && endParen > -1) { throw new IllegalArgumentException("Invalid method signature '" + signature + "': expected opening '(' for args list"); } else if (startParen == -1) { return findMethodWithMinimalParameters(clazz, signature); } else { String methodName = signature.substring(0, startParen); String[] parameterTypeNames = StringUtils.commaDelimitedListToStringArray(signature.substring(startParen + 1, endParen)); Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length]; for (int i = 0; i < parameterTypeNames.length; i++) { String parameterTypeName = parameterTypeNames[i].trim(); try { parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader()); } catch (Throwable ex) { throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" + parameterTypeName + "] for argument " + i + ". Root cause: " + ex); } } return findMethod(clazz, methodName, parameterTypes); } }
Retrieve the JavaBeans PropertyDescriptors of a given class.
Params:
  • clazz – the Class to retrieve the PropertyDescriptors for
Throws:
Returns:an array of PropertyDescriptors for the given class
/** * Retrieve the JavaBeans {@code PropertyDescriptor}s of a given class. * @param clazz the Class to retrieve the PropertyDescriptors for * @return an array of {@code PropertyDescriptors} for the given class * @throws BeansException if PropertyDescriptor look fails */
public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws BeansException { return CachedIntrospectionResults.forClass(clazz).getPropertyDescriptors(); }
Retrieve the JavaBeans PropertyDescriptors for the given property.
Params:
  • clazz – the Class to retrieve the PropertyDescriptor for
  • propertyName – the name of the property
Throws:
Returns:the corresponding PropertyDescriptor, or null if none
/** * Retrieve the JavaBeans {@code PropertyDescriptors} for the given property. * @param clazz the Class to retrieve the PropertyDescriptor for * @param propertyName the name of the property * @return the corresponding PropertyDescriptor, or {@code null} if none * @throws BeansException if PropertyDescriptor lookup fails */
@Nullable public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName) throws BeansException { return CachedIntrospectionResults.forClass(clazz).getPropertyDescriptor(propertyName); }
Find a JavaBeans PropertyDescriptor for the given method, with the method either being the read method or the write method for that bean property.
Params:
  • method – the method to find a corresponding PropertyDescriptor for, introspecting its declaring class
Throws:
Returns:the corresponding PropertyDescriptor, or null if none
/** * Find a JavaBeans {@code PropertyDescriptor} for the given method, * with the method either being the read method or the write method for * that bean property. * @param method the method to find a corresponding PropertyDescriptor for, * introspecting its declaring class * @return the corresponding PropertyDescriptor, or {@code null} if none * @throws BeansException if PropertyDescriptor lookup fails */
@Nullable public static PropertyDescriptor findPropertyForMethod(Method method) throws BeansException { return findPropertyForMethod(method, method.getDeclaringClass()); }
Find a JavaBeans PropertyDescriptor for the given method, with the method either being the read method or the write method for that bean property.
Params:
  • method – the method to find a corresponding PropertyDescriptor for
  • clazz – the (most specific) class to introspect for descriptors
Throws:
Returns:the corresponding PropertyDescriptor, or null if none
Since:3.2.13
/** * Find a JavaBeans {@code PropertyDescriptor} for the given method, * with the method either being the read method or the write method for * that bean property. * @param method the method to find a corresponding PropertyDescriptor for * @param clazz the (most specific) class to introspect for descriptors * @return the corresponding PropertyDescriptor, or {@code null} if none * @throws BeansException if PropertyDescriptor lookup fails * @since 3.2.13 */
@Nullable public static PropertyDescriptor findPropertyForMethod(Method method, Class<?> clazz) throws BeansException { Assert.notNull(method, "Method must not be null"); PropertyDescriptor[] pds = getPropertyDescriptors(clazz); for (PropertyDescriptor pd : pds) { if (method.equals(pd.getReadMethod()) || method.equals(pd.getWriteMethod())) { return pd; } } return null; }
Find a JavaBeans PropertyEditor following the 'Editor' suffix convention (e.g. "mypackage.MyDomainClass" -> "mypackage.MyDomainClassEditor").

Compatible to the standard JavaBeans convention as implemented by PropertyEditorManager but isolated from the latter's registered default editors for primitive types.

Params:
  • targetType – the type to find an editor for
Returns:the corresponding editor, or null if none found
/** * Find a JavaBeans PropertyEditor following the 'Editor' suffix convention * (e.g. "mypackage.MyDomainClass" -> "mypackage.MyDomainClassEditor"). * <p>Compatible to the standard JavaBeans convention as implemented by * {@link java.beans.PropertyEditorManager} but isolated from the latter's * registered default editors for primitive types. * @param targetType the type to find an editor for * @return the corresponding editor, or {@code null} if none found */
@Nullable public static PropertyEditor findEditorByConvention(@Nullable Class<?> targetType) { if (targetType == null || targetType.isArray() || unknownEditorTypes.contains(targetType)) { return null; } ClassLoader cl = targetType.getClassLoader(); if (cl == null) { try { cl = ClassLoader.getSystemClassLoader(); if (cl == null) { return null; } } catch (Throwable ex) { // e.g. AccessControlException on Google App Engine if (logger.isDebugEnabled()) { logger.debug("Could not access system ClassLoader: " + ex); } return null; } } String targetTypeName = targetType.getName(); String editorName = targetTypeName + "Editor"; try { Class<?> editorClass = cl.loadClass(editorName); if (editorClass != null) { if (!PropertyEditor.class.isAssignableFrom(editorClass)) { if (logger.isInfoEnabled()) { logger.info("Editor class [" + editorName + "] does not implement [java.beans.PropertyEditor] interface"); } unknownEditorTypes.add(targetType); return null; } return (PropertyEditor) instantiateClass(editorClass); } // Misbehaving ClassLoader returned null instead of ClassNotFoundException // - fall back to unknown editor type registration below } catch (ClassNotFoundException ex) { // Ignore - fall back to unknown editor type registration below } if (logger.isTraceEnabled()) { logger.trace("No property editor [" + editorName + "] found for type " + targetTypeName + " according to 'Editor' suffix convention"); } unknownEditorTypes.add(targetType); return null; }
Determine the bean property type for the given property from the given classes/interfaces, if possible.
Params:
  • propertyName – the name of the bean property
  • beanClasses – the classes to check against
Returns:the property type, or Object.class as fallback
/** * Determine the bean property type for the given property from the * given classes/interfaces, if possible. * @param propertyName the name of the bean property * @param beanClasses the classes to check against * @return the property type, or {@code Object.class} as fallback */
public static Class<?> findPropertyType(String propertyName, @Nullable Class<?>... beanClasses) { if (beanClasses != null) { for (Class<?> beanClass : beanClasses) { PropertyDescriptor pd = getPropertyDescriptor(beanClass, propertyName); if (pd != null) { return pd.getPropertyType(); } } } return Object.class; }
Obtain a new MethodParameter object for the write method of the specified property.
Params:
  • pd – the PropertyDescriptor for the property
Returns:a corresponding MethodParameter object
/** * Obtain a new MethodParameter object for the write method of the * specified property. * @param pd the PropertyDescriptor for the property * @return a corresponding MethodParameter object */
public static MethodParameter getWriteMethodParameter(PropertyDescriptor pd) { if (pd instanceof GenericTypeAwarePropertyDescriptor) { return new MethodParameter(((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodParameter()); } else { Method writeMethod = pd.getWriteMethod(); Assert.state(writeMethod != null, "No write method available"); return new MethodParameter(writeMethod, 0); } }
Determine required parameter names for the given constructor, considering the JavaBeans ConstructorProperties annotation as well as Spring's DefaultParameterNameDiscoverer.
Params:
  • ctor – the constructor to find parameter names for
Throws:
See Also:
Returns:the parameter names (matching the constructor's parameter count)
Since:5.3
/** * Determine required parameter names for the given constructor, * considering the JavaBeans {@link ConstructorProperties} annotation * as well as Spring's {@link DefaultParameterNameDiscoverer}. * @param ctor the constructor to find parameter names for * @return the parameter names (matching the constructor's parameter count) * @throws IllegalStateException if the parameter names are not resolvable * @since 5.3 * @see ConstructorProperties * @see DefaultParameterNameDiscoverer */
public static String[] getParameterNames(Constructor<?> ctor) { ConstructorProperties cp = ctor.getAnnotation(ConstructorProperties.class); String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor)); Assert.state(paramNames != null, () -> "Cannot resolve parameter names for constructor " + ctor); Assert.state(paramNames.length == ctor.getParameterCount(), () -> "Invalid number of parameter names: " + paramNames.length + " for constructor " + ctor); return paramNames; }
Check if the given type represents a "simple" property: a simple value type or an array of simple value types.

See isSimpleValueType(Class<?>) for the definition of simple value type.

Used to determine properties to check for a "simple" dependency-check.

Params:
  • type – the type to check
See Also:
Returns:whether the given type represents a "simple" property
/** * Check if the given type represents a "simple" property: a simple value * type or an array of simple value types. * <p>See {@link #isSimpleValueType(Class)} for the definition of <em>simple * value type</em>. * <p>Used to determine properties to check for a "simple" dependency-check. * @param type the type to check * @return whether the given type represents a "simple" property * @see org.springframework.beans.factory.support.RootBeanDefinition#DEPENDENCY_CHECK_SIMPLE * @see org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#checkDependencies * @see #isSimpleValueType(Class) */
public static boolean isSimpleProperty(Class<?> type) { Assert.notNull(type, "'type' must not be null"); return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType())); }
Check if the given type represents a "simple" value type: a primitive or primitive wrapper, an enum, a String or other CharSequence, a Number, a Date, a Temporal, a URI, a URL, a Locale, or a Class.

Void and void are not considered simple value types.

Params:
  • type – the type to check
See Also:
Returns:whether the given type represents a "simple" value type
/** * Check if the given type represents a "simple" value type: a primitive or * primitive wrapper, an enum, a String or other CharSequence, a Number, a * Date, a Temporal, a URI, a URL, a Locale, or a Class. * <p>{@code Void} and {@code void} are not considered simple value types. * @param type the type to check * @return whether the given type represents a "simple" value type * @see #isSimpleProperty(Class) */
public static boolean isSimpleValueType(Class<?> type) { return (Void.class != type && void.class != type && (ClassUtils.isPrimitiveOrWrapper(type) || Enum.class.isAssignableFrom(type) || CharSequence.class.isAssignableFrom(type) || Number.class.isAssignableFrom(type) || Date.class.isAssignableFrom(type) || Temporal.class.isAssignableFrom(type) || URI.class == type || URL.class == type || Locale.class == type || Class.class == type)); }
Copy the property values of the given source bean into the target bean.

Note: The source and target classes do not have to match or even be derived from each other, as long as the properties match. Any bean properties that the source bean exposes but the target bean does not will silently be ignored.

This is just a convenience method. For more complex transfer needs, consider using a full BeanWrapper.

Params:
  • source – the source bean
  • target – the target bean
Throws:
See Also:
/** * Copy the property values of the given source bean into the target bean. * <p>Note: The source and target classes do not have to match or even be derived * from each other, as long as the properties match. Any bean properties that the * source bean exposes but the target bean does not will silently be ignored. * <p>This is just a convenience method. For more complex transfer needs, * consider using a full BeanWrapper. * @param source the source bean * @param target the target bean * @throws BeansException if the copying failed * @see BeanWrapper */
public static void copyProperties(Object source, Object target) throws BeansException { copyProperties(source, target, null, (String[]) null); }
Copy the property values of the given source bean into the given target bean, only setting properties defined in the given "editable" class (or interface).

Note: The source and target classes do not have to match or even be derived from each other, as long as the properties match. Any bean properties that the source bean exposes but the target bean does not will silently be ignored.

This is just a convenience method. For more complex transfer needs, consider using a full BeanWrapper.

Params:
  • source – the source bean
  • target – the target bean
  • editable – the class (or interface) to restrict property setting to
Throws:
See Also:
/** * Copy the property values of the given source bean into the given target bean, * only setting properties defined in the given "editable" class (or interface). * <p>Note: The source and target classes do not have to match or even be derived * from each other, as long as the properties match. Any bean properties that the * source bean exposes but the target bean does not will silently be ignored. * <p>This is just a convenience method. For more complex transfer needs, * consider using a full BeanWrapper. * @param source the source bean * @param target the target bean * @param editable the class (or interface) to restrict property setting to * @throws BeansException if the copying failed * @see BeanWrapper */
public static void copyProperties(Object source, Object target, Class<?> editable) throws BeansException { copyProperties(source, target, editable, (String[]) null); }
Copy the property values of the given source bean into the given target bean, ignoring the given "ignoreProperties".

Note: The source and target classes do not have to match or even be derived from each other, as long as the properties match. Any bean properties that the source bean exposes but the target bean does not will silently be ignored.

This is just a convenience method. For more complex transfer needs, consider using a full BeanWrapper.

Params:
  • source – the source bean
  • target – the target bean
  • ignoreProperties – array of property names to ignore
Throws:
See Also:
/** * Copy the property values of the given source bean into the given target bean, * ignoring the given "ignoreProperties". * <p>Note: The source and target classes do not have to match or even be derived * from each other, as long as the properties match. Any bean properties that the * source bean exposes but the target bean does not will silently be ignored. * <p>This is just a convenience method. For more complex transfer needs, * consider using a full BeanWrapper. * @param source the source bean * @param target the target bean * @param ignoreProperties array of property names to ignore * @throws BeansException if the copying failed * @see BeanWrapper */
public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException { copyProperties(source, target, null, ignoreProperties); }
Copy the property values of the given source bean into the given target bean.

Note: The source and target classes do not have to match or even be derived from each other, as long as the properties match. Any bean properties that the source bean exposes but the target bean does not will silently be ignored.

As of Spring Framework 5.3, this method honors generic type information when matching properties in the source and target objects.

Params:
  • source – the source bean
  • target – the target bean
  • editable – the class (or interface) to restrict property setting to
  • ignoreProperties – array of property names to ignore
Throws:
See Also:
/** * Copy the property values of the given source bean into the given target bean. * <p>Note: The source and target classes do not have to match or even be derived * from each other, as long as the properties match. Any bean properties that the * source bean exposes but the target bean does not will silently be ignored. * <p>As of Spring Framework 5.3, this method honors generic type information * when matching properties in the source and target objects. * @param source the source bean * @param target the target bean * @param editable the class (or interface) to restrict property setting to * @param ignoreProperties array of property names to ignore * @throws BeansException if the copying failed * @see BeanWrapper */
private static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) throws BeansException { Assert.notNull(source, "Source must not be null"); Assert.notNull(target, "Target must not be null"); Class<?> actualEditable = target.getClass(); if (editable != null) { if (!editable.isInstance(target)) { throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]"); } actualEditable = editable; } PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null); for (PropertyDescriptor targetPd : targetPds) { Method writeMethod = targetPd.getWriteMethod(); if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) { PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); if (sourcePd != null) { Method readMethod = sourcePd.getReadMethod(); if (readMethod != null) { ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod); ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0); if (targetResolvableType.isAssignableFrom(sourceResolvableType)) { try { if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { readMethod.setAccessible(true); } Object value = readMethod.invoke(source); if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(target, value); } catch (Throwable ex) { throw new FatalBeanException( "Could not copy property '" + targetPd.getName() + "' from source to target", ex); } } } } } } }
Inner class to avoid a hard dependency on Kotlin at runtime.
/** * Inner class to avoid a hard dependency on Kotlin at runtime. */
private static class KotlinDelegate {
Retrieve the Java constructor corresponding to the Kotlin primary constructor, if any.
Params:
  • clazz – the Class of the Kotlin class
See Also:
/** * Retrieve the Java constructor corresponding to the Kotlin primary constructor, if any. * @param clazz the {@link Class} of the Kotlin class * @see <a href="https://kotlinlang.org/docs/reference/classes.html#constructors"> * https://kotlinlang.org/docs/reference/classes.html#constructors</a> */
@Nullable public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) { try { KFunction<T> primaryCtor = KClasses.getPrimaryConstructor(JvmClassMappingKt.getKotlinClass(clazz)); if (primaryCtor == null) { return null; } Constructor<T> constructor = ReflectJvmMapping.getJavaConstructor(primaryCtor); if (constructor == null) { throw new IllegalStateException( "Failed to find Java constructor for Kotlin primary constructor: " + clazz.getName()); } return constructor; } catch (UnsupportedOperationException ex) { return null; } }
Instantiate a Kotlin class using the provided constructor.
Params:
  • ctor – the constructor of the Kotlin class to instantiate
  • args – the constructor arguments to apply (use null for unspecified parameter if needed)
/** * Instantiate a Kotlin class using the provided constructor. * @param ctor the constructor of the Kotlin class to instantiate * @param args the constructor arguments to apply * (use {@code null} for unspecified parameter if needed) */
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws IllegalAccessException, InvocationTargetException, InstantiationException { KFunction<T> kotlinConstructor = ReflectJvmMapping.getKotlinFunction(ctor); if (kotlinConstructor == null) { return ctor.newInstance(args); } if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers()))) { KCallablesJvm.setAccessible(kotlinConstructor, true); } List<KParameter> parameters = kotlinConstructor.getParameters(); Map<KParameter, Object> argParameters = CollectionUtils.newHashMap(parameters.size()); Assert.isTrue(args.length <= parameters.size(), "Number of provided arguments should be less of equals than number of constructor parameters"); for (int i = 0 ; i < args.length ; i++) { if (!(parameters.get(i).isOptional() && args[i] == null)) { argParameters.put(parameters.get(i), args[i]); } } return kotlinConstructor.callBy(argParameters); } } }