8

I have a functionality that I wish to provide to a customer for a software mockup that we are preparing - and I want to know if it's

  1. possible
  2. intelligent (a.k.a. not stupid)
  3. the best thing

I want the customer to be able to write a java class that implements my Computable interface and stick it in some predetermined folder. This folder will contain the .java files rather than .class files. Then, at runtime, I want my program to search that folder and extract all of the Computables from that folder and store them in a map from the name of the Computable to the Computable object. The Computable should only have a default constructor and the it interface will only have one method called compute which maps an array of Object to an Object.

keyser
  • 18,829
  • 16
  • 59
  • 101
JnBrymn
  • 24,245
  • 28
  • 105
  • 147

8 Answers8

9

The Java Compiler API introduced in Java SE 6 should give you what you need.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
djna
  • 54,992
  • 14
  • 74
  • 117
  • Note that this API is only available in JDK, not in JRE. So if you ever intend to distribute it, the enduser/client must have installed JDK and this is pretty uncommon among the major public. – BalusC Jul 22 '10 at 16:11
  • @BalusC Does the 'x' at the end of javax always imply this? – JnBrymn Jul 24 '10 at 09:58
  • No, it doesn't always. Some are (became) part of standard Java SE API, others aren't. – BalusC Jul 24 '10 at 13:15
3

You may find Google Reflections useful to find classes implementing/extending a certain interface/superclass in the classpath. It's then as straightforward as

Reflections reflections = new Reflections("my.project.prefix");
Set<Class<? extends SomeClassOrInterface>> subTypes = reflections.getSubTypesOf(SomeClassOrInterface.class);

Then, to test if it indeed has a no-arg default constructor, just check for each if Class#newInstance() doesn't throw any exception.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • So what if the .class file was not on the current path, but in a folder that we only learn about at runtime? – JnBrymn Jul 24 '10 at 10:01
  • 1
    You can add paths to the classpath during runtime using [`URLClassLoader`](http://java.sun.com/javase/6/docs/api/java/net/URLClassLoader.html). – BalusC Jul 24 '10 at 13:17
2

There are several suggestions provided as answers to this question.

Here too On-the-fly, in-memory java code compilation for Java 5 and Java 6

Community
  • 1
  • 1
David J. Liszewski
  • 10,959
  • 6
  • 44
  • 57
1

If it's easy enough to compile at runtime that would be fine.

You can use javax.tools to do the compilation as needed. Create dynamic applications with javax.tools may help, too. It's also possible to do it in memory.

One caveat: using the compiler creates a dependency on the JDK; the JRE alone is insufficient.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • You have any sample code? Do I address the command line from Java to execute javac? How do I think suck in the class file and construct the class? – JnBrymn Jul 22 '10 at 14:50
0

take a look: Find Java classes implementing an interface

Community
  • 1
  • 1
foret
  • 728
  • 6
  • 14
  • Looked promising, but it appears to revolve around two possible solutions. 1) Use an API some guy built for himself (I don't want to risk playing with someone else's framework in the short time I have left.) or 2) Using reflection to figure out which already loaded classes implement `Computable`. Recall that my classes won't be loaded... they are just .java files. – JnBrymn Jul 22 '10 at 14:46
0

I think this would be simpler if you allowed your customer to type in a code declaration using something like Groovy, which is Java-ish enough, and easy to execute at runtime from a String value.

Robert Munteanu
  • 67,031
  • 36
  • 206
  • 278
  • Isn't Groovy a strict superset? If so I suppose you could just tell your customer that it's taking Java and they'll be none the wiser. – Mark Peters Jul 22 '10 at 14:48
  • Ah, I'm wrong. A java file is almost always valid groovy code but it's not a strict superset. – Mark Peters Jul 22 '10 at 14:49
0

It's easy enough to iterate through the list of files in a folder. Someone mentioned that it's possible to call the Java compiler from Java (if you re-distribute the JDK, which I think is a point whose legality needs checking!!) That's much of the battle.

You seem to have a fixed model in your mind where only files fulfilling a certain interface are extracted from the folder. I think this is where your method needs to give a little. The sensible way (IMO) to do this would be to compile all files in that folder, and then with their classes stashed away somewhere, you can load and reflect them and then determine which of them "do" the interface and which don't. Those that don't will have been needlessly loaded into your JVM, but unless it's intentionally very space-wasteful, code you don't execute can't harm your program.

Having determined which ones do the computable thing, you can then store those classes (or instances thereof) in a Collection and do whatever you like with them. You simply ignore the other ones.

Carl Smotricz
  • 66,391
  • 18
  • 125
  • 167
0

You could use BeanShell. This library is small and doesn't require the JDK. It is used in a number of IDE and web servers. The latest version appears to have the support you need loading .java files from the class path. (Still in beta)

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130