Link to home
Start Free TrialLog in
Avatar of chochomhaloimed
chochomhaloimed

asked on

Classes of Package

Let say I have a package name, for example "java.util". Or I have a valid Package object that coresponds to the package.

All I want is to get Classes of that Package, for example as Class[] or any other way.

If you believe that is not acievable, is the a way to get all Classes currenly loaded into VM.
Avatar of Nachiap
Nachiap

I think you have to write your own customised class loader
you have to over write loadClass() method..
Hi,

you might not even know what classes are loadable. As long as classes arent loaded, the VM doesnt know if they exist or not. This depends on where your ClassLoader gets its class files from. Imagine a ClassLoader that makes a network broadcast to check if any computer on the network has this class.

So you will have to write your own ClassLoader to achieve this.

Concering "java.util", there is a little difference. Classes can only be in the java package if they actually in the CLASSATH. They cannot be loaded anywhere else. (Try to make your own class in java.util and place it in the CLASSPATH and then try to access it from an applet via network. First will work, second will not). So the amount of classes in java.util is constant.

the Java Exorcist
Umm, exorcist, I'm not 100% sure, but I think you're wrong - I don't think the java.* classes get any special treatment from any actual code.

Sasha Maryanovsky.
Hi Sasha,

ok, I was wrong. But just a little bit.
the java.* classes DO get a special treatment. Try following program:

package java.util;

public class ClassTest{

    public static void main(String args[]) {

     System.out.println("working");
    }
}

It will compile just fine, but when started a SecurityException will be thrown (Prohibited package name).

That was the part i was right about.

What I was wrong about, was the part when I said that putting it in the CLASSPATH would help. It doesn't.

So you aren't allowed to declare classes in package java.* no matter what ClassLoader you use.

As for javax.* I am not sure if there are any rules. But this program worked when put in package javax.util

already got a job?
Sasha,

the point is not the package java.* or sun.* the difference comes from different class loaders.
In one case the "filesytem"-classloader is used in the other cas a "Network"-Classloader.
As I know the URLClassloader used in applets has
build in security restrictions, normally you cannot
load classes from packages starting with java. or sun.
over the network for obvious reasons.
Todo this you need to implement a SecurtityManager and
have to sign your applet and the user has to grant the needed rights to the applet.
I'm not sure what happens, if you use URLClassLoader from outside of the sandbox.

cheers
jf
Sasha,

the point is not the package java.* or sun.* the difference comes from different class loaders.
In one case the "filesytem"-classloader is used in the other cas a "Network"-Classloader.
As I know the URLClassloader used in applets has
build in security restrictions, normally you cannot
load classes from packages starting with java. or sun.
over the network for obvious reasons.
Todo this you need to implement a SecurtityManager and
have to sign your applet and the user has to grant the needed rights to the applet.
I'm not sure what happens, if you use URLClassLoader from outside of the sandbox.

cheers
jf
Sorry,

stupid browsers let me submit the comment twice
Sasha,

isn't it possible to setup something in a policy file
to allow the use of restricted package names ?
nope.
Sasha,

isn't it possible to setup something in a policy file
to allow the use of restricted package names ?
I think this is hard-coded.
The program I posted above runs as an application and not applet. So I already have the least possible security, i.e. I am actually allowed everything that is allowable. Try it and you will see that it throws a SecurityException no matter what permissions you allow in the policy file.
Avatar of chochomhaloimed

ASKER

Ok, the thinking is going wrong direction.

I do not care to customize java.util. I brought it as example, I should have bring as example com.my.bla

I do not care about classes that are not loaded. The assumption is, that Package I am intersted about is loaded.

Or, if it easier task, how to get all classes loaded into VM (from classpath, perhaps)
chochomhaloimed , like nachiap said, if you use your own classloader, all the classes will be loaded through it, which will allow you to monitor them.

Exorcist, I still think you're wrong, I'll try it tomorrow.
It could be that what you are seeing is something Sun put in their JVM, but I don't think it's a general restriction on JVMs, because there are many vendors that implement their own core classes, independently from Sun.

Falter, you are correct... the permissions aren't given by class names, but by the class loaders. As for your question, like I said, I think you can just load java.* classes without any problem... The thing is that when you're loading an applet, you have no control over the classpath or bootclasspath, so the default core classes will always be loaded since the bootstrap (null) classloader finds them. Anyway, I'll do some testing tomorrow to check this...

Sasha Maryanovsky.
Sasha, show me exactly what methods, and how(code) I should extend from ClassLoader to get what I want. And you will get your 300 with an A, if this will prove working.
chochomhaloimed,

I believe that ClassLoader modification is not necessary. For standalone application you need to check entries found in system properties "java.class.path" and "sun.boot.class.path" (if I'm not mistaken) and look for .class files there which map to your package. There is no generic solution--class loader may take classes wherever it likes from, and that sources may even not support listings. Imagine classes loaded from 'blind' ftp or http location--location where directory listing is prohibited. There will be no way to find list of classes in such (hardly possible) situation.

As for java/javax namespace extensions--yes, it's security issue. I didn't look into this precise problem, but I had problems loading classes from javax namespace and security adjustments solved the problem. Probably, some twaking of package 'sealed' state is necessary.

Regards,
Igor Bazarny,
Brainbench MVP for Java 1
www.brainbench.com 
ASKER CERTIFIED SOLUTION
Avatar of Sasha_Mapa
Sasha_Mapa

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
And here is a way to list classes loadable by default classloader:


import java.util.*;
import java.util.zip.*;
import java.io.*;

public class ListClasses{
    public static void main(String[] args){
        if( args.length == 0 ){
            System.out.println("Package name expected");
            return;
        }
        String pkg = args[0];
        ListClasses lister = new ListClasses(pkg);
        lister.list("sun.boot.class.path");
        lister.list("java.class.path");
    }

    private Hashtable listed = new Hashtable();
    private String packageName;

    ListClasses(String pkg){
        packageName = pkg;
    }

    void list(String propertyName){
        String path = System.getProperty(propertyName);
        if(path == null){
            System.out.println(propertyName);
            return;
        }
        for( StringTokenizer entryEnum = new StringTokenizer(path,File.pathSeparator);
             entryEnum.hasMoreTokens();   )
        {
             listEntry(entryEnum.nextToken());
        }
    }

    void listEntry(String entryName){
        File entryFile = new File(entryName);
        if( !entryFile.exists() ){
            return;
        }
        if( entryFile.isDirectory() ){
            listDirectory(entryFile);
        }
        else{
            listArchive(entryFile);
        }
    }

    void listDirectory(File root){
        String relativePath = packageName.replace('.', File.separatorChar);
        File packageDir = new File(root, relativePath);
        if( !packageDir.exists() || !packageDir.isDirectory() ){
            return;
        }
        String[] files=packageDir.list();
        for( int i=0; i<files.length; ++i){
            if( files[i].endsWith(".class")
                && !(new File(packageDir,files[i]).isDirectory()))
            {
                String className
                   = files[i].substring(0,files[i].length()-".class".length());
                if(listed.get(className) == null){
                    System.out.println(className);
                    listed.put(className,className);
                }
            }
        }
    }

    void listArchive(File archive){
        try{
            ZipFile zipFile = new ZipFile(archive);
            String relPath = packageName.replace('.','/')+"/";
            int pathLen = relPath.length();
            for( Enumeration entryEnum = zipFile.entries();
                 entryEnum.hasMoreElements(); )
            {
                ZipEntry entry = (ZipEntry)entryEnum.nextElement();
                String entryName = entry.getName();
                if( entryName.startsWith(relPath)
                    && entryName.length() > pathLen
                    && entryName.indexOf("/",pathLen) < 0
                    && entryName.endsWith(".class") )
                {
                    String className
                       = entryName.substring(pathLen,entryName.length()-".class".length());
                    if(listed.get(className) == null){
                        System.out.println(className);
                        listed.put(className,className);
                    }
                }
            }
        }
        catch(IOException ignored){
        }
    }
}
Note that bazarny's suggestion lists all the class files loadable by the bootstrap classloader (on a Sun JVM) and my suggestion allows keeping record of the classes that were actually loaded by the JVM - not sure which you want...

Sasha Maryanovsky.
Ok, trying to load a java.util.SomeClass class in JDK1.1 works fine. In 1.2, it throws a SecurityException if run the usual way - if run using "java -Xbootclasspath/p:. Test" then also runs fine. I suspect this is because of the "sealing packages" functionality added in JDK1.2 - it's possible to package a JAR file in such a manner that any children classloaders of the classloader that loaded that jar aren't allowed to define classes in any of the packages defined by classes in that jar. Since this is exactly the case with rt.jar, you can't load a java.* class the usual way, but if you prepend (or even append, what matters is that the bootstrap classloader is asked to load it) its location to the bootclasspath, then it works fine.

Sasha Maryanovsky.
Hi,

Isn't security issues are offtopic for this question?
When we ran into similar problem with classes from javax.<something> package (we got NoClassDefFoundError though), I where able to load that class:
- from bootclasspath without security modifications
- from .jar in jre/lib/ext dir without security modifications
- from classpath with AllPermission granted to anyone.
And we dicided to use -bootclasspath to load those classes.

Regards,
Igor Bazarny

PS. chochomhaloimed, are you satisfied with answers? Do you
need some more information? Or you can grant points?
I was away plus the server was down, so I just got the chance to review the answers. I will act shortly
Both solutions have its advantages and disadvantages, and both are legitamate answers for my question. Do you know if it is possible to accept two comments as an answer?
Hi,

> Do you know if it is possible to accept two comments as an answer?
For one question-no.
Typically it's done by submitting dummy question for one of experts and awarding points to another. You can't decrease points yourself to 'split' amout though. Contact EE support--they help to resolve such situations.
bazarny, i had posted for you a dummy question : dummy for bazarny
Thanks for the points (and the grade)...

Sasha Maryanovsky.