1 /* 2 * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.beans; 27 28 import java.lang.ref.Reference; 29 import java.lang.ref.WeakReference; 30 import java.lang.reflect.Method; 31 import java.util.List; 32 import java.util.ArrayList; 33 34 /** 35 * A MethodDescriptor describes a particular method that a Java Bean 36 * supports for external access from other components. 37 * 38 * @since 1.1 39 */ 40 41 public class MethodDescriptor extends FeatureDescriptor { 42 43 private final MethodRef methodRef = new MethodRef(); 44 45 private String[] paramNames; 46 47 private List<WeakReference<Class<?>>> params; 48 49 private ParameterDescriptor[] parameterDescriptors; 50 51 /** 52 * Constructs a {@code MethodDescriptor} from a 53 * {@code Method}. 54 * 55 * @param method The low-level method information. 56 */ MethodDescriptor(Method method)57 public MethodDescriptor(Method method) { 58 this(method, null); 59 } 60 61 62 /** 63 * Constructs a {@code MethodDescriptor} from a 64 * {@code Method} providing descriptive information for each 65 * of the method's parameters. 66 * 67 * @param method The low-level method information. 68 * @param parameterDescriptors Descriptive information for each of the 69 * method's parameters. 70 */ MethodDescriptor(Method method, ParameterDescriptor[] parameterDescriptors)71 public MethodDescriptor(Method method, 72 ParameterDescriptor[] parameterDescriptors) { 73 setName(method.getName()); 74 setMethod(method); 75 this.parameterDescriptors = (parameterDescriptors != null) 76 ? parameterDescriptors.clone() 77 : null; 78 } 79 80 /** 81 * Gets the method that this MethodDescriptor encapsulates. 82 * 83 * @return The low-level description of the method 84 */ getMethod()85 public synchronized Method getMethod() { 86 Method method = this.methodRef.get(); 87 if (method == null) { 88 Class<?> cls = getClass0(); 89 String name = getName(); 90 if ((cls != null) && (name != null)) { 91 Class<?>[] params = getParams(); 92 if (params == null) { 93 for (int i = 0; i < 3; i++) { 94 // Find methods for up to 2 params. We are guessing here. 95 // This block should never execute unless the classloader 96 // that loaded the argument classes disappears. 97 method = Introspector.findMethod(cls, name, i, null); 98 if (method != null) { 99 break; 100 } 101 } 102 } else { 103 method = Introspector.findMethod(cls, name, params.length, params); 104 } 105 setMethod(method); 106 } 107 } 108 return method; 109 } 110 setMethod(Method method)111 private synchronized void setMethod(Method method) { 112 if (method == null) { 113 return; 114 } 115 if (getClass0() == null) { 116 setClass0(method.getDeclaringClass()); 117 } 118 setParams(getParameterTypes(getClass0(), method)); 119 this.methodRef.set(method); 120 } 121 setParams(Class<?>[] param)122 private synchronized void setParams(Class<?>[] param) { 123 if (param == null) { 124 return; 125 } 126 paramNames = new String[param.length]; 127 params = new ArrayList<>(param.length); 128 for (int i = 0; i < param.length; i++) { 129 paramNames[i] = param[i].getName(); 130 params.add(new WeakReference<Class<?>>(param[i])); 131 } 132 } 133 134 // pp getParamNames used as an optimization to avoid method.getParameterTypes. getParamNames()135 String[] getParamNames() { 136 return paramNames; 137 } 138 getParams()139 private synchronized Class<?>[] getParams() { 140 Class<?>[] clss = new Class<?>[params.size()]; 141 142 for (int i = 0; i < params.size(); i++) { 143 Reference<? extends Class<?>> ref = (Reference<? extends Class<?>>)params.get(i); 144 Class<?> cls = ref.get(); 145 if (cls == null) { 146 return null; 147 } else { 148 clss[i] = cls; 149 } 150 } 151 return clss; 152 } 153 154 /** 155 * Gets the ParameterDescriptor for each of this MethodDescriptor's 156 * method's parameters. 157 * 158 * @return The locale-independent names of the parameters. May return 159 * a null array if the parameter names aren't known. 160 */ getParameterDescriptors()161 public ParameterDescriptor[] getParameterDescriptors() { 162 return (this.parameterDescriptors != null) 163 ? this.parameterDescriptors.clone() 164 : null; 165 } 166 resolve(Method oldMethod, Method newMethod)167 private static Method resolve(Method oldMethod, Method newMethod) { 168 if (oldMethod == null) { 169 return newMethod; 170 } 171 if (newMethod == null) { 172 return oldMethod; 173 } 174 return !oldMethod.isSynthetic() && newMethod.isSynthetic() ? oldMethod : newMethod; 175 } 176 177 /* 178 * Package-private constructor 179 * Merge two method descriptors. Where they conflict, give the 180 * second argument (y) priority over the first argument (x). 181 * @param x The first (lower priority) MethodDescriptor 182 * @param y The second (higher priority) MethodDescriptor 183 */ 184 MethodDescriptor(MethodDescriptor x, MethodDescriptor y)185 MethodDescriptor(MethodDescriptor x, MethodDescriptor y) { 186 super(x, y); 187 188 this.methodRef.set(resolve(x.methodRef.get(), y.methodRef.get())); 189 params = x.params; 190 if (y.params != null) { 191 params = y.params; 192 } 193 paramNames = x.paramNames; 194 if (y.paramNames != null) { 195 paramNames = y.paramNames; 196 } 197 198 parameterDescriptors = x.parameterDescriptors; 199 if (y.parameterDescriptors != null) { 200 parameterDescriptors = y.parameterDescriptors; 201 } 202 } 203 204 /* 205 * Package-private dup constructor 206 * This must isolate the new object from any changes to the old object. 207 */ MethodDescriptor(MethodDescriptor old)208 MethodDescriptor(MethodDescriptor old) { 209 super(old); 210 211 this.methodRef.set(old.getMethod()); 212 params = old.params; 213 paramNames = old.paramNames; 214 215 if (old.parameterDescriptors != null) { 216 int len = old.parameterDescriptors.length; 217 parameterDescriptors = new ParameterDescriptor[len]; 218 for (int i = 0; i < len ; i++) { 219 parameterDescriptors[i] = new ParameterDescriptor(old.parameterDescriptors[i]); 220 } 221 } 222 } 223 appendTo(StringBuilder sb)224 void appendTo(StringBuilder sb) { 225 appendTo(sb, "method", this.methodRef.get()); 226 if (this.parameterDescriptors != null) { 227 sb.append("; parameterDescriptors={"); 228 for (ParameterDescriptor pd : this.parameterDescriptors) { 229 sb.append(pd).append(", "); 230 } 231 sb.setLength(sb.length() - 2); 232 sb.append("}"); 233 } 234 } 235 } 236