Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.util.ServiceLoader not loading my provider class

I am trying to put together a basic SPI-based registry of Handlers, which I lookup from a HandlerRegistry. When I use the ServiceLoader.load(Handler.class) to initialize the providers, and then iterate the list to lazily load them, I am not seeing any instances of the class. Keeping this as simple as possible, my HandlerRegistry class is:

public class HandlerRegistry 
{
  private static HandlerRegistry registry;

  private ServiceLoader<Handler> handlerLoader;

  private HandlerRegistry()
  {
    handlerLoader = ServiceLoader.load(Handler.class);
  }

  public static synchronized HandlerRegistry getRegistry()
  {
    if (registry == null) {
      registry = new HandlerRegistry();
      registry.init();
    }
    return registry;
  }

  private void init()
  {
System.out.println("HandlerRegistry.init()");
  }

  public Handler lookup(String item)
  {
System.out.println("lookup("+item+")");
    try {
      Iterator<Handler> it = handlerLoader.iterator();
      while (it.hasNext()) {
        Handler handler = it.next();
System.out.println("found handler "+handler);
      }
    }
    catch (ServiceConfigurationError err) {
      err.printStackTrace();
    }
    return null;
  }
}

I have a com.example.handler.Handler interface (empty for now for simplicity), and a com.example.handler.handlers.DummyHandler class which implements that interface. I have created a file in my jar called META-INF/services/com.example.handler.Handler, which contains the single line

com.example.handler.handlers.DummyHandler

according to the javadoc. My unit test simply calls the lookup() method to verify looking up the handler for an item. Of course there will eventulaly need to be a check of some kind to see if this is the right handler for this item, but at this point I am not even seeing my DummyHandler class get loaded by the registry. Am I doing something wrong here?

Thanks!

like image 284
bachman Avatar asked Aug 07 '13 13:08

bachman


1 Answers

The answer appears to be in the sensitivity to exactly how this is configured. I had been placing my provider name resource file (the one named com.example.handler.Handler) directly in the top level project directory, i.e., /resources/META-INF/services/com.example.handler.Handler. I had configured my build.gradle to pull the file out and put it into the jar:

jar { from('resources') { include 'META-INF/services/*.*' } }

When I inspected the jar file, the file was there, right where I expected it to be, so I thought all was well. On a kick, I happened to move the resources folder from down under src/main, and presto! it works. I inspected the jar file and it appears identical to one built the previous way, but for some reason this one works. I will update further if I can determine a difference, but at least my test case works now.

like image 194
bachman Avatar answered Oct 06 '22 12:10

bachman