简体   繁体   中英

Access package-private variables using reserved package name

I was studying the source code of java.util.HashMap and I wanted to see how well the hashcode function distributes the key's in the internal array of Entry 's( which is a package private variable ).So I made a package named java.util in my project just to check weather I can fool the compiler to think it's the same package.Surprisingly it worked and I wrote the following code:

package java.util;

public class HashMapExt<K, V> extends HashMap<K, V> implements Map<K, V> {

    public static void main(String[] args) {
        HashMapExt<Integer, String> mp = new HashMapExt<Integer, String>();
        mp.put(1, "Hello");
        mp.put(2, "Map");
        mp.put(3, "Extention");
        mp.printData();
    }

    void printData() {

        System.out.println(Arrays.toString(table));
    }
}

It compiled successfully but while running it gave an exception:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.util
    at java.lang.ClassLoader.preDefineClass(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$000(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)

Now the question is, is it possible to change the default security model so that I can access the internal variable table or is there any other alternative ( maybe by using reflection ) ?

Even if there is an option to have your class in the java.util package (like replacing the core jar or defining your custom class loader for example), you'd better use reflection. It is simple and straightforward:

Field tableField = HashMap.class.getDeclaredField("table");
tableField.setAccessible(true);
Map.Entry[] entries = (Map.Entry[]) tableField.get(yourMap);

You may try either prepending your jar in the classpath or by using an endorsed directory .

The former:

java -Xbootclasspath/p:youJarHere.jar  ..... 

And the effect is, to load first the classes you have in yourJar, even overriding core classes.

The later form is to place in your $JAVA_HOME/lib/endorsed directory the classes/jars, it has a similar effect.

I haven't used any of these for a couple of years, but I used them once to replace a core class ( something in the CORBA package or something like that ).

Give it a try and let us know if it worked.

Here some links:

http://blogs.sourceallies.com/2010/02/replacing-and-patching-java-application-and-core-classes/

http://download.oracle.com/javase/6/docs/technotes/guides/standards/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM