In this article, "code evaluation" means - executing code expressions in runtime, like it happens when you pause the application in debug mode in IDEA and use the feature "Evaluate Expression". Let's consider how to implement "code evaluation" in a java application and then explore implemented solutions for using "code evaluation" in the java-spring application.
Use case example
For example, projects in your company use kubernetes. After implementing the new feature you must pass all pipelines to check how it works in the environment with all integrations with other services. And after deploying the service you see that some little things work not properly. And you want to make some little fixes for checking the hypothesis. However, to check it your must pass all pipelines including coding, review, building, deploying, etc.
If you have a tool like code evaluator in the project you can change any code or value of any variable (even the override code of the class method), check changes in runtime, and after checking changes start to fix the code and start pipeline things.
Notice, this tool must exist only in a non-production environment.
Implementation
As is known, groovy is fully compatible with java programming language. Groovy has a dynamic compilation feature, which we will use for "code evaluation" implementation. We will use groovy for "code evaluation", but it will work in any java application. How to add groovy to your java project you can find yourself easily. And now let's consider how to implement "code evaluation".
1) Let's create a groovy class and define a string variable that contains a class with a placeholder.
def EXPRESSION_CLASS_TEMPLATE = """
package dev.toliyansky.eval.service
class ExpressionClass implements java.util.function.Supplier<Object> {
def get() {
%s
}
}
"""
package must be with the same package where this code will call.
2) Let's compile and load a class from the first paragraph.
For instance, you can place the code below in the REST controller, it will allow getting a text for evaluation expression from the request body.
def finalClassCode = String.format(EXPRESSION_CLASS_TEMPLATE, code)
def supplier = groovyClassLoader.parseClass(finalClassCode)
.getDeclaredConstructor()
.newInstance() as Supplier<Object>
def result = supplier.get()
On the first line, we replace %s with code that will be dynamically compiled and executed in runtime.
On the second line, we compile and instantiate the class from the first paragraph. Notice that instantiated class casted to the Supplier
for the ability to call the method with text that you want to evaluate. Supplier<Object>
is ideal for this purpose because it doesn't have parameters and has a return statement.
Implemented solution
If you don't want to mess around with implementing dynamic compilation and plugging up groovy into your project then you can use implemented spring boot starter with implemented "code evaluation" feature: evaluator-spring-boot-starter
After adding this starter dependency to your project you can evaluate code through http://host:port/eval with UI.
You can evaluate any text by sending HTTP requests. If you are interested in this project check readme on GitHub.
UI Screenshots
Example with dynamically overriding code of method in runtime. It can be any bean in your application, such us controllers or services.
Also as a bonus, this solution provides the possibility to execute Bash, Cmd, or PowerShell commands. It allows debug not only your application but even checking or changing some environments where your application started.
Top comments (0)