Friday, March 4, 2011

is something similar to ServiceLoader in Java 1.5?

Hello i want to discover at runtime classes in the classpath which implements a defined interface. ServiceLoader suits well (i think, i haven't used it), but i need do it in Java 1.5.

any ideas?

From stackoverflow
  • There is no reliable way to know what classes are in the classpath. According to its documentation, ServiceLoader relies on external files to tell it what classes to load; you might want to do the same. The basic idea is to have a file with the name of the class(es) to load, and then use reflection to instantiate it/them.

  • There's nothing built into Java 1.5 for this. I implemented it myself; it's not too complicated. However, when we upgrade to Java 6, I will have to replace calls to my implementation with calls to ServiceLoader. I could have defined a little bridge between the app and the loader, but I only use it in a few places, and the wrapper itself would be a good candidate for a ServiceLoader.

    This is the core idea:

    public <S> Iterable<S> load(Class<S> ifc) throws Exception {
      ClassLoader ldr = Thread.currentThread().getContextClassLoader();
      Enumeration<URL> e = ldr.getResources("META-INF/services/" + ifc.getName());
      Collection<S> services = new ArrayList<S>();
      while (e.hasMoreElements()) {
        URL url = e.nextElement();
        InputStream is = url.openStream();
        try {
          BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
          while (true) {
            String line = r.readLine();
            if (line == null)
              break;
            int comment = line.indexOf('#');
            if (comment >= 0)
              line = line.substring(0, comment);
            String name = line.trim();
            if (name.length() == 0)
              continue;
            Class<?> clz = Class.forName(name, true, ldr);
            Class<? extends S> impl = clz.asSubclass(ifc);
            Constructor<? extends S> ctor = impl.getConstructor();
            S svc = ctor.newInstance();
            services.add(svc);
          }
        }
        finally {
          is.close();
        }
      }
      return services;
    }
    

    Better exception handling is left as an exercise for the reader. Also, the method could be parameterized to accept a ClassLoader of the caller's choosing.

  • ServiceLoader is quite basic, and has been in use (informally) within the JDK since 1.3. ServiceLoader just finally made it a first class citizen. It simply looks for a resource file named for your interface, which is basically bundled in the META-INF directory of a library jar.

    That file contains the name of the class to load.

    So, you'd have a file named:

    META-INF/services/com.example.your.interface

    and inside it is a single line: com.you.your.interfaceImpl.

    In lieu of ServiceLoader, I like Netbeans Lookup. It works with 1.5 (and maybe 1.4).

    Out of the box, it does the exact same thing as ServiceLoader, and it's trivial to use. But it offers a lot more flexibility.

    Here's a link: http://openide.netbeans.org/lookup/

    Here's a article about ServiceLoader, but it mentions Netbeans Lookup at the bottom: http://weblogs.java.net/blog/timboudreau/archive/2008/08/simple_dependen.html

  • Have you thought of using an OSGI framework ?

  • Use the Service class instead of ServiceLoader for JDKs < 6.0.

0 comments:

Post a Comment