Save This Page
Home » openjdk-7 » sun » reflect » [javadoc | source]
    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   
   38       /** Used to filter out fields and methods from certain classes from public
   39           view, where they are sensitive or they may contain VM-internal objects.
   40           These Maps are updated very rarely. Rather than synchronize on
   41           each access, we use copy-on-write */
   42       private static volatile Map<Class,String[]> fieldFilterMap;
   43       private static volatile Map<Class,String[]> methodFilterMap;
   44   
   45       static {
   46           Map<Class,String[]> map = new HashMap<Class,String[]>();
   47           map.put(Reflection.class,
   48               new String[] {"fieldFilterMap", "methodFilterMap"});
   49           map.put(System.class, new String[] {"security"});
   50           fieldFilterMap = map;
   51   
   52           methodFilterMap = new HashMap<Class,String[]>();
   53       }
   54   
   55       /** Returns the class of the method <code>realFramesToSkip</code>
   56           frames up the stack (zero-based), ignoring frames associated
   57           with java.lang.reflect.Method.invoke() and its implementation.
   58           The first frame is that associated with this method, so
   59           <code>getCallerClass(0)</code> returns the Class object for
   60           sun.reflect.Reflection. Frames associated with
   61           java.lang.reflect.Method.invoke() and its implementation are
   62           completely ignored and do not count toward the number of "real"
   63           frames skipped. */
   64       public static native Class getCallerClass(int realFramesToSkip);
   65   
   66       /** Retrieves the access flags written to the class file. For
   67           inner classes these flags may differ from those returned by
   68           Class.getModifiers(), which searches the InnerClasses
   69           attribute to find the source-level access flags. This is used
   70           instead of Class.getModifiers() for run-time access checks due
   71           to compatibility reasons; see 4471811. Only the values of the
   72           low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be
   73           valid. */
   74       private static native int getClassAccessFlags(Class c);
   75   
   76       /** A quick "fast-path" check to try to avoid getCallerClass()
   77           calls. */
   78       public static boolean quickCheckMemberAccess(Class memberClass,
   79                                                    int modifiers)
   80       {
   81           return Modifier.isPublic(getClassAccessFlags(memberClass) & modifiers);
   82       }
   83   
   84       public static void ensureMemberAccess(Class currentClass,
   85                                             Class memberClass,
   86                                             Object target,
   87                                             int modifiers)
   88           throws IllegalAccessException
   89       {
   90           if (currentClass == null || memberClass == null) {
   91               throw new InternalError();
   92           }
   93   
   94           if (!verifyMemberAccess(currentClass, memberClass, target, modifiers)) {
   95               throw new IllegalAccessException("Class " + currentClass.getName() +
   96                                                " can not access a member of class " +
   97                                                memberClass.getName() +
   98                                                " with modifiers \"" +
   99                                                Modifier.toString(modifiers) +
  100                                                "\"");
  101           }
  102       }
  103   
  104       public static boolean verifyMemberAccess(Class currentClass,
  105                                                // Declaring class of field
  106                                                // or method
  107                                                Class  memberClass,
  108                                                // May be NULL in case of statics
  109                                                Object target,
  110                                                int    modifiers)
  111       {
  112           // Verify that currentClass can access a field, method, or
  113           // constructor of memberClass, where that member's access bits are
  114           // "modifiers".
  115   
  116           boolean gotIsSameClassPackage = false;
  117           boolean isSameClassPackage = false;
  118   
  119           if (currentClass == memberClass) {
  120               // Always succeeds
  121               return true;
  122           }
  123   
  124           if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
  125               isSameClassPackage = isSameClassPackage(currentClass, memberClass);
  126               gotIsSameClassPackage = true;
  127               if (!isSameClassPackage) {
  128                   return false;
  129               }
  130           }
  131   
  132           // At this point we know that currentClass can access memberClass.
  133   
  134           if (Modifier.isPublic(modifiers)) {
  135               return true;
  136           }
  137   
  138           boolean successSoFar = false;
  139   
  140           if (Modifier.isProtected(modifiers)) {
  141               // See if currentClass is a subclass of memberClass
  142               if (isSubclassOf(currentClass, memberClass)) {
  143                   successSoFar = true;
  144               }
  145           }
  146   
  147           if (!successSoFar && !Modifier.isPrivate(modifiers)) {
  148               if (!gotIsSameClassPackage) {
  149                   isSameClassPackage = isSameClassPackage(currentClass,
  150                                                           memberClass);
  151                   gotIsSameClassPackage = true;
  152               }
  153   
  154               if (isSameClassPackage) {
  155                   successSoFar = true;
  156               }
  157           }
  158   
  159           if (!successSoFar) {
  160               return false;
  161           }
  162   
  163           if (Modifier.isProtected(modifiers)) {
  164               // Additional test for protected members: JLS 6.6.2
  165               Class targetClass = (target == null ? memberClass : target.getClass());
  166               if (targetClass != currentClass) {
  167                   if (!gotIsSameClassPackage) {
  168                       isSameClassPackage = isSameClassPackage(currentClass, memberClass);
  169                       gotIsSameClassPackage = true;
  170                   }
  171                   if (!isSameClassPackage) {
  172                       if (!isSubclassOf(targetClass, currentClass)) {
  173                           return false;
  174                       }
  175                   }
  176               }
  177           }
  178   
  179           return true;
  180       }
  181   
  182       private static boolean isSameClassPackage(Class c1, Class c2) {
  183           return isSameClassPackage(c1.getClassLoader(), c1.getName(),
  184                                     c2.getClassLoader(), c2.getName());
  185       }
  186   
  187       /** Returns true if two classes are in the same package; classloader
  188           and classname information is enough to determine a class's package */
  189       private static boolean isSameClassPackage(ClassLoader loader1, String name1,
  190                                                 ClassLoader loader2, String name2)
  191       {
  192           if (loader1 != loader2) {
  193               return false;
  194           } else {
  195               int lastDot1 = name1.lastIndexOf('.');
  196               int lastDot2 = name2.lastIndexOf('.');
  197               if ((lastDot1 == -1) || (lastDot2 == -1)) {
  198                   // One of the two doesn't have a package.  Only return true
  199                   // if the other one also doesn't have a package.
  200                   return (lastDot1 == lastDot2);
  201               } else {
  202                   int idx1 = 0;
  203                   int idx2 = 0;
  204   
  205                   // Skip over '['s
  206                   if (name1.charAt(idx1) == '[') {
  207                       do {
  208                           idx1++;
  209                       } while (name1.charAt(idx1) == '[');
  210                       if (name1.charAt(idx1) != 'L') {
  211                           // Something is terribly wrong.  Shouldn't be here.
  212                           throw new InternalError("Illegal class name " + name1);
  213                       }
  214                   }
  215                   if (name2.charAt(idx2) == '[') {
  216                       do {
  217                           idx2++;
  218                       } while (name2.charAt(idx2) == '[');
  219                       if (name2.charAt(idx2) != 'L') {
  220                           // Something is terribly wrong.  Shouldn't be here.
  221                           throw new InternalError("Illegal class name " + name2);
  222                       }
  223                   }
  224   
  225                   // Check that package part is identical
  226                   int length1 = lastDot1 - idx1;
  227                   int length2 = lastDot2 - idx2;
  228   
  229                   if (length1 != length2) {
  230                       return false;
  231                   }
  232                   return name1.regionMatches(false, idx1, name2, idx2, length1);
  233               }
  234           }
  235       }
  236   
  237       static boolean isSubclassOf(Class queryClass,
  238                                   Class ofClass)
  239       {
  240           while (queryClass != null) {
  241               if (queryClass == ofClass) {
  242                   return true;
  243               }
  244               queryClass = queryClass.getSuperclass();
  245           }
  246           return false;
  247       }
  248   
  249       // fieldNames must contain only interned Strings
  250       public static synchronized void registerFieldsToFilter(Class containingClass,
  251                                                 String ... fieldNames) {
  252           fieldFilterMap =
  253               registerFilter(fieldFilterMap, containingClass, fieldNames);
  254       }
  255   
  256       // methodNames must contain only interned Strings
  257       public static synchronized void registerMethodsToFilter(Class containingClass,
  258                                                 String ... methodNames) {
  259           methodFilterMap =
  260               registerFilter(methodFilterMap, containingClass, methodNames);
  261       }
  262   
  263       private static Map<Class,String[]> registerFilter(Map<Class,String[]> map,
  264               Class containingClass, String ... names) {
  265           if (map.get(containingClass) != null) {
  266               throw new IllegalArgumentException
  267                               ("Filter already registered: " + containingClass);
  268           }
  269           map = new HashMap<Class,String[]>(map);
  270           map.put(containingClass, names);
  271           return map;
  272       }
  273   
  274       public static Field[] filterFields(Class containingClass,
  275                                          Field[] fields) {
  276           if (fieldFilterMap == null) {
  277               // Bootstrapping
  278               return fields;
  279           }
  280           return (Field[])filter(fields, fieldFilterMap.get(containingClass));
  281       }
  282   
  283       public static Method[] filterMethods(Class containingClass, Method[] methods) {
  284           if (methodFilterMap == null) {
  285               // Bootstrapping
  286               return methods;
  287           }
  288           return (Method[])filter(methods, methodFilterMap.get(containingClass));
  289       }
  290   
  291       private static Member[] filter(Member[] members, String[] filteredNames) {
  292           if ((filteredNames == null) || (members.length == 0)) {
  293               return members;
  294           }
  295           int numNewMembers = 0;
  296           for (Member member : members) {
  297               boolean shouldSkip = false;
  298               for (String filteredName : filteredNames) {
  299                   if (member.getName() == filteredName) {
  300                       shouldSkip = true;
  301                       break;
  302                   }
  303               }
  304               if (!shouldSkip) {
  305                   ++numNewMembers;
  306               }
  307           }
  308           Member[] newMembers =
  309               (Member[])Array.newInstance(members[0].getClass(), numNewMembers);
  310           int destIdx = 0;
  311           for (Member member : members) {
  312               boolean shouldSkip = false;
  313               for (String filteredName : filteredNames) {
  314                   if (member.getName() == filteredName) {
  315                       shouldSkip = true;
  316                       break;
  317                   }
  318               }
  319               if (!shouldSkip) {
  320                   newMembers[destIdx++] = member;
  321               }
  322           }
  323           return newMembers;
  324       }
  325   }

Save This Page
Home » openjdk-7 » sun » reflect » [javadoc | source]