AccessibleMembersLookup.java revision 1612:0da44ab8c417
1121986Sjhb/* 2121986Sjhb * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. 3121986Sjhb * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4121986Sjhb * 5121986Sjhb * This code is free software; you can redistribute it and/or modify it 6121986Sjhb * under the terms of the GNU General Public License version 2 only, as 7121986Sjhb * published by the Free Software Foundation. Oracle designates this 8121986Sjhb * particular file as subject to the "Classpath" exception as provided 9121986Sjhb * by Oracle in the LICENSE file that accompanied this code. 10121986Sjhb * 11121986Sjhb * This code is distributed in the hope that it will be useful, but WITHOUT 12121986Sjhb * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13121986Sjhb * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14121986Sjhb * version 2 for more details (a copy is included in the LICENSE file that 15121986Sjhb * accompanied this code). 16121986Sjhb * 17121986Sjhb * You should have received a copy of the GNU General Public License version 18121986Sjhb * 2 along with this work; if not, write to the Free Software Foundation, 19121986Sjhb * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20121986Sjhb * 21121986Sjhb * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22121986Sjhb * or visit www.oracle.com if you need additional information or have any 23121986Sjhb * questions. 24121986Sjhb */ 25121986Sjhb 26121986Sjhb/* 27121986Sjhb * This file is available under and governed by the GNU General Public 28121986Sjhb * License version 2 only, as published by the Free Software Foundation. 29121986Sjhb * However, the following notice accompanied the original version of this 30121986Sjhb * file, and Oracle licenses the original version of this file under the BSD 31121986Sjhb * license: 32121986Sjhb */ 33121986Sjhb/* 34121986Sjhb Copyright 2009-2013 Attila Szegedi 35121986Sjhb 36121986Sjhb Licensed under both the Apache License, Version 2.0 (the "Apache License") 37121986Sjhb and the BSD License (the "BSD License"), with licensee being free to 38121986Sjhb choose either of the two at their discretion. 39121986Sjhb 40121986Sjhb You may not use this file except in compliance with either the Apache 41121986Sjhb License or the BSD License. 42121986Sjhb 43121986Sjhb If you choose to use this file in compliance with the Apache License, the 44121986Sjhb following notice applies to you: 45121986Sjhb 46121986Sjhb You may obtain a copy of the Apache License at 47121986Sjhb 48121986Sjhb http://www.apache.org/licenses/LICENSE-2.0 49121986Sjhb 50121986Sjhb Unless required by applicable law or agreed to in writing, software 51121986Sjhb distributed under the License is distributed on an "AS IS" BASIS, 52121986Sjhb WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 53121986Sjhb implied. See the License for the specific language governing 54121986Sjhb permissions and limitations under the License. 55121986Sjhb 56121986Sjhb If you choose to use this file in compliance with the BSD License, the 57121986Sjhb following notice applies to you: 58122124Sjhb 59122124Sjhb Redistribution and use in source and binary forms, with or without 60122124Sjhb modification, are permitted provided that the following conditions are 61122124Sjhb met: 62121986Sjhb * Redistributions of source code must retain the above copyright 63121986Sjhb notice, this list of conditions and the following disclaimer. 64121986Sjhb * Redistributions in binary form must reproduce the above copyright 65121986Sjhb notice, this list of conditions and the following disclaimer in the 66121986Sjhb documentation and/or other materials provided with the distribution. 67121986Sjhb * Neither the name of the copyright holder nor the names of 68121986Sjhb contributors may be used to endorse or promote products derived from 69121986Sjhb this software without specific prior written permission. 70121986Sjhb 71121986Sjhb THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 72121986Sjhb IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 73121986Sjhb TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 74121986Sjhb PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 75121986Sjhb BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 76121986Sjhb CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 77121986Sjhb SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 78121986Sjhb BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 79121986Sjhb WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 80121986Sjhb OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 81121986Sjhb ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82121986Sjhb*/ 83121986Sjhb 84121986Sjhbpackage jdk.dynalink.beans; 85121986Sjhb 86121986Sjhbimport java.lang.reflect.Method; 87121986Sjhbimport java.lang.reflect.Modifier; 88121986Sjhbimport java.util.Arrays; 89121986Sjhbimport java.util.Collection; 90121986Sjhbimport java.util.HashMap; 91121986Sjhbimport java.util.LinkedHashSet; 92121986Sjhbimport java.util.Map; 93121986Sjhbimport java.util.Set; 94121986Sjhb 95121986Sjhb/** 96122124Sjhb * Utility class for discovering accessible methods and inner classes. Normally, a public member declared on a class is 97122124Sjhb * accessible (that is, it can be invoked from anywhere). However, this is not the case if the class itself is not 98122124Sjhb * public, or belongs to a restricted-access package. In that case, it is required to lookup a member in a publicly 99122124Sjhb * accessible superclass or implemented interface of the class, and use it instead of the member discovered on the 100122124Sjhb * class. 101121986Sjhb */ 102130980Sjhbclass AccessibleMembersLookup { 103121986Sjhb private final Map<MethodSignature, Method> methods; 104121986Sjhb private final Set<Class<?>> innerClasses; 105121986Sjhb private final boolean instance; 106121986Sjhb 107121986Sjhb /** 108121986Sjhb * Creates a mapping for all accessible methods and inner classes on a class. 109121986Sjhb * 110121986Sjhb * @param clazz the inspected class 111121986Sjhb * @param instance true to inspect instance methods, false to inspect static methods. 112121986Sjhb */ 113121986Sjhb AccessibleMembersLookup(final Class<?> clazz, final boolean instance) { 114121986Sjhb this.methods = new HashMap<>(); 115121986Sjhb this.innerClasses = new LinkedHashSet<>(); 116121986Sjhb this.instance = instance; 117121986Sjhb lookupAccessibleMembers(clazz); 118130980Sjhb } 119130980Sjhb 120121986Sjhb /** 121133017Sscottl * Returns an accessible method equivalent of a method. 122121986Sjhb * 123121986Sjhb * @param m the method whose accessible equivalent is requested. 124121986Sjhb * @return the accessible equivalent for the method (can be the same as the passed in method), or null if there is 125121986Sjhb * no accessible method equivalent. 126128931Sjhb */ 127128931Sjhb Method getAccessibleMethod(final Method m) { 128121986Sjhb return m == null ? null : methods.get(new MethodSignature(m)); 129121986Sjhb } 130121986Sjhb 131129964Sjhb Collection<Method> getMethods() { 132121986Sjhb return methods.values(); 133121986Sjhb } 134129097Sjhb 135121986Sjhb Class<?>[] getInnerClasses() { 136121986Sjhb return innerClasses.toArray(new Class<?>[0]); 137121986Sjhb } 138128931Sjhb 139128931Sjhb /** 140121986Sjhb * A helper class that represents a method signature - name and argument types. 141129964Sjhb */ 142129097Sjhb static final class MethodSignature { 143129097Sjhb private final String name; 144129097Sjhb private final Class<?>[] args; 145129097Sjhb 146129097Sjhb /** 147129097Sjhb * Creates a new method signature from arbitrary data. 148129097Sjhb * 149121986Sjhb * @param name the name of the method this signature represents. 150133017Sscottl * @param args the argument types of the method. 151133017Sscottl */ 152133017Sscottl MethodSignature(final String name, final Class<?>[] args) { 153133017Sscottl this.name = name; 154133017Sscottl this.args = args; 155133017Sscottl } 156121986Sjhb 157121986Sjhb /** 158121986Sjhb * Creates a signature for the given method. 159121986Sjhb * 160121986Sjhb * @param method the method for which a signature is created. 161121986Sjhb */ 162121986Sjhb MethodSignature(final Method method) { 163121986Sjhb this(method.getName(), method.getParameterTypes()); 164121986Sjhb } 165121986Sjhb 166121986Sjhb /** 167121986Sjhb * Compares this object to another object 168121986Sjhb * 169121986Sjhb * @param o the other object 170121986Sjhb * @return true if the other object is also a method signature with the same name, same number of arguments, and 171121986Sjhb * same types of arguments. 172121986Sjhb */ 173121986Sjhb @Override 174130980Sjhb public boolean equals(final Object o) { 175130980Sjhb if(o instanceof MethodSignature) { 176130980Sjhb final MethodSignature ms = (MethodSignature)o; 177130980Sjhb return ms.name.equals(name) && Arrays.equals(args, ms.args); 178130980Sjhb } 179130980Sjhb return false; 180130980Sjhb } 181130980Sjhb 182130980Sjhb /** 183130980Sjhb * Returns a hash code, consistent with the overridden {@link #equals(Object)}. 184130980Sjhb */ 185130980Sjhb @Override 186130980Sjhb public int hashCode() { 187130980Sjhb return name.hashCode() ^ Arrays.hashCode(args); 188130980Sjhb } 189130980Sjhb 190121986Sjhb @Override 191130980Sjhb public String toString() { 192130980Sjhb final StringBuilder b = new StringBuilder(); 193130980Sjhb b.append("[MethodSignature ").append(name).append('('); 194130980Sjhb if(args.length > 0) { 195130980Sjhb b.append(args[0].getCanonicalName()); 196130980Sjhb for(int i = 1; i < args.length; ++i) { 197130980Sjhb b.append(", ").append(args[i].getCanonicalName()); 198130980Sjhb } 199130980Sjhb } 200130980Sjhb return b.append(")]").toString(); 201130980Sjhb } 202130980Sjhb } 203130980Sjhb 204130980Sjhb private void lookupAccessibleMembers(final Class<?> clazz) { 205130980Sjhb boolean searchSuperTypes; 206130980Sjhb 207130980Sjhb if(!CheckRestrictedPackage.isRestrictedClass(clazz)) { 208130980Sjhb searchSuperTypes = false; 209130980Sjhb for(final Method method: clazz.getMethods()) { 210130980Sjhb final boolean isStatic = Modifier.isStatic(method.getModifiers()); 211130980Sjhb if(instance != isStatic) { 212130980Sjhb final MethodSignature sig = new MethodSignature(method); 213130980Sjhb if(!methods.containsKey(sig)) { 214121986Sjhb final Class<?> declaringClass = method.getDeclaringClass(); 215121986Sjhb if(declaringClass != clazz && CheckRestrictedPackage.isRestrictedClass(declaringClass)) { 216121986Sjhb //Sometimes, the declaring class of a method (Method.getDeclaringClass()) 217121986Sjhb //retrieved through Class.getMethods() for a public class will be a 218121986Sjhb //non-public superclass. For such a method, we need to find a method with 219121986Sjhb //the same name and signature in a public superclass or implemented 220121986Sjhb //interface. 221121986Sjhb //This typically doesn't happen with classes emitted by a reasonably modern 222121986Sjhb //javac, as it'll create synthetic delegator methods in all public 223121986Sjhb //immediate subclasses of the non-public class. We have, however, observed 224121986Sjhb //this in the wild with class files compiled with older javac that doesn't 225121986Sjhb //generate the said synthetic delegators. 226121986Sjhb searchSuperTypes = true; 227121986Sjhb } else { 228121986Sjhb // don't allow inherited static 229121986Sjhb if (!isStatic || clazz == declaringClass) { 230121986Sjhb methods.put(sig, method); 231121986Sjhb } 232121986Sjhb } 233133017Sscottl } 234121986Sjhb } 235121986Sjhb } 236121986Sjhb for(final Class<?> innerClass: clazz.getClasses()) { 237121986Sjhb // Add both static and non-static classes, regardless of instance flag. StaticClassLinker will just 238121986Sjhb // expose non-static classes with explicit constructor outer class argument. 239121986Sjhb // NOTE: getting inner class objects through getClasses() does not resolve them, so if those classes 240121986Sjhb // were not yet loaded, they'll only get loaded in a non-resolved state; no static initializers for 241121986Sjhb // them will trigger just by doing this. 242121986Sjhb innerClasses.add(innerClass); 243121986Sjhb } 244121986Sjhb } else { 245121986Sjhb searchSuperTypes = true; 246121986Sjhb } 247121986Sjhb 248133017Sscottl // don't need to search super types for static methods 249133017Sscottl if(instance && searchSuperTypes) { 250133017Sscottl // If we reach here, the class is either not public, or it is in a restricted package. Alternatively, it is 251133017Sscottl // public, but some of its methods claim that their declaring class is non-public. We'll try superclasses 252121986Sjhb // and implemented interfaces then looking for public ones. 253121986Sjhb final Class<?>[] interfaces = clazz.getInterfaces(); 254121986Sjhb for(int i = 0; i < interfaces.length; i++) { 255121986Sjhb lookupAccessibleMembers(interfaces[i]); 256121986Sjhb } 257121986Sjhb final Class<?> superclass = clazz.getSuperclass(); 258122148Sjhb if(superclass != null) { 259133017Sscottl lookupAccessibleMembers(superclass); 260121986Sjhb } 261121986Sjhb } 262121986Sjhb } 263129964Sjhb} 264129964Sjhb