使用Java的不安全实现动态类中的接口

时间:2014-12-13 18:09:00

标签: java interface

我尝试使用Java的sun.misc.Unsafe.defineClass(String name,byte [] code,int off,int len,ClassLoader classLoader,ProtectionDomain protectionDomain)动态加载类,但是我通过调用Class.newInstance()(或Class.getConstructor(。。newInstance())创建的对象不是我在该类中实现的接口的实例(以及Class.getInterfaces()返回的实例)。< / p>

我定义的加载给定字节码的类的方法是:

public static Class<?> loadClass(String name, URL url, byte[] code) {
    Unsafe u = UnsafeKey.getUnsafe();

    java.lang.ClassLoader loader = java.lang.ClassLoader.getSystemClassLoader();

    Permissions perms=new Permissions();
    perms.add(new RuntimePermission("accessDeclaredMembers"));
    ProtectionDomain protection = new ProtectionDomain(new CodeSource(url,(Certificate[])null),perms);

    return u.defineClass(name, code, 0, code.length, loader, protection);
}

我的情况下的字节码是使用这种方法直接从.class文件(由我的jdk编译)加载的:

public static Class<?> loadClass(String name, File f) throws IOException {
    byte[] data = new byte[(int) f.length()];
    InputStream i = new FileInputStream(f);
    i.read(data);
    return loadClass(name, f.toURI().toURL(), data);
}

将加载的数据发送到第一个方法。

用于测试的I类实现了一个名为PixelArtist的接口:

import com.ralitski.art.api.PixelArtist;

public class PixelArtistTest implements PixelArtist {

    public PixelArtistTest() {}

    @Override
    public int getWidth() {
        return 100;
    }

    @Override
    public int getHeight() {
        return 100;
    }

    @Override
    public int getColor(int x, int y) {
        int z = x * y;
        return x + (y * 255) + z;
    }
}

从文件加载此类,定义它并创建新实例后,我尝试将它与此方法一起使用(传递此对象是通过调用Class.newInstance()创建的):

private static Artist getArtist(Object o) {
    System.out.println(o);
    Class c = o.getClass();
    System.out.println(c);
    System.out.println(c.getSuperclass());
    for(Class c2 : c.getInterfaces()) {
        System.out.println("    " + c2);
    }
    System.out.println(PixelArtist.class.isInstance(o));
    if(o instanceof Artist) {
        System.out.println(1);
        return (Artist)o;
    } else if(o instanceof PixelArtist) {
        System.out.println(2);
        return new PixelArtistFeed((PixelArtist)o);
    } else {
        System.out.println(3);
        return null;
    }
}

该代码的输出是:

PixelArtistTest@1947c6b
class PixelArtistTest
class java.lang.Object
    interface com.ralitski.art.api.PixelArtist
false
3

如您所见,Class将PixelArtist列为界面,但从该类创建的对象不是PixelArtist类型的实例。

在我定义它时,我尝试为类添加不同的权限(甚至是AllPermission),我尝试使用Class.getConstructor()。newInstance()实例化Object,但是这个错误仍然存​​在。

1 个答案:

答案 0 :(得分:2)

问题是您正在将类加载到系统类加载器中。这个类加载器没有你的接口,或者有另一个具有不同类加载器的接口副本,很可能是你的类加载器。

我建议您使用默认的类加载器,例如与PixelArtist.class.getClassLoader()

相同