开发者

Superseding Classes from JARs Earlier in Classpath

I distribute some code to my first-semester programming students that creates a ZIP archive of their homework within Eclipse. For assignment N, I create a main method in class hwN.Submitter which invokes a library method foo.Submit.zip(). I distribute the main and the library in an executable JAR. foo is fairly stable, but occasionally it changes. The library is bundl开发者_JAVA技巧ed in each homework's JAR file.

Now, suppose a student adds hw1's JAR to Eclipse's Build Path. I then change the API of foo.Submit for hw2 and distribute its JAR. Since it's added later in the Build Path, hw2.Submitter ends up loading foo.Submit from hw1's JAR, which doesn't contain the method since the API changed.

Now, I seem to have a few choices: A) tell my students to remove old JARs, B) tell my students to reorder the Build Path, or C) write my own class loader. I don't like A because it's useful for them to run the JARs on old homeworks. I don't like B because they are first-semester programmers. And I can't get C to work.

I've played around with URLClassLoader, but the parent class loader finds the classes in the old JARs first. How can I supersede these old JARs or override the parent class loader?


Okay, poking around a bit more, I was able to find a solution. This is the class loader I came up with:

package speccheck;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * Create a class loader which favors speccheck.* classes from the JAR
 * associated with the homework.
 */
public class LatestSpecCheckClassLoader extends URLClassLoader {
  /**
   * Create a loader which checks $(pwd)/bin/speccheck_TAG_DO_NOT_SUBMIT.jar
   * first for speccheck.* classes
   * 
   * @param tag
   * Homework tag, like "hw4" or "pre2".
   * @throws MalformedURLException
   */
  public LatestSpecCheckClassLoader(String tag) throws MalformedURLException {
    super(new URL[]{new URL("file://" + System.getProperty("user.dir") + "/bin/" + tag + "/speccheck_" + tag + "_DO_NOT_SUBMIT.jar")});
  }

  @Override
  public Class<?> loadClass(String name) throws ClassNotFoundException {
    // Check for cached.
    Class<?> loadedClass = findLoadedClass(name);
    if (loadedClass != null) {
      return loadedClass;
    }

    // If the class is in the speccheck package, do not delegate to parent
    // loader. Check in the URLs registered with this loader instead.
    try {
      if (name.startsWith("speccheck.")) {
        loadedClass = findClass(name);
      }
    } catch (ClassNotFoundException e) {
    }

    // If still not found, then let's defer.
    if (loadedClass == null) {
      return super.loadClass(name);
    }

    return loadedClass;
  }
}

Hats off to Alex Miller for a working example.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜