one-nio: компилируем Java на лету
В библиотеке one-nio есть возможность компилировать Java код на лету. Это может быть нужно, когда вы хотите дать пользователю возможность задавать формулы для вычисления значений. Как-то мне нужно было посчитать вес тасков для отдачи пользователям по сложной формуле, которая зависела от квалификации пользователя и типа таска. Я решил эту задачу используя встроенный в jvm движок Nashorn. Писал куски кода на Javascript, компилировал и запускал в программе.
Можно обойтись без Javascript, если писать и компилировать прямо Java код:
package ru.yamakarov.gen;
import one.nio.compiler.CompilationException;
import one.nio.compiler.Javac;
import one.nio.gen.BytecodeGenerator;
public class FunctionScript {
public static void main(String[] args) throws CompilationException {
String template =
"package ru.yamakarov.gen;\n" +
"\n" +
"public class GeneratedScales extends Scales {\n" +
" public int weight (Context context) {\n" +
" return %s;\n" +
" }\n" +
"}";
String functionStr = "context.multiplier * 10";
byte[] classData = new Javac().compile(
String.format(template, functionStr)
);
Scales myScales = new BytecodeGenerator().instantiate(classData, Scales.class);
System.out.println(myScales.weight(new Context(10)));
}
}
Можно писать в файле или в базе данных код функции:
String functionStr = "context.multiplier * 10";
Подставлять его в шаблон, расширяющий класс Scales
:
package ru.yamakarov.gen;
public class Scales {
public int weight (Context context) {
return 0;
}
}
Итоговый экземпляр myScales
можно сохранять для повторного использования, чтобы сократить время вызова.
Также в context
можно передавать и другие параметры, кроме использованного мною multiplier
:
package ru.yamakarov.gen;
public class Context {
public int multiplier;
public Context(int multiplier) {
this.multiplier = multiplier;
}
}
Я не проверял, но такой способ должен работать быстрее использования javascript движка, будет поддерживать jit оптимизации, в случае частого вызова метода, который был получен от пользователя и больше мне нравится.