Deploying a Custom SPI in Wildfly

376 views
Skip to first unread message

Michael Pritt

unread,
Oct 29, 2021, 2:46:15 PM10/29/21
to WildFly
I'm having trouble getting a custom SPI to be properly loaded by the java ServiceLoader in wildfly.  It seems that WILDFLY has its own implementation of the loader and is ignoring SPI implementations in any jar whether it is a global module or a jar belonging to the deployment whether it be in an ear or war.  The jar has properly defined a META-INF/services folder and within that folder it contains a UTF-8 text file named java.util.spi.ResourceBundle.ResourceBundleControlProvider.  There is a class defined in the jar that implements that interface.  When i use this jar in a normal java application it automatically recognizes that the jar has a SPI and loads it accordingly and I'm able to use the ResourceBundle API just fine and it recognizes that implemented provider without problem.  

However when I try to bundle this same jar in a deployable war file, on wildfly it doesn't load the SPI properly and I'm not able to use the ResourceBundle API.  
I've also tried to add the jar, the one containing the SPI, as a global module instead of packaging it with the war and specify it in the domain:ee <global-modules> area and denote it's services="true".  That doesn't work either.   I've done a bunch of different packaging and nothing seems to work.  I've verified that jar is loaded and is visible and the class available through the class loader.

So what am I missing here?  Is wildfly just looking at specific SPI's?  Because I've turned on TRACE debugging and I can see that wildfly is looking for certain implementations in the META-INF/services folder so I'm a bit confused.  

James Perkins

unread,
Nov 1, 2021, 3:07:11 PM11/1/21
to WildFly
You might not be able to do this from a deployment. It looks like the ResourceBundle stores those in a static collection that is likely captured before your deployment is processed. This is some what speculation though as I'm not too familiar with the ResourceBundle API.

Michael Pritt

unread,
Nov 1, 2021, 3:32:21 PM11/1/21
to WildFly
Yes you're correct.  I just noticed that while comparing the loading process between my standalone application vs wildfly.  Wildfly it is doing resource bundle calls very early on in the startup with the Logger classes.  I'm now trying to see if I can make that logging sub-system dependent on my custom SPI jar so it will be loaded prior to those initial resource bundle calls or somehow have it loaded prior to those calls some other way.

James Perkins

unread,
Nov 1, 2021, 8:35:37 PM11/1/21
to WildFly
I'm not really sure if that would work either. While the logging subsystem kicks in early, it's not necessarily the first module created.

Michael Pritt

unread,
Nov 2, 2021, 2:29:46 PM11/2/21
to WildFly
It is indeed a problem.  On the one hand we have the limitation from ResourceBundle's architecture, not being able to add SPI's later and from Wildfly not being able to  adequately specify an SPI system dependency that is loaded early enough in the startup so ResourceBundles can be properly initialized.  Wildfly's module loading with regards to SPI's leaves something to be desired.  Thanks for your input and comments.

James Perkins

unread,
Nov 2, 2021, 2:45:52 PM11/2/21
to WildFly
What kind of dependencies does your implementation have? If there are only JDK dependencies then maybe putting it on the boot class path would work.

Michael Pritt

unread,
Nov 2, 2021, 3:20:06 PM11/2/21
to WildFly
That's the other problem, because of the control's dependencies I just can't add it to the boot class path.   (The boot class path option does work using an implementation that has only JDK dependencies).  This particular implementation of the ResourceBundle control retrieves its information from the database so it has other dependencies.  I believe my only option, after researching all this, is to have the code use the ResourceBundle.getBundle() call that takes the ResourceBuncle control.  I was trying to keep that particular detail hidden from the surrounding code...all they would need to do is call ResourceBundle.getBundle() without specifying the control.  

James Perkins

unread,
Nov 4, 2021, 10:23:47 AM11/4/21
to WildFly
You might be able to hack it with a lazy loading version. Basically just a version you put on the boot class path that uses a ServiceLoader or another means to load instances later.

Michael Pritt

unread,
Nov 5, 2021, 1:07:51 PM11/5/21
to WildFly
That was a good suggestion.  I now have two versions of the SPI.  One that is registered and is on the boot classpath and the other is the real SPI and is to be found by the first.  When wildfly starts up, the boot classpath SPI is found and registered with the first call to get a resource bundle.  Later when the application is deployed and requests its bundle, the SPI boot version uses the ServiceLoader which now notices the second SPI that is packaged as a global module.  That second SPI is the real SPI and it is able to load the right ResourceBundle.Control.  Works great.  Small tradeoff to have the rest of the code use Resource Bundles the way they were intended.
Reply all
Reply to author
Forward
0 new messages