You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2014/01/03 20:37:03 UTC
svn commit: r1555229 - in /commons/proper/beanutils/trunk/src:
main/java/org/apache/commons/beanutils/BeanIntrospectionData.java
test/java/org/apache/commons/beanutils/BeanIntrospectionDataTestCase.java
Author: oheger
Date: Fri Jan 3 19:37:03 2014
New Revision: 1555229
URL: http://svn.apache.org/r1555229
Log:
Added a getWriteMethod() method to BeanIntrospectionData.
BeanIntrospectionData now remembers the names of write methods. If a write
method of a property is no longer stored in its PropertyDescriptor, the method
can now be obtained anew.
Added:
commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanIntrospectionDataTestCase.java
Modified:
commons/proper/beanutils/trunk/src/main/java/org/apache/commons/beanutils/BeanIntrospectionData.java
Modified: commons/proper/beanutils/trunk/src/main/java/org/apache/commons/beanutils/BeanIntrospectionData.java
URL: http://svn.apache.org/viewvc/commons/proper/beanutils/trunk/src/main/java/org/apache/commons/beanutils/BeanIntrospectionData.java?rev=1555229&r1=1555228&r2=1555229&view=diff
==============================================================================
--- commons/proper/beanutils/trunk/src/main/java/org/apache/commons/beanutils/BeanIntrospectionData.java (original)
+++ commons/proper/beanutils/trunk/src/main/java/org/apache/commons/beanutils/BeanIntrospectionData.java Fri Jan 3 19:37:03 2014
@@ -16,7 +16,11 @@
*/
package org.apache.commons.beanutils;
+import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
/**
* <p>
@@ -42,6 +46,9 @@ 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.
@@ -49,7 +56,19 @@ class BeanIntrospectionData {
* @param descs the array with the descriptors of the available properties
*/
public BeanIntrospectionData(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(PropertyDescriptor[] descs, Map<String, String> writeMethNames) {
descriptors = descs;
+ writeMethodNames = writeMethNames;
}
/**
@@ -76,4 +95,57 @@ class BeanIntrospectionData {
}
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(Class<?> beanCls, PropertyDescriptor desc) {
+ Method method = desc.getWriteMethod();
+ if (method == null) {
+ String methodName = writeMethodNames.get(desc.getName());
+ if (methodName != null) {
+ method = MethodUtils.getAccessibleMethod(beanCls, methodName,
+ desc.getPropertyType());
+ if (method != null) {
+ try {
+ desc.setWriteMethod(method);
+ } catch (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(PropertyDescriptor[] descs) {
+ Map<String, String> methods = new HashMap<String, String>();
+ for (PropertyDescriptor pd : descs) {
+ Method method = pd.getWriteMethod();
+ if (method != null) {
+ methods.put(pd.getName(), method.getName());
+ }
+ }
+ return methods;
+ }
}
Added: commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanIntrospectionDataTestCase.java
URL: http://svn.apache.org/viewvc/commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanIntrospectionDataTestCase.java?rev=1555229&view=auto
==============================================================================
--- commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanIntrospectionDataTestCase.java (added)
+++ commons/proper/beanutils/trunk/src/test/java/org/apache/commons/beanutils/BeanIntrospectionDataTestCase.java Fri Jan 3 19:37:03 2014
@@ -0,0 +1,117 @@
+/*
+ * 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.beanutils;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Test class for {@code BeanIntrospectionData}.
+ *
+ * @version $Id: $
+ */
+public class BeanIntrospectionDataTestCase extends TestCase {
+ /** Constant for the test bean class. */
+ private static final Class<?> BEAN_CLASS = FluentIntrospectionTestBean.class;
+
+ /** Constant for the name of the test property. */
+ private static final String TEST_PROP = "fluentGetProperty";
+
+ /**
+ * Creates an array with property descriptors for the test bean class.
+ *
+ * @return the array with property descriptors
+ */
+ private static PropertyDescriptor[] fetchDescriptors() {
+ PropertyUtilsBean pub = new PropertyUtilsBean();
+ pub.addBeanIntrospector(new FluentPropertyBeanIntrospector());
+ return pub.getPropertyDescriptors(BEAN_CLASS);
+ }
+
+ /**
+ * Creates a test instance which is initialized with default property descriptors.
+ *
+ * @return the test instance
+ */
+ private static BeanIntrospectionData setUpData() {
+ return new BeanIntrospectionData(fetchDescriptors());
+ }
+
+ /**
+ * Returns the property descriptor for the test property.
+ *
+ * @param bid the data object
+ * @return the test property descriptor
+ */
+ private static PropertyDescriptor fetchTestDescriptor(BeanIntrospectionData bid) {
+ return bid.getDescriptor(TEST_PROP);
+ }
+
+ /**
+ * Tests whether a write method can be queried if it is defined in the descriptor.
+ */
+ public void testGetWriteMethodDefined() {
+ BeanIntrospectionData data = setUpData();
+ PropertyDescriptor pd = fetchTestDescriptor(data);
+ assertNotNull("No write method", pd.getWriteMethod());
+ assertEquals("Wrong write method", pd.getWriteMethod(),
+ data.getWriteMethod(BEAN_CLASS, pd));
+ }
+
+ /**
+ * Tests whether a write method can be queried that is currently not available in the
+ * property descriptor.
+ */
+ public void testGetWriteMethodUndefined() throws Exception {
+ BeanIntrospectionData data = setUpData();
+ PropertyDescriptor pd = fetchTestDescriptor(data);
+ Method writeMethod = pd.getWriteMethod();
+ pd.setWriteMethod(null);
+ assertEquals("Wrong write method", writeMethod,
+ data.getWriteMethod(BEAN_CLASS, pd));
+ assertEquals("Method not set in descriptor", writeMethod, pd.getWriteMethod());
+ }
+
+ /**
+ * Tests getWriteMethod() if the method cannot be resolved. (This is a corner case
+ * which should normally not happen in practice.)
+ */
+ public void testGetWriteMethodNonExisting() throws Exception {
+ PropertyDescriptor pd = new PropertyDescriptor(TEST_PROP,
+ BEAN_CLASS.getMethod("getFluentGetProperty"), BEAN_CLASS.getMethod(
+ "setFluentGetProperty", String.class));
+ Map<String, String> methods = new HashMap<String, String>();
+ methods.put(TEST_PROP, "hashCode");
+ BeanIntrospectionData data = new BeanIntrospectionData(
+ new PropertyDescriptor[] { pd }, methods);
+ pd.setWriteMethod(null);
+ assertNull("Got a write method", data.getWriteMethod(BEAN_CLASS, pd));
+ }
+
+ /**
+ * Tests getWriteMethod() for a property for which no write method is known.
+ */
+ public void testGetWriteMethodUnknown() {
+ BeanIntrospectionData data = setUpData();
+ PropertyDescriptor pd = data.getDescriptor("class");
+ assertNull("Got a write method", data.getWriteMethod(BEAN_CLASS, pd));
+ }
+}