An open API service indexing awesome lists of open source software.

https://github.com/noear/liquor

Java dynamic compiler (jar in jar compatible), Java expression engine, Java script engine. Dynamic Compilation as a Service! (Supports JSR223)
https://github.com/noear/liquor

dynamic-compilation java

Last synced: 10 months ago
JSON representation

Java dynamic compiler (jar in jar compatible), Java expression engine, Java script engine. Dynamic Compilation as a Service! (Supports JSR223)

Awesome Lists containing this project

README

          


Liquor



Java dynamic compiler, expression, scripting tool (jar in jar compatible)




Maven


Apache 2


jdk-8


jdk-11


jdk-17


jdk-21


jdk-23




gitee star


github star


The compiler code for this tool is mainly derived from arthas. Related knowledge is relatively unpopular, very precious. In order to reuse convenient, specially organized into a small toolkit for long-term maintenance. Evaluators were added later to run expressions and scripts.

| Artifact | Size | Features | Functional Description |
|----------------------|------|-----------------------------------------|--------------------------------------|
| liquor | 24KB | DynamicCompiler | Compiling classes |
| liquor-eval | 23KB | LiquorEvaluator (Exprs,Scripts) | Evaluate expression and script(support JSR223) |

Reference dependency:

```xml

org.noear
liquor-eval
1.5.2

```

Performance (Third party performance test):

* [https://gitee.com/xiandafu/beetl/tree/master/express-benchmark](https://gitee.com/xiandafu/beetl/tree/master/express-benchmark)

## Security Alerts !!!

Liquor offers full Java capabilities (anything can happen). It is recommended that developers do a good job of security checking (or filtering) code before submitting it to Liquor for execution.

## Compiler demo

You can have package names. You can import classes. Interdependent; Can not repeat compilation; Just like you would write a java class.

```java
public class DemoApp {
public static void main(String[] args) throws Exception{
// reusable (don't, keep creating)
DynamicCompiler compiler = new DynamicCompiler();

String className = "HelloWorld";
String classCode = "import java.util.HashMap;\n\n"+
"public class HelloWorld { " +
" public static void helloWorld() { " +
" System.out.println(\"Hello, world!\"); " +
" } " +
"}";

//Add source code (more than one) and build
compiler.addSource(className, classCode).build();

Class> clazz = compiler.getClassLoader().loadClass(className);
clazz.getMethod("helloWorld").invoke(null);
}
}
```

## Evaluator demo

Liquor evaluator tool, is based on Java compiler implementation. Under "cache overwriting", the performance is close to the original Java code. However, when there are "infinitely many variations" of expressions, the cache is invalidated and an infinite number of classes are generated, and then OOM.

Consider the expression evaluator:

* Use "variables" instead of constants to reduce compilation of Exprs.eval("a+b+c", context).
* [recommendation] effects, like class-to-instance relationships
* Use uncached mode Exprs.eval(new CodeSpec("1+2+3").cached(false))
* [Not recommended]

### 1) Expression Evaluator(You can only write one line of code)

* Something must be returned
* There is no ";" in the expression , "return" and ";" are automatically added. . Otherwise, make sure your statements are complete
* Use CodeSpec::imports to import the classes required by the expression

```java
public class DemoApp {
public static void main(String[] args) throws Exception {
//Basics
System.out.println(Exprs.eval("1+1"));

//Advanced
CodeSpec code1 = new CodeSpec("aa + 22").parameters(new ParamSpec("aa", Integer.class));
System.out.println(Exprs.eval(code1, 1)); //=> 23

Map context2 = new HashMap<>();
context2.put("bb", 3);
System.out.println(Exprs.eval("bb + 22", context2)); //=>25

System.out.println(Exprs.eval(new CodeSpec("Math.min(1,2)").imports(Math.class))); //=>1
}
}
```

### 2) Script Evaluator

* You can import classes or static methods. No package name
* Inner classes are used without decoration ("public", "static"). Fields and methods of inner classes do not support "static"
* Using CodeSpec::imports to import classes or static methods required by an expression Or add an "import" statement to your code

```java
public class DemoApp {
public static void main(String[] args) throws Exception {
//Basics
Scripts.eval("System.out.println(\"hello word\");");

//Advanced (Don't add public if you have an inner class)
CodeSpec code1 = new CodeSpec("import java.util.HashMap;\n\n"+
" class Demo {\n" +
" public String hello(String word) {\n" +
" return word;\n" +
" }\n" +
" }\n" +
"\n" +
" Demo demo = new Demo();\n" +
" return demo.hello(name);") //name is an external parameter
.parameters(new ParamSpec("name", String.class))
.returnType(String.class);
System.out.println(Scripts.eval(code1, "noear")); //=>noear
}
}
```

## JSR223 demo

```java
@Test
public void case1() {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("liquor"); //或 "java"

scriptEngine.eval("System.out.println(\"Hello world!\");");
}
```