# liquor **Repository Path**: noear/liquor ## Basic Information - **Project Name**: liquor - **Description**: Java 动态编译器(兼容 jar in jar)、Java 表达式引擎、Java 脚本引擎。动态编译即服务!(支持 JSR223) - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: https://solon.noear.org/article/liquor - **GVP Project**: No ## Statistics - **Stars**: 280 - **Forks**: 75 - **Created**: 2021-05-31 - **Last Updated**: 2026-09-27 ## Categories & Tags **Categories**: utils **Tags**: None ## README

Liquor

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

Ask DeepWiki Maven Apache 2 jdk-8 jdk-11 jdk-17 jdk-21 jdk-25
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 | 26KB | DynamicCompiler | Compiling classes | | liquor-eval | 22KB | LiquorEvaluator (Exprs,Scripts) | Evaluate expression and script(support JSR223) | Reference dependency: ```xml org.noear liquor-eval 1.6.8 ``` 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 import org.noear.liquor.DynamicCompiler; 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 import org.noear.liquor.Utils; import org.noear.liquor.eval.CodeSpec; import org.noear.liquor.eval.Exprs; import org.noear.liquor.eval.ParamSpec; 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, Utils.asMap("aa", 1))); //=> 23 System.out.println(Exprs.eval("bb + 22", Utils.asMap("bb", 3))); //=>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 import org.noear.liquor.Utils; import org.noear.liquor.eval.CodeSpec; import org.noear.liquor.eval.ParamSpec; import org.noear.liquor.eval.Scripts; 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, Utils.asMap("name", "noear"))); //=>noear } } ``` ## JSR223 demo ```java import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; @Test public void case1() { ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("liquor"); //或 "java" scriptEngine.eval("System.out.println(\"Hello world!\");"); } ```