SourceBuddy Brings Eval To Java
Written by Nikos Vaggalis   
Monday, 23 January 2023

SourceBuddy is a Java library that compiles and loads dynamically generated Java source code. This has the advantage of providing Java with an eval facility such as those found in interpreted languages.

Languages like Perl and Javascript have eval for evaluating code at runtime that gets passed into the function as a plain string. For instance :

say "Give first number: ";
$a = <STDIN>;

say "Give second number: ";
$b = <STDIN>;

say "Give operator: ";
$operator = <STDIN>;

$result = eval "$a $operator $y";
say $result;

So given an input of $a=1, $b=2, $operator=+, eval will evaluate the expression "1 + 2" which gives 3.

To be extra cautious when needing to evaluate user supplied code; you don't want to compile and run a system("rm -rf") do you?

Eval can load whole libraries/modules at runtime as well like

$module = "My::module";
eval("use $module;");

Of course in cases like that it is recommended to use more flexible solutions like Module::Load or Class::Load :

use Module::Load;
my $module = "My::module";
load $module;

What about loading and evaluating code encapsulated into modules at runtime, from a file system path:

use FindBin;

foreach $module in (@modulesArray) {
use lib "$FindBin::Bin/modules";
eval "use $module";
if ($@) {
  die "can't load $module";
  }
}


Java gets that kind of functionality now too thanks to SourceBuddy, a Java source compiler facade in front of the JDK-provided javac compiler.

sbuddy

With SourceBuddy you can compile Java source code you created dynamically, in your Java application. Your program can create the source code of one or more Java classes, pass the strings to SourceBuddy and then use the classes. An example code is the following:

String source = """
package com.sb.demo;

public class MyClass implements Talker {

  @Override
  public void say() {
     System.out.println("Hello, Buddy!");
   }
 }""";


Class<?> myClassClass = Compiler.compile(source);

Talker myClass = (Talker) myClassClass.getConstructor().newInstance();

myClass.say();

This is the same as Perl's simple string eval.To replicate Perl's runtime loading of modules from a file path you can use SourceBuddy's API call:

.from(Paths.get("src/test/java"))

Why would you need this kind of functionality anyway? You use eval when the code to be evaluated is not known in advance, or even generated server-side. Yes, it's niche, but there are use cases.

In a sense this functionality is similar to that found in REPLing, where you can issue code at the shell which compiles and runs it as you go.
We've seen an example of that applied to another compiled language, that of C#, in "CSharpRepl Brings REPL Superpowers To C#"

REPL, once an inherent property of the interpreted languages, has now found its way into compiled languages too.

So what's the deal with REPL? It's all about the immediate feedback loop you get; you can enter program elements one at a time, immediately see the result, and make adjustments as needed.

You can evaluate anything;variables, code blocks, functions, even define full-fledged classes and use them in the REPL console, always getting instant feedback, or even use C#/Java as a scripting language for testing purposes and running short lived utility scripts.

This comes in stark contrast with the typical workflow of working with a compiled language:

 

  • Write a complete program.
  • Compile it and fix any errors.
  • Run the program.
  • Figure out what is wrong with it.
  • Edit it.
  • Repeat the process.

 

A REPL gives you the option to try out code without that hassle. You can test individual statements, try out different variations of a method, and experiment with unfamiliar APIs. Which makes it great for quick tutorials and prototypes.

For Java there's Jbang (jbang --interactive which uses JShell internally) and Jshell that serve the REPL's shell purpose.
While a REPL renders Java as a scripting language, it is different from the purpose of SourceBuddy which lets you load dynamically generated Java source code inside your program.

In short, tools like Jbang and SourceBuddy act as extensions to the Java language bringing with them capabilities from interpreted languages.

More Information

SourceBuddy

Related Articles

CSharpRepl Brings REPL Superpowers To C#

 

Last Updated ( Wednesday, 25 January 2023 )