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