| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.commons.beanutils2; |
| |
| import java.beans.IntrospectionException; |
| import java.beans.PropertyDescriptor; |
| import java.lang.reflect.Method; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| * <p> |
| * An internally used helper class for storing introspection information about a bean |
| * class. |
| * </p> |
| * <p> |
| * This class is used by {@link PropertyUtilsBean}. When accessing bean properties via |
| * reflection information about the properties available and their types and access |
| * methods must be present. {@code PropertyUtilsBean} stores this information in a cache |
| * so that it can be accessed quickly. The cache stores instances of this class. |
| * </p> |
| * <p> |
| * This class mainly stores information about the properties of a bean class. Per default, |
| * this is contained in {@code PropertyDescriptor} objects. Some additional information |
| * required by the {@code BeanUtils} library is also stored here. |
| * </p> |
| * |
| * @since 1.9.1 |
| */ |
| class BeanIntrospectionData { |
| /** An array with property descriptors for the managed bean class. */ |
| private final PropertyDescriptor[] descriptors; |
| |
| /** A map for remembering the write method names for properties. */ |
| private final Map<String, String> writeMethodNames; |
| |
| /** |
| * Creates a new instance of {@code BeanIntrospectionData} and initializes its |
| * completely. |
| * |
| * @param descs the array with the descriptors of the available properties |
| */ |
| public BeanIntrospectionData(final PropertyDescriptor[] descs) { |
| this(descs, setUpWriteMethodNames(descs)); |
| } |
| |
| /** |
| * Creates a new instance of {@code BeanIntrospectionData} and allows setting the map |
| * with write method names. This constructor is mainly used for testing purposes. |
| * |
| * @param descs the array with the descriptors of the available properties |
| * @param writeMethNames the map with the names of write methods |
| */ |
| BeanIntrospectionData(final PropertyDescriptor[] descs, final Map<String, String> writeMethNames) { |
| descriptors = descs; |
| writeMethodNames = writeMethNames; |
| } |
| |
| /** |
| * Returns the array with property descriptors. |
| * |
| * @return the property descriptors for the associated bean class |
| */ |
| public PropertyDescriptor[] getDescriptors() { |
| return descriptors; |
| } |
| |
| /** |
| * Returns the {@code PropertyDescriptor} for the property with the specified name. If |
| * this property is unknown, result is <b>null</b>. |
| * |
| * @param name the name of the property in question |
| * @return the {@code PropertyDescriptor} for this property or <b>null</b> |
| */ |
| public PropertyDescriptor getDescriptor(final String name) { |
| for (final PropertyDescriptor pd : getDescriptors()) { |
| if (name.equals(pd.getName())) { |
| return pd; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the write method for the property determined by the given |
| * {@code PropertyDescriptor}. This information is normally available in the |
| * descriptor object itself. However, at least by the ORACLE implementation, the |
| * method is stored as a {@code SoftReference}. If this reference has been freed by |
| * the GC, it may be the case that the method cannot be obtained again. Then, |
| * additional information stored in this object is necessary to obtain the method |
| * again. |
| * |
| * @param beanCls the class of the affected bean |
| * @param desc the {@code PropertyDescriptor} of the desired property |
| * @return the write method for this property or <b>null</b> if there is none |
| */ |
| public Method getWriteMethod(final Class<?> beanCls, final PropertyDescriptor desc) { |
| Method method = desc.getWriteMethod(); |
| if (method == null) { |
| final String methodName = writeMethodNames.get(desc.getName()); |
| if (methodName != null) { |
| method = MethodUtils.getAccessibleMethod(beanCls, methodName, |
| desc.getPropertyType()); |
| if (method != null) { |
| try { |
| desc.setWriteMethod(method); |
| } catch (final IntrospectionException e) { |
| // ignore, in this case the method is not cached |
| } |
| } |
| } |
| } |
| |
| return method; |
| } |
| |
| /** |
| * Initializes the map with the names of the write methods for the supported |
| * properties. The method names - if defined - need to be stored separately because |
| * they may get lost when the GC claims soft references used by the |
| * {@code PropertyDescriptor} objects. |
| * |
| * @param descs the array with the descriptors of the available properties |
| * @return the map with the names of write methods for properties |
| */ |
| private static Map<String, String> setUpWriteMethodNames(final PropertyDescriptor[] descs) { |
| final Map<String, String> methods = new HashMap<>(); |
| for (final PropertyDescriptor pd : descs) { |
| final Method method = pd.getWriteMethod(); |
| if (method != null) { |
| methods.put(pd.getName(), method.getName()); |
| } |
| } |
| return methods; |
| } |
| } |