Я работаю над REPL для собственного языка программирования. Он реализован поверх компилятора, который он использует для генерации байт-кода для ввода и преобразования его в экземпляр Class<?>
с использованием метода sun.misc.Unsafe.defineClass(String, byte[], int, int, ClassLoader, ProtectionDomain)
. Соответствующий код выглядит следующим образом (не относящихся к делу деталей, таких как обработка исключений опущенных):Определите несколько классов во время выполнения с помощью Unsafe.defineClass
void compileAndLoad(List<ICompilable> compilables)
{
List<Class<?>> classes = ...;
for (ICompilable c : compilables)
{
classes.add(compile(compilable));
}
for (Class<?> c : classes)
{
UNSAFE.ensureClassInitialized(c);
}
}
// CLASS_LOADER = Enclosing.class.getClassLoader()
// PROTECTION_DOMAIN = Enclosing.class.getClassLoader()
Class<?> compile(ICompilable compilable)
{
byte[] bytecode = genBytecode(compilable);
String name = compilable.getFullName() // e.g. 'foo.bar.Baz'
return UNSAFE.defineClass(name, bytes, 0, bytes.length, CLASS_LOADER, PROTECTION_DOMAIN);
}
Say вход требует несколько классов, чтобы быть скомпилированы и загружены.
> class A { interface B { }; func b() = new B { /* anonymous class */ } }
compilables
список имеет содержание
[ repl.Result_0, repl.Result_0$A, repl.Result_0$A$0, repl.Result_0$A$B ]
repl.Result_0$A
класс зависит от (анонимной) класса repl.Result_0$A$0
и repl.Result_0$B
класса и ссылки их имена в байткод. При определении его с помощью Unsafe
, произойдет следующее сообщение об ошибке:
java.lang.NoClassDefFoundError: repl/Result_0$A$B
at sun.misc.Unsafe.defineClass(Native Method)
at MyClass.compile(MyClass.java:42)
// ... snip
Caused by: java.lang.ClassNotFoundException: repl.Result_0$A$B
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 9 more
Я знаю, что это может быть решена путем изменения порядка списка и определения repl.Result_0$A$B
первый, но это не будет общим решением, так как там могут быть ссылки с B -> A
как Что ж.
Есть ли способ определить и загрузить несколько классов с использованием Unsafe.defineClass
, не вызывая ошибок проверки для неразрешенных классов?
Вы пытались использовать компилятор Java API, вместо Unsafe? Вы можете создать собственную реализацию JavaFileObject, которая предоставляет байт-код, а затем использовать собственный ClassLoader для загрузки классов с помощью FileObjects ... Я не знаю достаточно вашего компилятора, чтобы узнать, будет ли это работать, но я использую этот подход для компилировать классы во время выполнения, и я никогда не сталкивался с этой проблемой. – Renato
Мне нравится парень с таким интересом;) Во всяком случае, Ренато прав, используйте некоторую библиотеку, чтобы правильно сформировать класс, а затем используйте обычный загрузчик классов для их загрузки. –
Почему вы используете Unsafe вместо ClassLoader.defineClass? –