• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ensureMemberAccess(Class<?> currentClass, Class<?> memberClass, Object target, int modifiers)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 
verifyMemberAccess(Class<?> currentClass, Class<?> memberClass, Object target, int modifiers)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 
isSameClassPackage(Class<?> c1, Class<?> c2)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 */
isSameClassPackage(ClassLoader loader1, String name1, ClassLoader loader2, String name2)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 
isSubclassOf(Class<?> queryClass, Class<?> ofClass)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