How is the Java Service Provide API supposed to work?

Refresh

November 2018

Views

1.6k time

5

It seems like everybody has had an unpleasant brush with the Java Service Provider, that thing you can do with a file named like META-INF/services/com.example.Interface, but that nobody uses except for trying to load the right XML parser. I'm trying to work with a library that uses the Service Provider API, and trick it so that I can provide some runtime-extended classes (using cglib) that don't actually implement the interface but can be made to do so easily.

Basically, I think the steps I need to perform are:

  1. Create a custom class loader that will respond to getResources(...) and return an "extra" URL
  2. Also have that class loader hook getResourceAsStream(...) to return a list of the classes I am going to manipulate with cglib, when asked for the "extra" resource
  3. Finally, have that class loader load those classes when requested

But here's where I get lost. For example, when the library tries to determine what implementers are out there, it calls getResources(...) which returns a bunch of URLs. But getResourceAsStream(...) doesn't take URLs, it takes "names". Names which seem to be classpath-relative, and therefore the same everywhere. So META-INF/services/com.example.Interface in has the same "name" as META-INF/services/com.example.Interface in their JAR, right? Except somehow this works with those blasted XML parsers...

Of course, all of this assumes they were smart/kind enough to call ClassLoader.getSystemClassLoader() rather than using ClassLoader.getSystemResources(...), ClassLoader.getSystemResourceAsStream(...), etc., as in the latter case there's no way to hook the ClassLoader and provide the faked file.

I guess in that case I could use BCEL to manipulate the class files when my code is being packaged by Maven, rather than waiting until runtime to do it with cglib?

1 answers

3

Идея , которую я описал было по правильному пути. Ошибка , которую я сделал было думать , что использование ClassLoader.getResourceAsStream(..)для доступа к содержимому с URL. Вместо этого, вы должны просто URL.openStream().

Если бы я нашел его , прежде чем отправлять, java.util.ServiceLoader(@since 1.6) дает некоторое представление о том, как правильно делать.