How to execute code from a client side app

Is it possible to write complex code (like instantiating an object and use the stream API) in string then parse it using something like spring language expression? Basically what I'm trying to do is to write code from the client side in string format then find a way to parse it and execute it on the backend side. From a business use case what I want to do is write some code to out put something and simply store it in a column field named "result".

Someone replied to me before and said it's doable but I had to abandon the chat

If you abandon Java you can do this with something you can sandbox in the jvm, like possibly nashorn or my pref. - SCI.

String expressionStr = """
(let [customer-1 (Customer. "Mike" 9)
      customer-2 (Customer. "Ted" 20)
      customers. [customer-1 customer-2]]
  (->> customers
       (filter (fn [customer] (= "Mike" (.getName customer))))
       (first)))
"""

Then evaluate that in SCI.

https://github.com/borkdude/sci

IFn eval = Clojure.read("sci.core", "eval-string");
Customer customer = (Customer) eval.invoke(expressionStr);

and to give it sandboxed access to your classes, probably do this

IFn symbol = Clojure.read("clojure.core", "symbol");
IFn keyword = Clojure.read("clojure.core", "keyword");
IFn eval = Clojure.read("sci.core", "eval-string");
Customer customer = (Customer) eval.invoke(
    expressionStr, 
    Map.of(keyword.invoke("classes"), Map.of(symbol.invoke("Customer"), Customer.class))
);

Full example if you have clojure and sci included in your project

import clojure.java.api.Clojure;
import clojure.lang.IFn;
import java.util.Map;

public final class SciTest {
    private SciTest() {}

    private static final IFn REQUIRE;
    private static final IFn SYMBOL;
    private static final IFn KEYWORD;

    private static final IFn EVAL_STRING;

    static {
        REQUIRE = Clojure.var("clojure.core", "require");
        SYMBOL = Clojure.var("clojure.core", "symbol");
        KEYWORD = Clojure.var("clojure.core", "keyword");

        REQUIRE.invoke(Clojure.read("sci.core"));
        EVAL_STRING = Clojure.var("sci.core", "eval-string");
    }

    public record Thing(int x) {}

    public static void main(String[] args) {
        System.out.println(EVAL_STRING.invoke(
                """
                (Thing. 10)
                """,
                Map.of(
                        KEYWORD.invoke("classes"),
                        Map.of(
                            SYMBOL.invoke("Thing"), Thing.class
                        )
                )
        ));
    }
}

Will take a look, thanks!

Curious what the actual requirement here is though. Since this isn't exactly super duper safe to do even with the sandboxing. They can still OOM your machine or whatever.

Requirement isn't fully clear but basically when creating a new entity record, there's a "result" field where the end user wants to write some code or formula based on other fields of the entity, ex: result = id + title + getUniqueRandNubr()

Yeah this might be a better use for a little dsl. You can make a tiny lang with antlr pretty easily. This is more general purpose, you can basically write any code.


<- Index