views:

249

answers:

4

I have a library Eclipse project/workspace containing functionality that is occasionally delivered to a customer. We're all researchers so this is done very informally; I make a JAR and a Word file with documentation, and send it to them.

I prefer to send them a JAR file that only contains what they actually need, to simplify things. If they need classes X, Y, Z and W, then I send a JAR file containing X, Y, Z, and W, as well as all of the classes that those depend on.

Right now I am doing this in a hopelessly manual way (I create a new project, drag over X, Y, Z, and W, and then drag over anything I need to fix the compiler errors). What's the right way to automate it in Eclipse?

EDIT: Just to be clear, the Eclipse projects involved contain many more classes than are actually needed by the customer.

EDIT: Also, there is no reflection involved; I can be confident that the compiler knows what is going on. I'm the one who wrote the code, and I avoid reflection like the plague. The only place I used reflection is to imitate Collections.toArray(), and in that case the only class that could cause a problem is one that the user provided.

+1  A: 

You can use Ant to automate something like this

OTisler
I'm a newbie to Ant, but when I tried putting in a compile action for the specific classes involved, it ONLY compiled those and didn't pull in the dependencies. How would this work to get the depended-on classes compiled as well?
jprete
A: 

When you use the Export command you are given the choice to choose which files to include on the generated JAR.

Mario Marinato -br-
If I only choose classes XYZW, will it automatically add the required classes on its own? If I save that configuration as a ".jardesc", then will it dynamically update the output based on any changes in the dependencies of XYZW?
jprete
Unfortunately, it will not add the required classes. You have to choose them all.I have no knowledge about jardesc files, sorry.
Mario Marinato -br-
+1  A: 

You are currently copying enough class files to make the compiler happy. However, are you sure you are copying enough class files to make the running application happy? Some applications load their classes via reflection at run time:

String className = "org.my.company.Foo";
Class<?> fooClass = Class.forName(className);
Object foo = fooClass.newInstance();

In this example, the compiler will not complain, even if you don't copy the org.my.company.Foo class. However, the running application will most certainly complain when it can't find the class.

If you want to accommodate both situations, you can try writing a custom ClassLoader that records all classes being loaded by the running application:

public class RecordingClassLoader extends ClassLoader {

    private FileWriter classNameWriter;

    public RecordingClassLoader(ClassLoader parent) throws IOException {
     super(parent);
     classNameWriter = new FileWriter(System.getProperty("loaded.classes.file", "C:\\classes.txt"));
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
     try {
      classNameWriter.write(name);
      classNameWriter.write("\r\n");
      classNameWriter.flush();
     } catch (IOException e) {
      e.printStackTrace();
      throw new RuntimeException("Could not record class loading", e);
     }

     return super.loadClass(name);
    }

}

You could then run your application like this:

java
  -Djava.system.class.loader=RecordingClassLoader
  -Dloaded.classes.file=loaded_classes.txt
  YourApplication

The loaded_classes.txt file will look something like this:

java.lang.System
java.nio.charset.Charset
java.lang.String
...
...
YourApplication

You can modify the class loader to ignore any classes being loaded from the java. packages. After you run the application, you can then have a little program automatically copy the classes mentioned in this file.

Adam Paynter
I wrote the code involved, and I am certain that reflection is not relevant (see the question edit). However, that would be a pretty good answer to a slightly different question. :)
jprete
+1  A: 

Byecycle, an Eclipse plugin will help. Not in getting a thorough automated process, but in determining the dependencies. I'm not sure whether you can get it to work on Ganymede/Galileo, since I've used this a long time back.

Update

The Class Dependency Analyzer Tool might prove to be more helpful, since it comes with a plug-in extension API that could be used to create a plug-in to perform exactly the task that you intend to do.

Update #2

In case you were wondering about the usage of Ant, you can use the ClassFileSet type to obtain a class and its list of dependencies. This can be referenced inside a copy task to copy the required class files. Do note that this doesn't copy source files.

Internally, this method depends on the BCEL library, so if you wish to perform a copy of sources, you could attempt to write code to examine a .class file's dependencies, and copy the sources over to another directory.

Vineet Reynolds