Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine return type of a Java expression in a String at runtime

At runtime, in my Java program, given a String, I 'd like to know the return type. For example:

  • 1 + 1 returns int
  • 1L + 1L returns long
  • 1L + 1 returns long
  • 1 + 1.5 returns double
  • 1 + 2 - 3 * 4 / 5 returns int
  • 1 / 0 returns int
  • 1 + Math.nextInt() returns int
  • 1.5 + Math.nextInt() returns double
  • Color.RED returns java.awt.Color
  • Given that a is an int: a + 1 returns int
  • Given that a is an int: a + 1.5 returns double

There is no need to actually evaluate the code: I just need the return type. How can I do this with the JDK runtime compiler, ECJ JDT or any other pure Java dependency?


Detailed code: Here's a simplified, pseudo-code unit test for this code:

public static void ExpressionTyper {
    public String determineType(String expression, Map<String, String> variableTypes) {
       ... // How do I implement this?
    }
}
public void ExpressionTyperTest {
    @Test public void determineType() {
        assertEquals("int", ExpressionTyper.determineType("1 + 1", emptyMap());
        assertEquals("long", ExpressionTyper.determineType("1 + 1L", emptyMap());
        assertEquals("double", ExpressionTyper.determineType("1 + 1.5", emptyMap());
        assertEquals("int", ExpressionTyper.determineType("a + 1", mapOf({"a", "int"}));
        assertEquals("int", ExpressionTyper.determineType("a + b", mapOf({"a", "int"}, {"b", "int"}));
        assertEquals("double", ExpressionTyper.determineType("a + b", mapOf({"a", "double"}, {"b", "int"}));
    }
}
like image 780
Geoffrey De Smet Avatar asked Jan 05 '23 18:01

Geoffrey De Smet


2 Answers

I think this depends on the range of input you want to be able to process.

You see, in the end you are asking: how do I evaluate string expressions at runtime.

So, the short answer is: you need some kind of interpreter / REPL implementation; or at least "parts" of that.

Another approach could be to use the javax compiler to simply compile the thing, and then deduce the type, like here.

Other options would go along the lines of certain "compiler construction" topics, like constant folding.

like image 103
GhostCat Avatar answered Jan 08 '23 08:01

GhostCat


I've not tried this ...

  1. Wrap your expression in code like this:

      public class Test {
          private Test xxx = <<insert expression>>;
      }
    
  2. Compile code.

  3. Parse the compilation error message to extract the compiler's idea of the RHS type.

The problem is that an expression like Math.nextInt() might require an import to be compilable, and I doubt that there is a bombproof way to infer what the import ought to be. Still, this should work for a useful subset of expressions.

This approach is also fragile and non-portable since it depends on the precise form of the compilation error message which is liable to be compiler / version dependent.


A better solution (but more work) would be to implement a parser and type-checker for your Java subset expression language.

like image 24
Stephen C Avatar answered Jan 08 '23 09:01

Stephen C