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.
Byecycle, an Eclipse plugin would help, but it has been removed from Sourceforge. 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.
You can use Ant to automate something like this
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.
When you use the Export command you are given the choice to choose which files to include on the generated JAR.
I submitted an Eclipse enhancement request to support such a refactoring. In the meantime, I found some promising tools to help with the decoupling and dependency analysis.
- eDepend is a dependency viewer plugin that includes a
Class/Package dependency diagram that displays elements dependencies,
relationships with libraries/other projects and dependency cycles. It
can also list find classes that caused the dependencies.
- STAN structure analysis for Java
- nWire
- Class Dependency Analyzer
- Dependency Finder
Related questions: 1