package org.springframework.beans.BeanUtils
1、问题
主要解决的问题是:把对象的属性数据封装到对象中。(属性拷贝)在整个J2EE的编程过程中,我们经常会从各种配置文件中读取相应的数据,需要明白的一点是从配置文件中读取到的数据都是String,但是很显然我们的应用程序中不仅仅有String一种数据类型,比如:基本数据类型(int、double、char、float等),还有自定义数据类型(引用数据类型),那么我们必须面临的一个问题就是讲字符串类型转换为各种具体的数据类型,该怎么办呢?
2、转换使用的方法
Beanutils工具在使用时几乎只用到以下几个方法,其中一个方法通常情况下都是使用匿名内部类。
- BeanUtils.setProperty(bean, name, value);其中bean是指你将要设置的对象,name指的是将要设置的属性(写成”属性名”),value(从配置文件中读取到到的字符串值)
- BeanUtils.copyProperties(bean, name, value),和上面的方法是完全一样的。使用哪个都可以
- ConvertUtils.register(Converter converter , ..),当需要将String数据转换成引用数据类型(自定义数据类型时),需要使用此方法实现转换。
- BeanUtils.populate(bean,Map),其中Map中的key必须与目标对象中的属性名相同,否则不能实现拷贝。
- BeanUtils.copyProperties(newObject,oldObject),实现对象的拷贝
自定义数据类型使用BeanUtils工具时必须具备的条件
3、其他操作bean的方法
各种DTO,BO,VO,PO相互转换的代码。在业务代码中出现大量的GET,SET方法不美观,容易出错而且耗费精力。由此出现了很多的开源工具,详见https://www.jianshu.com/p/04a8f4754c19
两个相同类的实例进行所有属性的copy,也可以对两个不同实例进行相同属性名称的值的copy。
4、代码
package org.springframework.beans; public abstract class BeanUtils { private static final Log logger = LogFactory.getLog(BeanUtils.class); private static final Set<Class<?>> unknownEditorTypes = Collections.newSetFromMap(new ConcurrentReferenceHashMap(64)); private static final Map<Class<?>, Object> DEFAULT_TYPE_VALUES; public BeanUtils() { } /** @deprecated */ @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"); } else { try { return clazz.newInstance(); } catch (InstantiationException var2) { throw new BeanInstantiationException(clazz, "Is it an abstract class?", var2); } catch (IllegalAccessException var3) { throw new BeanInstantiationException(clazz, "Is the constructor accessible?", var3); } } } 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"); } else { try { return instantiateClass(clazz.getDeclaredConstructor()); } catch (NoSuchMethodException var3) { Constructor<T> ctor = findPrimaryConstructor(clazz); if (ctor != null) { return instantiateClass(ctor); } else { throw new BeanInstantiationException(clazz, "No default constructor found", var3); } } catch (LinkageError var4) { throw new BeanInstantiationException(clazz, "Unresolvable class definition", var4); } } } public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) throws BeanInstantiationException { Assert.isAssignable(assignableTo, clazz); return instantiateClass(clazz); } 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 BeanUtils.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 var6) { throw new BeanInstantiationException(ctor, "Is it an abstract class?", var6); } catch (IllegalAccessException var7) { throw new BeanInstantiationException(ctor, "Is the constructor accessible?", var7); } catch (IllegalArgumentException var8) { throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", var8); } catch (InvocationTargetException var9) { throw new BeanInstantiationException(ctor, "Constructor threw exception", var9.getTargetException()); } } @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 = BeanUtils.KotlinDelegate.findPrimaryConstructor(clazz); if (kotlinPrimaryConstructor != null) { return kotlinPrimaryConstructor; } } return null; } @Nullable public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) { try { return clazz.getMethod(methodName, paramTypes); } catch (NoSuchMethodException var4) { return findDeclaredMethod(clazz, methodName, paramTypes); } } @Nullable public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) { try { return clazz.getDeclaredMethod(methodName, paramTypes); } catch (NoSuchMethodException var4) { return clazz.getSuperclass() != null ? findDeclaredMethod(clazz.getSuperclass(), methodName, paramTypes) : null; } } @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; } @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; } @Nullable public static Method findMethodWithMinimalParameters(Method[] methods, String methodName) throws IllegalArgumentException { Method targetMethod = null; int numMethodsFoundWithCurrentMinimumArgs = 0; Method[] var4 = methods; int var5 = methods.length; for(int var6 = 0; var6 < var5; ++var6) { Method method = var4[var6]; if (method.getName().equals(methodName)) { int numParams = method.getParameterCount(); if (targetMethod != null && numParams >= targetMethod.getParameterCount()) { if (!method.isBridge() && targetMethod.getParameterCount() == numParams) { if (targetMethod.isBridge()) { targetMethod = method; } else { ++numMethodsFoundWithCurrentMinimumArgs; } } } else { targetMethod = method; numMethodsFoundWithCurrentMinimumArgs = 1; } } } 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."); } else { return targetMethod; } } @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(40); int endParen = signature.indexOf(41); 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 var10) { throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" + parameterTypeName + "] for argument " + i + ". Root cause: " + var10); } } return findMethod(clazz, methodName, parameterTypes); } } public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws BeansException { CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz); return cr.getPropertyDescriptors(); } @Nullable public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName) throws BeansException { CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz); return cr.getPropertyDescriptor(propertyName); } @Nullable public static PropertyDescriptor findPropertyForMethod(Method method) throws BeansException { return findPropertyForMethod(method, method.getDeclaringClass()); } @Nullable public static PropertyDescriptor findPropertyForMethod(Method method, Class<?> clazz) throws BeansException { Assert.notNull(method, "Method must not be null"); PropertyDescriptor[] pds = getPropertyDescriptors(clazz); PropertyDescriptor[] var3 = pds; int var4 = pds.length; for(int var5 = 0; var5 < var4; ++var5) { PropertyDescriptor pd = var3[var5]; if (method.equals(pd.getReadMethod()) || method.equals(pd.getWriteMethod())) { return pd; } } return null; } @Nullable public static PropertyEditor findEditorByConvention(@Nullable Class<?> targetType) { if (targetType != null && !targetType.isArray() && !unknownEditorTypes.contains(targetType)) { ClassLoader cl = targetType.getClassLoader(); if (cl == null) { try { cl = ClassLoader.getSystemClassLoader(); if (cl == null) { return null; } } catch (Throwable var5) { if (logger.isDebugEnabled()) { logger.debug("Could not access system ClassLoader: " + var5); } return null; } } String targetTypeName = targetType.getName(); String editorName = targetTypeName + "Editor"; try { Class<?> editorClass = cl.loadClass(editorName); 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; } else { return (PropertyEditor)instantiateClass(editorClass); } } catch (ClassNotFoundException var6) { if (logger.isTraceEnabled()) { logger.trace("No property editor [" + editorName + "] found for type " + targetTypeName + " according to 'Editor' suffix convention"); } unknownEditorTypes.add(targetType); return null; } } else { return null; } } public static Class<?> findPropertyType(String propertyName, @Nullable Class<?>... beanClasses) { if (beanClasses != null) { Class[] var2 = beanClasses; int var3 = beanClasses.length; for(int var4 = 0; var4 < var3; ++var4) { Class<?> beanClass = var2[var4]; PropertyDescriptor pd = getPropertyDescriptor(beanClass, propertyName); if (pd != null) { return pd.getPropertyType(); } } } return Object.class; } 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); } } public static boolean isSimpleProperty(Class<?> type) { Assert.notNull(type, "'type' must not be null"); return isSimpleValueType(type) || type.isArray() && isSimpleValueType(type.getComponentType()); } public static boolean isSimpleValueType(Class<?> type) { return Void.class != type && Void.TYPE != 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); } public static void copyProperties(Object source, Object target) throws BeansException { copyProperties(source, target, (Class)null, (String[])null); } public static void copyProperties(Object source, Object target, Class<?> editable) throws BeansException { copyProperties(source, target, editable, (String[])null); } public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException { copyProperties(source, target, (Class)null, ignoreProperties); } 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; PropertyDescriptor[] var7 = targetPds; int var8 = targetPds.length; for(int var9 = 0; var9 < var8; ++var9) { PropertyDescriptor targetPd = var7[var9]; 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 && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) { 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 var15) { throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15); } } } } } } static { Map<Class<?>, Object> values = new HashMap(); values.put(Boolean.TYPE, false); values.put(Byte.TYPE, (byte)0); values.put(Short.TYPE, Short.valueOf((short)0)); values.put(Integer.TYPE, 0); values.put(Long.TYPE, 0L); DEFAULT_TYPE_VALUES = Collections.unmodifiableMap(values); } private static class KotlinDelegate { private KotlinDelegate() { } @Nullable public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) { try { KFunction<T> primaryCtor = KClasses.getPrimaryConstructor(JvmClassMappingKt.getKotlinClass(clazz)); if (primaryCtor == null) { return null; } else { Constructor<T> constructor = ReflectJvmMapping.getJavaConstructor(primaryCtor); if (constructor == null) { throw new IllegalStateException("Failed to find Java constructor for Kotlin primary constructor: " + clazz.getName()); } else { return constructor; } } } catch (UnsupportedOperationException var3) { return null; } } 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); } else { List<KParameter> parameters = kotlinConstructor.getParameters(); Map<KParameter, Object> argParameters = new HashMap(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 (!((KParameter)parameters.get(i)).isOptional() || args[i] != null) { argParameters.put(parameters.get(i), args[i]); } } return kotlinConstructor.callBy(argParameters); } } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南