4

ClassLoaderを使用して別のプロジェクトのクラスにアクセスしたい。そのクラスへのパスを指定して、そのクラスファイルを取得するにはどうすればよいですか?

アプリケーションを介して多くの異なるクラスファイルをロードし、異なるクラスのパスは絶えず変化するため、コードを介してこれを実行できるようにしたいと思います。

クラスファイルをロードしているCustomClassLoaderを使用していますが、それらがプロジェクトにあり、別のプロジェクトにない場合に限ります

import java.io.FileInputStream;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;

public class CustomClassLoader extends ClassLoader {

String repoLocation = "C:/TempBINfolder/bin/";

public CustomClassLoader() {
}

public CustomClassLoader(ClassLoader parent) {
    super(parent);
}

@Override
protected Class<?> findClass(final String name)
        throws ClassNotFoundException {

    AccessControlContext acc = AccessController.getContext();

    try {
        return (Class) AccessController.doPrivileged(
                new PrivilegedExceptionAction() {

                    public Object run() throws ClassNotFoundException {

                        FileInputStream fi = null;
                        try {

                            String path = name.replace('.', '/');
                            fi = new FileInputStream(repoLocation + path
                                    + ".class");
                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
                            byte[] buffer = new byte[8192]; // a big chunk
                            int read;
                            while ((read = fi.read(buffer)) > 0)
                                baos.write(buffer, 0, read);
                            byte[] classBytes= baos.toByteArray();

                            return defineClass(name, classBytes, 0,
                                    classBytes.length);
                        } catch (Exception e) {
                            throw new ClassNotFoundException(name);
                        }
                    }
                }, acc);
    } catch (java.security.PrivilegedActionException pae) {
        return super.findClass(name);
    }
}
}

クラスを呼び出す

for (Class singleClass : listOfClasses) {
            try {

                ClassLoader classLoader = new CustomClassLoader(ClassLoader.getSystemClassLoader());
                Class stringClass = null;
                try {
                    stringClass = classLoader.loadClass(singleClass.getName());
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger(CompilerForm.class.getName()).log(Level.SEVERE, null, ex);
                }
                try {
                    stringClass.newInstance();
                } catch (InstantiationException ex) {
                    Logger.getLogger(CompilerForm.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(CompilerForm.class.getName()).log(Level.SEVERE, null, ex);
                }


                Class cls = Class.forName(stringClass.getName());

私がやろうとするとClass cls = Class.forName(stringClass.getPackage()+"."+stringClass.getName());、パッケージはnull

編集:以下は私のために働いた

URL classUrl;
classUrl = new URL("file:///"+ccl.getRepoLocation());    //This is location of .class file
URL[] classUrls = {classUrl};
URLClassLoader ucl = new URLClassLoader(classUrls);
Class cls = ucl.loadClass(stringClass.getName());    // Current .class files name
4

3 に答える 3

2

URLClassLoaderを使用してそれを行います。

于 2012-08-20T10:17:58.257 に答える
2

そのコードは良さそうです(私自身もずっと前に似たようなことをしました)。少しバグがありますが:

もし、するなら

byte[] classBytes = new byte[fi.available()];
fi.read(classBytes);

ブロッキングなしで使用可能なバイト数と同じ数のバイトを読み取っているだけです。つまり、ファイル全体を読んでいるわけではありません。実際、readメソッドは、完全なバイトバッファが読み取られることを保証しません。

やってみてください:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192]; // a big chunk
int read;
while ((read = fi.read(buffer)) > 0)
   baos.write(buffer, 0, read);
byte[] bytesClass = baos.toByteArray();

または、ApacheのStreams.copyを使用します。同じことをするのに便利な方法です。

パッケージ定義

ClassLoaderにはdefinePackageメソッドがあります。必要な新しいパッケージごとにそのメソッドを呼び出す必要があると思います。それ以外の場合、ClassLoaderにはパッケージを定義する方法がありませんが、完全なクラス名からではなく、十分ではないようです。

したがって、コードはこれに到達します:

// being package the name of the package for the new class
// being definedPackages a Set<String> member of the classloader

if (!this.definedPackages.contains(package)) {
   definePackage(package,"","","","","","",null);
   this.definedPackages.add(package);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192]; // a big chunk
int read;
while ((read = fi.read(buffer)) > 0)
   baos.write(buffer, 0, read);
byte[] bytesClass = baos.toByteArray();
于 2012-08-20T10:19:53.880 に答える
0

私を助けてくれた上記のコードをありがとう。

SUB:2つの異なる場所で利用可能な同じクラスを呼び出す

クラスパスjarファイルにAbcというクラスがあり、コードを変更してローカルディレクトリに同じクラスAbcを動的に生成します。

インスタンスを作成し、ローカルディレクトリでクラスAbcを使用する必要があります。以下は作業コードです。

class CustomClassLoader extends ClassLoader {

String repoLocation = "./";
//C:/TempBINfolder/bin/
 CustomClassLoader() {
}

 CustomClassLoader(ClassLoader parent) {
    super(parent);
}

@Override
protected Class<?> findClass(final String name)   throws ClassNotFoundException {

    AccessControlContext acc = AccessController.getContext();

    try {
        return (Class) AccessController.doPrivileged(
                new PrivilegedExceptionAction() {

                    public Object run() throws ClassNotFoundException {

                        FileInputStream fi = null;
                        try {

                            String path = name.replace('.', '/');
                            fi = new FileInputStream(repoLocation + path+ ".class");
                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
                            byte[] buffer = new byte[8192]; // a big chunk
                            int read;
                            while ((read = fi.read(buffer)) > 0)
                                baos.write(buffer, 0, read);
                            byte[] classBytes= baos.toByteArray();

                            return defineClass(name, classBytes, 0,
                                    classBytes.length);
                        } catch (Exception e) {
                            throw new ClassNotFoundException(name);
                        }
                    }
                }, acc);
    } catch (java.security.PrivilegedActionException pae) {
        return super.findClass(name);
    }
}
}

CustomClassLoaderクラスを呼び出し、

    ClassLoader classLoader = new CustomClassLoader(ClassLoader.getSystemClassLoader());
    Class stringClass = (new CustomClassLoader(ClassLoader.getSystemClassLoader())).findClass(packageName+"."+javaFileName);
    Object  t = (Object) stringClass.newInstance();

ありがとう、マーワス

于 2012-08-23T07:13:23.740 に答える