When running a test program in an unnamed module under JUnit the ResourceBundleControlProvider.getControl() method is not invoked.
I have this implementation of ResourceBundleControlProvider:
import java.util.ResourceBundle;
import java.util.spi.ResourceBundleControlProvider;
/**
* A ResourceBundleControlProvider implementation
*/
public class MyControlProvider implements ResourceBundleControlProvider {
public ResourceBundle.Control getControl(String baseName) {
System.out.println("In getControl, baseName: " + baseName);
return null;
}
}
I have the following in META-INF/services/java.util.spi.ResourceBundleControlProvider:
MyControlProvider:
This test program is intended to demonstrate that MyControlProvider.getControl(String) is invoked:
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.ServiceLoader;
import java.util.spi.ResourceBundleControlProvider;
import org.junit.jupiter.api.Test;
class TestProvider
{
/**
* Attempt to load a missing resource bundle - should throw
* MissingResourceException and write a message to stdout.
*/
@Test
public void testProvider() {
try {
ResourceBundle.getBundle("foo");
}
catch(MissingResourceException e) {
System.out.println("Caught: " + e.getMessage());
}
ServiceLoader<ResourceBundleControlProvider> loader =
ServiceLoader.loadInstalled(ResourceBundleControlProvider.class);
for (ResourceBundleControlProvider provider : loader) {
System.out.println("Found installed provider instance of: " + provider.getClass().getName());
}
ServiceLoader<ResourceBundleControlProvider> loader2 = ServiceLoader.load(ResourceBundleControlProvider.class);
for (ResourceBundleControlProvider provider : loader2) {
System.out.println("Found provider instance of: " + provider.getClass().getName());
}
Module mod = this.getClass().getModule();
if (mod.isNamed()) {
System.out.println("Module: " + mod.getName());
}
else {
System.out.println("Unnamed Module: " + mod.toString());
}
}
public static void main(String[] args) {
TestProvider tp = new TestProvider();
tp.testProvider();
}
}
When I run the test program directly, I see that the getControl() method is invoked:
java -cp . TestProvider
In getControl, baseName: foo
Caught: Can't find bundle for base name foo, locale en_US
Found provider instance of: MyControlProvider
Unnamed Module: unnamed module @5caf905d
When I run the test under JUnit it is not:
java -jar ../junit/junit-platform-console-standalone-1.13.0-M2.jar execute -cp . --scan-classpath
💚 Thanks for using JUnit! Support its development at https://junit.org/sponsoring
Caught: Can't find bundle for base name foo, locale en_US
Found provider instance of: MyControlProvider
Unnamed Module: unnamed module @565f390
╷
├─ JUnit Platform Suite ✔
├─ JUnit Jupiter ✔
│ └─ TestProvider ✔
│ └─ testProvider() ✔
└─ JUnit Vintage ✔
Test run finished after 188 ms
The JDK docs for ResourceBundleControlProvider state that "All ResourceBundleControlProviders are ignored in named modules.". The JUnit test run appears to be running from an unnamed module, so it seems that in this case it should not be ignored.
I am running this version of JUnit, JDK and MacOS:
JUnit Platform Console Launcher 1.13.0-M2
JVM: 21.0.6 (Eclipse Adoptium OpenJDK 64-Bit Server VM 21.0.6+7-LTS)
OS: Mac OS X 15.4.1 aarch64
ClassLoaderissue. It looks likeResourceBundleControlProviderimplementations are loaded from the system class loader (not sure if this is documented somewhere). If JUnit is loading your test classes using its own class loader then your control provider won't be visible.getBundle()to pass the system class loader:ResourceBundle.getBundle("foo", Locale.getDefault(), ClassLoader.getSystemClassLoader());The results are the same.getBundle()is not used to retrieve the provider though, so the test doesn't disprove your suggestion.