2014-12-13 3 views
2

Я пытаюсь динамически загружать классы с помощью Java sun.misc.Unsafe.defineClass (имя строки, байт [] код, int off, int len, классLoader classLoader, ProtectionDomain protectionDomain), но по какой-то причине объекты, которые я создаю, вызывая Class.newInstance() (или Class.getConstructor()). newInstance()) не являются экземплярами интерфейса, который я реализовал в этом классе (и который возвращает Class.getInterfaces()), ,Внедрение интерфейсов в динамических классах с использованием небезопасных Java

Метод, который я определил загрузить класс данный байт-код это:

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); 
} 

Который отправляет загруженные данные в первый метод.

Класс Я использую для тестирования реализует интерфейс под названием 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; 
    } 
} 

выходной сигнал этого кода заключается в следующем:

[email protected] 
class PixelArtistTest 
class java.lang.Object 
    interface com.ralitski.art.api.PixelArtist 
false 
3 

Как вы можете видеть, класс перечисляет PixelArtist как интерфейс, но объект, созданный из этого класса, не является экземпляром типа PixelArtist.

Я попытался добавить разные разрешения для класса, когда я его определяю (даже для AllPermission), и я попытался создать экземпляр объекта Object с помощью Class.getConstructor(). NewInstance(), но эта ошибка сохраняется.

ответ

1

Проблема заключается в том, что вы загружаете класс в загрузчик системного класса. Этот загрузчик классов не имеет вашего интерфейса или имеет другую копию интерфейса, у которой есть другой загрузчик классов, скорее всего, ваш загрузчик классов.

Я предлагаю вам использовать ваш загрузчик классов по умолчанию, а не, например. то же, что и PixelArtist.class.getClassLoader()

Смежные вопросы