views:

390

answers:

2

I am looking to compile an application in Java, made up of a various number of java classes in a certain number of packages. At the command line, I can change to the folder containing the root package and type:

javac rootpackage/subpackage/*.java

or

javac rootpackage/*/*.java

to compile all the java classes in all the primary subpackages of my rootpackage.

However I would like to be able to do this within a Java application. (The idea is that we provide an application to students which contains unit tests. The unit tests need to be run against their code, the application then creates a JAR file containing their source files which have been 'watermarked' with the test results. All this works ok, but we would like to make sure that the class files tested are created from the source files submitted, hence the idea to compile programmatically the java sources).

The problem comes in that each student stores their root package in an arbitrary position, and I cannot seem to pass the location of the file to JavaCompiler (javax.tools).

Is it possible, and if so, can someone give some hints on how to have an arbitrary placed root package compiled properly.

Cheers

Richard

More Info:

a student has a folder structure:

/home/student/work/java/myproject/

which contains the root package. They launch the application (possibly stored in this folder - and thus no problems- however more than likely stored elsewhere) which asks them for the folder that contains the root package. After entering, the students click a create JAR button, that compiles the files in their packages, runs the tests on the newly compiled files and then creates the JAR.

Whilst thinking through this problem, it is possible that the solution is to tell the students to install our 'create JAR' application in the folder containing their root package.

A: 

Could you peek at the top of each .java file for the line beginning:

package com.blah.blah.assignment;

i.e. look for the start of the package name and then look for the first directory in your search path beginning com (in this example), and then give this path to the JavaCompiler object, or have I misunderstood your question?

Having just looked at the javax.tools package, why not create a composite wrapper for the javaFilemanager which wraps a ForwardingjavaFileManager which will forward all requests for the methods such as getFileForInput or getJavaFileForInput down to the appropriate starting directory in the student's source directory (as decided by your preliminary bit of parsing of the first .java file to determine the root of their sourcepath)

James B
A: 

The last argument to JavaCompiler.getTask() is an Iterable<? extends JavaFileObject> containing the compilation units to pass to the compiler. One of the provided implementations of JavaFileObject is SimpleFileJavaObject (http://java.sun.com/javase/6/docs/api/javax/tools/SimpleJavaFileObject.html). This is constructed with a java.net.URI object, which can be created easily from a File object. Putting it all together, do something like this:

List<JavaFileObject> javaFiles = new ArrayList<JavaFileObject>();
File javaFile = new File(rootPackageDirFromUser, fileNameInRootDir);
URI javaURI = javaFile.toURI();
javaFiles.add(new SimpleJavaFileObject(javaURI, JavaFileObject.Kind.SOURCE));
JavaCompiler.CompilationTask task =
    ToolProvider.getSystemJavaCompiler().getTask(..., javaFiles);

where rootPackageDirFromUser is given by the user, who tells you where they stored the files, and fileNameInRootDir is the name of a java source file in that dir. If you don't know the file names in advance, you'll need to iterate over the rootPackageDirFromUser to construct a list.

I haven't tested this, but that should give you the general idea.

archbishop