While working on a project that I needed to make available right away, I encountered the need to tweak two built-in SPI implementations in Arquillian (the Servlet 2.5 protocol and the JBoss AS 5 container). I quickly discovered that the only way I could provide my own implementation was to copy all the source code from these implementation packages into my project so that I could extend and customize the implementation.
Why was that necessary?
The reason I had to do this is because the implementation JARs include a service-provider configuration file in the META-INF/services directory that activates that service implementation (see ServiceLoader). If you depend on this JAR for the purpose of extending the service implementation, the service-provider configuration file that you provide for your implementation will conflict with the implementation you are extending, assuming that Arquillian (or any other consumer) is looking for exactly one implementation.
I don't believe that the loader strategy is broken, it's missing a critical piece of functionality. In addition to being able to activate a service-provider, the configuration file should be able to veto an implementation. If any configuration file vetoes an implementation, then that implementation is disabled (or blacklisted).
Thus, when providing an implementation that extends an existing implementation, the service-provider configuration file would include two lines rather than one. Here's an example of the META-INF/services/org.jboss.arquillian.spi.DeployableContainer file that overrides a build-in Arquillian container:
With this feature, it would be possible to extend a service implementation with very minimal effort. You no longer have to copy over all the classes just to "get away" from the service-provider configuration file in the original implementation JAR.
I've filed this as a feature request for Arquillian. ARQ-320
I want to point out that I believe this is a far more robust and deterministic approach than using priority values, where the default implementation is 0 and other implementations have to "one up" each other to be the preferred implementation. How high of a value to you use? It seems pretty fragile to me, though if you could support both approaches. If I'm extending an implementation, I know I never want the other one and hence the vetoing approach fits best.