• Post Reply Bookmark Topic Watch Topic
  • New Topic

Dynamic compiling: is there a way to test what was compiled?  RSS feed

 
Pat Mig
Greenhorn
Posts: 23
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I built a servlet that compiles java code and returns compilation errors (if any). I'm calling it from an html form where I type the code.
The servlet is working great (mostly thanks to Ron McLeod, who helped me A LOT on this forum).
The thing is, it just compiles code and tells you the results, but it doesn't test the code. Since I'm using it for educational purposes (teaching java to beginners), I thought it would be nice to check that syntactically correct code actually does what the user intends it to.
Currently the servlet is set to create a .class file on my c: drive if the compilation succeeds. Maybe there's a way I can run that class somehow?

This is my servlet class:




It uses a class called "JavaObjectFromString" which looks like this:



The code I'm expecting to compile is very simple, however it covers a wide variety of situations: in some cases the user is only asked to declare a variable and assign a value to it, sometimes they have to write a while loop to increment a variable, in some other cases they need to write a whole method.

Is this testing I'm trying to do something too complex? I'm not sure where to start...

Thanks
 
Ulf Dittmer
Rancher
Posts: 42970
73
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That is possible, modulo some caveats.

For starters, you should take security precautions before you run random code. However you end up running the code, a tight security manager should be in place.

The two principal ways of running the code would be a) in-process with the servlet container, and b) in a standalone process separated from the servlet container. Which is better depends on what the code is supposed to be doing - does it implement a common interface that you could test? Or is it supposed to run via "main" method?

I note that your code doesn't add any interface declarations, so your test code can't make many assumptions about the resulting class - that makes testing hard.
 
Pat Mig
Greenhorn
Posts: 23
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks, Ulf
About how to run the code, I'd go with the easiest choice. I guess that would be from within the servlet container, but I'm not too aware of the implications.
And I got a bit lost with the interface implementation. What would be the exact purpose of it in this case? How would it help me test?

What I actually did was replace the second line of the "compile" code (String toCompile = "class test {" + codeToCompile + "}") with a call to a method that receives 2 parameters: the code itself to be compiled and a number indicating what "kind of exercise" it is. That way, if I ask the user to just declare a variable I can surround his code with class test {" + code + "} but if I'm asking him to write a for loop I surround it with class test {public void testMethod() {" + code + "}} and this way the user only focuses on just typing the required code, without having to wrap it in a whole class structure.
That's as far as I got, other than the classes I posted above :P
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Likes 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So right now, it looks like you have three basic scenarios:

1) The user writes simple statements like variable declarations and assignments
2) The user writes complex statements like loops
3) The user writes entire methods themselves

Each of these scenarios requires different testing.

1) In the first case, you need to check if there is/are variable/s declared and what the values are (and their types?). For this case, you need to use reflection to inspect the class, and if the variables are non-static, create an instance of the class and inspect the values.

2) In the second case, you need to create a method which you can run. You already do this, but this is the perfect case for an interface like Ulf was saying. For example, if you had an interface declared like this:

Then you could change your code template to this:

And your could run the code via the interface:

That saves you from having to use use reflection to find the method, which can be complex.

3) The third case requires you to do something very similar to the first case, you have to use reflection to find the method and execute it. Or you could require the method be named something specific so the method is easier to find (and in that case you could use the interface strategy as above).

Any of these strategies require you to generate instances of the class in question. And the way to do that is via a ClassLoader (and the simplest is probably to use a URLClassLoader). Click the links in that last sentance for a peak at their API and see if you can figure out how to get the class you created into memory. Your goal is to get an instance of a Class object, which, if you look at the API will help you generate instances or find variables. Sort of a big subject so it is better to start small and see how far you can get with each step.
 
Ulf Dittmer
Rancher
Posts: 42970
73
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks, Steve, you actually wrote a lot of what I intended to say :-)

The reason being, I've dabbled in this space, and still find it interesting. For some background on this, and for some practical experiments, I'll point you to two articles I've written which may be of interest if you want to get into this. Creating Java classes at runtime for evaluating numerical expressions is about how to create and run Java classes within a JVM using the Javassist library. While you already have the compilation done, since it works with files it's a bit awkward to use; the article described how to do it entirely in memory, and how to create entire classes from bits and pieces of code (as seems to be the case here). Adding Plugins to a Java Application talks about the classloader aspect Steve mentioned, and the security aspect I mentioned, that you would encounter when doing this in a desktop app - doing it as part of a web app is not fundamentally different (although it would have some implications on the security manager, since many of the things you might want to forbid the servlet container actually needs to do).

Of course, the security precautions could be moot, if you know exactly who submits that code and you trust those folks to do the right, or the worst-case scenario (the entire machine where the code runs is compromised) is acceptable.
 
Pat Mig
Greenhorn
Posts: 23
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks a bunch, guys
Everything you mentioned is really interesting and opened my mind to possibilities I didn't know about.
And lots of great stuff to read!
Thanks!
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!