Home | History | Annotate | Download | only in reflect
      1 /*
      2  * Copyright (c) 2001, 2013, 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 sun.reflect;
     27 
     28 import java.lang.reflect.*;
     29 import java.util.Collections;
     30 import java.util.HashMap;
     31 import java.util.Map;
     32 
     33 /** Common utility routines used by both java.lang and
     34     java.lang.reflect */
     35 
     36 public class Reflection {
     37 
     38     // Android-removed: Dead code: Misc unused fields and methods.
     39 
     40     public static void ensureMemberAccess(Class<?> currentClass,
     41                                           Class<?> memberClass,
     42                                           Object target,
     43                                           int modifiers)
     44         throws IllegalAccessException
     45     {
     46         if (currentClass == null || memberClass == null) {
     47             throw new InternalError();
     48         }
     49 
     50         if (!verifyMemberAccess(currentClass, memberClass, target, modifiers)) {
     51             throw new IllegalAccessException("Class " + currentClass.getName() +
     52                                              " can not access a member of class " +
     53                                              memberClass.getName() +
     54                                              " with modifiers \"" +
     55                                              Modifier.toString(modifiers) +
     56                                              "\"");
     57         }
     58     }
     59 
     60     public static boolean verifyMemberAccess(Class<?> currentClass,
     61                                              // Declaring class of field
     62                                              // or method
     63                                              Class<?> memberClass,
     64                                              // May be NULL in case of statics
     65                                              Object   target,
     66                                              int      modifiers)
     67     {
     68         // Verify that currentClass can access a field, method, or
     69         // constructor of memberClass, where that member's access bits are
     70         // "modifiers".
     71 
     72         boolean gotIsSameClassPackage = false;
     73         boolean isSameClassPackage = false;
     74 
     75         if (currentClass == memberClass) {
     76             // Always succeeds
     77             return true;
     78         }
     79 
     80         // Android-changed
     81         // if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
     82         if (!Modifier.isPublic(memberClass.getAccessFlags())) {
     83             isSameClassPackage = isSameClassPackage(currentClass, memberClass);
     84             gotIsSameClassPackage = true;
     85             if (!isSameClassPackage) {
     86                 return false;
     87             }
     88         }
     89 
     90         // At this point we know that currentClass can access memberClass.
     91 
     92         if (Modifier.isPublic(modifiers)) {
     93             return true;
     94         }
     95 
     96         boolean successSoFar = false;
     97 
     98         if (Modifier.isProtected(modifiers)) {
     99             // See if currentClass is a subclass of memberClass
    100             if (isSubclassOf(currentClass, memberClass)) {
    101                 successSoFar = true;
    102             }
    103         }
    104 
    105         if (!successSoFar && !Modifier.isPrivate(modifiers)) {
    106             if (!gotIsSameClassPackage) {
    107                 isSameClassPackage = isSameClassPackage(currentClass,
    108                                                         memberClass);
    109                 gotIsSameClassPackage = true;
    110             }
    111 
    112             if (isSameClassPackage) {
    113                 successSoFar = true;
    114             }
    115         }
    116 
    117         if (!successSoFar) {
    118             return false;
    119         }
    120 
    121         if (Modifier.isProtected(modifiers)) {
    122             // Additional test for protected members: JLS 6.6.2
    123             Class<?> targetClass = (target == null ? memberClass : target.getClass());
    124             if (targetClass != currentClass) {
    125                 if (!gotIsSameClassPackage) {
    126                     isSameClassPackage = isSameClassPackage(currentClass, memberClass);
    127                     gotIsSameClassPackage = true;
    128                 }
    129                 if (!isSameClassPackage) {
    130                     if (!isSubclassOf(targetClass, currentClass)) {
    131                         return false;
    132                     }
    133                 }
    134             }
    135         }
    136 
    137         return true;
    138     }
    139 
    140     private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) {
    141         return isSameClassPackage(c1.getClassLoader(), c1.getName(),
    142                                   c2.getClassLoader(), c2.getName());
    143     }
    144 
    145     /** Returns true if two classes are in the same package; classloader
    146         and classname information is enough to determine a class's package */
    147     private static boolean isSameClassPackage(ClassLoader loader1, String name1,
    148                                               ClassLoader loader2, String name2)
    149     {
    150         if (loader1 != loader2) {
    151             return false;
    152         } else {
    153             int lastDot1 = name1.lastIndexOf('.');
    154             int lastDot2 = name2.lastIndexOf('.');
    155             if ((lastDot1 == -1) || (lastDot2 == -1)) {
    156                 // One of the two doesn't have a package.  Only return true
    157                 // if the other one also doesn't have a package.
    158                 return (lastDot1 == lastDot2);
    159             } else {
    160                 int idx1 = 0;
    161                 int idx2 = 0;
    162 
    163                 // Skip over '['s
    164                 if (name1.charAt(idx1) == '[') {
    165                     do {
    166                         idx1++;
    167                     } while (name1.charAt(idx1) == '[');
    168                     if (name1.charAt(idx1) != 'L') {
    169                         // Something is terribly wrong.  Shouldn't be here.
    170                         throw new InternalError("Illegal class name " + name1);
    171                     }
    172                 }
    173                 if (name2.charAt(idx2) == '[') {
    174                     do {
    175                         idx2++;
    176                     } while (name2.charAt(idx2) == '[');
    177                     if (name2.charAt(idx2) != 'L') {
    178                         // Something is terribly wrong.  Shouldn't be here.
    179                         throw new InternalError("Illegal class name " + name2);
    180                     }
    181                 }
    182 
    183                 // Check that package part is identical
    184                 int length1 = lastDot1 - idx1;
    185                 int length2 = lastDot2 - idx2;
    186 
    187                 if (length1 != length2) {
    188                     return false;
    189                 }
    190                 return name1.regionMatches(false, idx1, name2, idx2, length1);
    191             }
    192         }
    193     }
    194 
    195     static boolean isSubclassOf(Class<?> queryClass,
    196                                 Class<?> ofClass)
    197     {
    198         while (queryClass != null) {
    199             if (queryClass == ofClass) {
    200                 return true;
    201             }
    202             queryClass = queryClass.getSuperclass();
    203         }
    204         return false;
    205     }
    206 
    207     // Android-removed: Dead code: Misc unused methods.
    208 
    209 }
    210