Mercurial > hg > openjdk > jdk8 > jdk
changeset 8096:2ad01ecbaf90
7172865: PropertyDescriptor fails to work with setter method name if setter is non-void
Reviewed-by: art, alexsch
author | malenkov |
---|---|
date | Tue, 03 Sep 2013 21:53:14 +0400 |
parents | 80a8c4ff3b51 |
children | ba711056009f |
files | src/share/classes/java/beans/IndexedPropertyDescriptor.java src/share/classes/java/beans/MethodDescriptor.java src/share/classes/java/beans/MethodRef.java src/share/classes/java/beans/PropertyDescriptor.java test/java/beans/Introspector/Test7172865.java |
diffstat | 5 files changed, 287 insertions(+), 74 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/java/beans/IndexedPropertyDescriptor.java Tue Sep 03 17:27:20 2013 +0400 +++ b/src/share/classes/java/beans/IndexedPropertyDescriptor.java Tue Sep 03 21:53:14 2013 +0400 @@ -41,8 +41,8 @@ public class IndexedPropertyDescriptor extends PropertyDescriptor { private Reference<? extends Class<?>> indexedPropertyTypeRef; - private Reference<Method> indexedReadMethodRef; - private Reference<Method> indexedWriteMethodRef; + private final MethodRef indexedReadMethodRef = new MethodRef(); + private final MethodRef indexedWriteMethodRef = new MethodRef(); private String indexedReadMethodName; private String indexedWriteMethodName; @@ -173,11 +173,11 @@ * May return null if the property isn't indexed or is write-only. */ public synchronized Method getIndexedReadMethod() { - Method indexedReadMethod = getIndexedReadMethod0(); + Method indexedReadMethod = this.indexedReadMethodRef.get(); if (indexedReadMethod == null) { Class<?> cls = getClass0(); if (cls == null || - (indexedReadMethodName == null && indexedReadMethodRef == null)) { + (indexedReadMethodName == null && !this.indexedReadMethodRef.isSet())) { // the Indexed readMethod was explicitly set to null. return null; } @@ -215,20 +215,19 @@ // the indexed property type is set by the reader. setIndexedPropertyType(findIndexedPropertyType(readMethod, - getIndexedWriteMethod0())); + this.indexedWriteMethodRef.get())); setIndexedReadMethod0(readMethod); } private void setIndexedReadMethod0(Method readMethod) { + this.indexedReadMethodRef.set(readMethod); if (readMethod == null) { indexedReadMethodName = null; - indexedReadMethodRef = null; return; } setClass0(readMethod.getDeclaringClass()); indexedReadMethodName = readMethod.getName(); - this.indexedReadMethodRef = getSoftReference(readMethod); setTransient(readMethod.getAnnotation(Transient.class)); } @@ -241,11 +240,11 @@ * May return null if the property isn't indexed or is read-only. */ public synchronized Method getIndexedWriteMethod() { - Method indexedWriteMethod = getIndexedWriteMethod0(); + Method indexedWriteMethod = this.indexedWriteMethodRef.get(); if (indexedWriteMethod == null) { Class<?> cls = getClass0(); if (cls == null || - (indexedWriteMethodName == null && indexedWriteMethodRef == null)) { + (indexedWriteMethodName == null && !this.indexedWriteMethodRef.isSet())) { // the Indexed writeMethod was explicitly set to null. return null; } @@ -301,15 +300,14 @@ } private void setIndexedWriteMethod0(Method writeMethod) { + this.indexedWriteMethodRef.set(writeMethod); if (writeMethod == null) { indexedWriteMethodName = null; - indexedWriteMethodRef = null; return; } setClass0(writeMethod.getDeclaringClass()); indexedWriteMethodName = writeMethod.getName(); - this.indexedWriteMethodRef = getSoftReference(writeMethod); setTransient(writeMethod.getAnnotation(Transient.class)); } @@ -349,18 +347,6 @@ : null; } - private Method getIndexedReadMethod0() { - return (this.indexedReadMethodRef != null) - ? this.indexedReadMethodRef.get() - : null; - } - - private Method getIndexedWriteMethod0() { - return (this.indexedWriteMethodRef != null) - ? this.indexedWriteMethodRef.get() - : null; - } - private Class<?> findIndexedPropertyType(Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException { @@ -492,8 +478,8 @@ */ IndexedPropertyDescriptor(IndexedPropertyDescriptor old) { super(old); - indexedReadMethodRef = old.indexedReadMethodRef; - indexedWriteMethodRef = old.indexedWriteMethodRef; + this.indexedReadMethodRef.set(old.indexedReadMethodRef.get()); + this.indexedWriteMethodRef.set(old.indexedWriteMethodRef.get()); indexedPropertyTypeRef = old.indexedPropertyTypeRef; indexedWriteMethodName = old.indexedWriteMethodName; indexedReadMethodName = old.indexedReadMethodName; @@ -502,7 +488,7 @@ void updateGenericsFor(Class<?> type) { super.updateGenericsFor(type); try { - setIndexedPropertyType(findIndexedPropertyType(getIndexedReadMethod0(), getIndexedWriteMethod0())); + setIndexedPropertyType(findIndexedPropertyType(this.indexedReadMethodRef.get(), this.indexedWriteMethodRef.get())); } catch (IntrospectionException exception) { setIndexedPropertyType(null); @@ -532,7 +518,7 @@ void appendTo(StringBuilder sb) { super.appendTo(sb); appendTo(sb, "indexedPropertyType", this.indexedPropertyTypeRef); - appendTo(sb, "indexedReadMethod", this.indexedReadMethodRef); - appendTo(sb, "indexedWriteMethod", this.indexedWriteMethodRef); + appendTo(sb, "indexedReadMethod", this.indexedReadMethodRef.get()); + appendTo(sb, "indexedWriteMethod", this.indexedWriteMethodRef.get()); } }
--- a/src/share/classes/java/beans/MethodDescriptor.java Tue Sep 03 17:27:20 2013 +0400 +++ b/src/share/classes/java/beans/MethodDescriptor.java Tue Sep 03 21:53:14 2013 +0400 @@ -38,7 +38,7 @@ public class MethodDescriptor extends FeatureDescriptor { - private Reference<Method> methodRef; + private final MethodRef methodRef = new MethodRef(); private String[] paramNames; @@ -81,7 +81,7 @@ * @return The low-level description of the method */ public synchronized Method getMethod() { - Method method = getMethod0(); + Method method = this.methodRef.get(); if (method == null) { Class<?> cls = getClass0(); String name = getName(); @@ -114,13 +114,7 @@ setClass0(method.getDeclaringClass()); } setParams(getParameterTypes(getClass0(), method)); - this.methodRef = getSoftReference(method); - } - - private Method getMethod0() { - return (this.methodRef != null) - ? this.methodRef.get() - : null; + this.methodRef.set(method); } private synchronized void setParams(Class<?>[] param) { @@ -177,12 +171,10 @@ */ MethodDescriptor(MethodDescriptor x, MethodDescriptor y) { - super(x,y); + super(x, y); - methodRef = x.methodRef; - if (y.methodRef != null) { - methodRef = y.methodRef; - } + Method method = y.methodRef.get(); + this.methodRef.set(null != method ? method : x.methodRef.get()); params = x.params; if (y.params != null) { params = y.params; @@ -205,7 +197,7 @@ MethodDescriptor(MethodDescriptor old) { super(old); - methodRef = old.methodRef; + this.methodRef.set(old.getMethod()); params = old.params; paramNames = old.paramNames; @@ -219,7 +211,7 @@ } void appendTo(StringBuilder sb) { - appendTo(sb, "method", this.methodRef); + appendTo(sb, "method", this.methodRef.get()); if (this.parameterDescriptors != null) { sb.append("; parameterDescriptors={"); for (ParameterDescriptor pd : this.parameterDescriptors) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/beans/MethodRef.java Tue Sep 03 21:53:14 2013 +0400 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.beans; + +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; + +import static sun.reflect.misc.ReflectUtil.isPackageAccessible; + +final class MethodRef { + private String signature; + private SoftReference<Method> methodRef; + private WeakReference<Class<?>> typeRef; + + void set(Method method) { + if (method == null) { + this.signature = null; + this.methodRef = null; + this.typeRef = null; + } + else { + this.signature = method.toGenericString(); + this.methodRef = new SoftReference<>(method); + this.typeRef = new WeakReference<Class<?>>(method.getDeclaringClass()); + } + } + + boolean isSet() { + return this.methodRef != null; + } + + Method get() { + if (this.methodRef == null) { + return null; + } + Method method = this.methodRef.get(); + if (method == null) { + method = find(this.typeRef.get(), this.signature); + if (method == null) { + this.signature = null; + this.methodRef = null; + this.typeRef = null; + } + else { + this.methodRef = new SoftReference<>(method); + } + } + return isPackageAccessible(method.getDeclaringClass()) ? method : null; + } + + private static Method find(Class<?> type, String signature) { + if (type != null) { + for (Method method : type.getMethods()) { + if (type.equals(method.getDeclaringClass())) { + if (method.toGenericString().equals(signature)) { + return method; + } + } + } + } + return null; + } +}
--- a/src/share/classes/java/beans/PropertyDescriptor.java Tue Sep 03 17:27:20 2013 +0400 +++ b/src/share/classes/java/beans/PropertyDescriptor.java Tue Sep 03 21:53:14 2013 +0400 @@ -36,8 +36,8 @@ public class PropertyDescriptor extends FeatureDescriptor { private Reference<? extends Class<?>> propertyTypeRef; - private Reference<Method> readMethodRef; - private Reference<Method> writeMethodRef; + private final MethodRef readMethodRef = new MethodRef(); + private final MethodRef writeMethodRef = new MethodRef(); private Reference<? extends Class<?>> propertyEditorClassRef; private boolean bound; @@ -68,8 +68,8 @@ public PropertyDescriptor(String propertyName, Class<?> beanClass) throws IntrospectionException { this(propertyName, beanClass, - Introspector.IS_PREFIX + NameGenerator.capitalize(propertyName), - Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName)); + Introspector.IS_PREFIX + NameGenerator.capitalize(propertyName), + Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName)); } /** @@ -203,10 +203,10 @@ * May return null if the property can't be read. */ public synchronized Method getReadMethod() { - Method readMethod = getReadMethod0(); + Method readMethod = this.readMethodRef.get(); if (readMethod == null) { Class<?> cls = getClass0(); - if (cls == null || (readMethodName == null && readMethodRef == null)) { + if (cls == null || (readMethodName == null && !this.readMethodRef.isSet())) { // The read method was explicitly set to null. return null; } @@ -247,17 +247,16 @@ */ public synchronized void setReadMethod(Method readMethod) throws IntrospectionException { + this.readMethodRef.set(readMethod); if (readMethod == null) { readMethodName = null; - readMethodRef = null; return; } // The property type is determined by the read method. - setPropertyType(findPropertyType(readMethod, getWriteMethod0())); + setPropertyType(findPropertyType(readMethod, this.writeMethodRef.get())); setClass0(readMethod.getDeclaringClass()); readMethodName = readMethod.getName(); - this.readMethodRef = getSoftReference(readMethod); setTransient(readMethod.getAnnotation(Transient.class)); } @@ -268,10 +267,10 @@ * May return null if the property can't be written. */ public synchronized Method getWriteMethod() { - Method writeMethod = getWriteMethod0(); + Method writeMethod = this.writeMethodRef.get(); if (writeMethod == null) { Class<?> cls = getClass0(); - if (cls == null || (writeMethodName == null && writeMethodRef == null)) { + if (cls == null || (writeMethodName == null && !this.writeMethodRef.isSet())) { // The write method was explicitly set to null. return null; } @@ -318,9 +317,9 @@ */ public synchronized void setWriteMethod(Method writeMethod) throws IntrospectionException { + this.writeMethodRef.set(writeMethod); if (writeMethod == null) { writeMethodName = null; - writeMethodRef = null; return; } // Set the property type - which validates the method @@ -328,22 +327,9 @@ setClass0(writeMethod.getDeclaringClass()); writeMethodName = writeMethod.getName(); - this.writeMethodRef = getSoftReference(writeMethod); setTransient(writeMethod.getAnnotation(Transient.class)); } - private Method getReadMethod0() { - return (this.readMethodRef != null) - ? this.readMethodRef.get() - : null; - } - - private Method getWriteMethod0() { - return (this.writeMethodRef != null) - ? this.writeMethodRef.get() - : null; - } - /** * Overridden to ensure that a super class doesn't take precedent */ @@ -617,8 +603,8 @@ PropertyDescriptor(PropertyDescriptor old) { super(old); propertyTypeRef = old.propertyTypeRef; - readMethodRef = old.readMethodRef; - writeMethodRef = old.writeMethodRef; + this.readMethodRef.set(old.readMethodRef.get()); + this.writeMethodRef.set(old.writeMethodRef.get()); propertyEditorClassRef = old.propertyEditorClassRef; writeMethodName = old.writeMethodName; @@ -632,7 +618,7 @@ void updateGenericsFor(Class<?> type) { setClass0(type); try { - setPropertyType(findPropertyType(getReadMethod0(), getWriteMethod0())); + setPropertyType(findPropertyType(this.readMethodRef.get(), this.writeMethodRef.get())); } catch (IntrospectionException exception) { setPropertyType(null); @@ -723,8 +709,8 @@ appendTo(sb, "constrained", this.constrained); appendTo(sb, "propertyEditorClass", this.propertyEditorClassRef); appendTo(sb, "propertyType", this.propertyTypeRef); - appendTo(sb, "readMethod", this.readMethodRef); - appendTo(sb, "writeMethod", this.writeMethodRef); + appendTo(sb, "readMethod", this.readMethodRef.get()); + appendTo(sb, "writeMethod", this.writeMethodRef.get()); } private boolean isAssignable(Method m1, Method m2) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/beans/Introspector/Test7172865.java Tue Sep 03 21:53:14 2013 +0400 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.beans.IndexedPropertyDescriptor; +import java.beans.MethodDescriptor; +import java.beans.PropertyDescriptor; + +/* + * @test + * @bug 7172854 7172865 + * @summary Tests that cached methods are not lost + * @author Sergey Malenkov + */ + +public class Test7172865 { + public static void main(String[] args) throws Exception { + int errors = 0; + + MethodDescriptor md = new MethodDescriptor(Test7172865.class.getMethod("getGood")); + + errors += test(PropertyDescriptor.class, "good", true); + PropertyDescriptor pdGoodString = new PropertyDescriptor("good", Test7172865.class, "getGood", "setGood"); + PropertyDescriptor pdGoodMethod = new PropertyDescriptor("good", + Test7172865.class.getMethod("getGood"), + Test7172865.class.getMethod("setGood", args.getClass())); + + errors += test(PropertyDescriptor.class, "bad", false); + PropertyDescriptor pdBadString = new PropertyDescriptor("bad", Test7172865.class, "getBad", null); + PropertyDescriptor pdBadMethod = new PropertyDescriptor("bad", + Test7172865.class.getMethod("getBad"), + Test7172865.class.getMethod("setBad", args.getClass())); + + errors += test(IndexedPropertyDescriptor.class, "good", true); + IndexedPropertyDescriptor ipdGoodString = new IndexedPropertyDescriptor("good", Test7172865.class, "getGood", "setGood", "getGood", "setGood"); + IndexedPropertyDescriptor ipdGoodMethod = new IndexedPropertyDescriptor("good", + Test7172865.class.getMethod("getGood"), + Test7172865.class.getMethod("setGood", args.getClass()), + Test7172865.class.getMethod("getGood", Integer.TYPE), + Test7172865.class.getMethod("setGood", Integer.TYPE, String.class)); + + errors += test(IndexedPropertyDescriptor.class, "bad", false); + IndexedPropertyDescriptor ipdBadString = new IndexedPropertyDescriptor("bad", Test7172865.class, "getBad", null, "getBad", null); + IndexedPropertyDescriptor ipdBadMethod = new IndexedPropertyDescriptor("bad", + Test7172865.class.getMethod("getBad"), + Test7172865.class.getMethod("setBad", args.getClass()), + Test7172865.class.getMethod("getBad", Integer.TYPE), + Test7172865.class.getMethod("setBad", Integer.TYPE, String.class)); + + for (int i = 1; i <= 2; i++) { + System.out.println("STEP: " + i); + errors += test("md", null != md.getMethod()); + + errors += test("pdGoodString", pdGoodString, true, true); + errors += test("pdGoodMethod", pdGoodMethod, true, true); + + errors += test("pdBadString", pdBadString, true, false); + errors += test("pdBadMethod", pdBadMethod, true, true); + + errors += test("ipdGoodString", ipdGoodString, true, true, true, true); + errors += test("ipdGoodMethod", ipdGoodMethod, true, true, true, true); + + errors += test("ipdBadString", ipdBadString, true, false, true, false); + errors += test("ipdBadMethod", ipdBadMethod, true, true, true, true); + + try { + int[] array = new int[1024]; + while (true) { + array = new int[array.length << 1]; + } + } + catch (OutOfMemoryError error) { + System.gc(); + } + } + if (errors > 0) { + throw new Error("found " + errors + " errors"); + } + } + + private static int test(Class<?> type, String property, boolean value) { + String message = type.getSimpleName() + "(" + property + ") "; + try { + type.getConstructor(String.class, Class.class).newInstance(property, Test7172865.class); + message += "passed"; + } + catch (Exception exception) { + message += "failed"; + value = !value; + } + if (value) { + message += " as expected"; + } + System.out.println(message); + return value ? 0 : 1; + } + + private static int test(String message, boolean value) { + System.out.println(message + ": " + (value ? "passed" : "failed")); + return value ? 0 : 1; + } + + private static int test(String message, PropertyDescriptor pd, boolean rm, boolean wm) { + return test(message + ".Read", rm == (null != pd.getReadMethod())) + + test(message + ".Write", wm == (null != pd.getWriteMethod())); + } + + private static int test(String message, IndexedPropertyDescriptor ipd, boolean rm, boolean wm, boolean irm, boolean iwm) { + return test(message, ipd, rm, wm) + + test(message + ".IndexedRead", irm == (null != ipd.getIndexedReadMethod())) + + test(message + ".IndexedWrite", iwm == (null != ipd.getIndexedWriteMethod())); + } + + public String[] getGood() { + return null; + } + + public String getGood(int index) { + return null; + } + + public void setGood(String[] good) { + } + + public void setGood(int index, String value) { + } + + public String[] getBad() { + return null; + } + + public String getBad(int index) { + return null; + } + + public Test7172865 setBad(String[] bad) { + return null; + } + + public Test7172865 setBad(int index, String value) { + return null; + } +}