I have created a maven project L
and written a Java extension (i.e. an optional package) implementing (i.e. extending) the (abstract) service providers that implement (i.e. extend) LocaleServiceProvider, to support a dialect (let's call it xy
) that isn't normally supported by the JRE. (I do not want to use the CLDR extension that came with Java 8, even though I'm running 8.141.)
The project compiles, and produces a jar
with a META-INF/services
folder that contains the provider-configuration files in UTF-8 with the qualified provider class names being on a line that ends with a line feed (\n
).
I have then declared a maven dependency in my project P
on the locale project L
, and I thought that that would work, because the tutorial states
The extension framework makes use of the class-loading delegation mechanism. When the runtime environment needs to load a new class for an application, it looks for the class in the following locations, in order:
[...]
- The class path: classes, including classes in JAR files, on paths specified by the system property java.class.path. If a JAR file on the class path has a manifest with the Class-Path attribute, JAR files specified by the Class-Path attribute will be searched also. By default, the java.class.path property's value is ., the current directory. You can change the value by using the -classpath or -cp command-line options, or setting the CLASSPATH environment variable. The command-line options override the setting of the CLASSPATH environment variable.
Maven puts all dependencies on the classpath, I believe.
Yet when I run my unit test in P
(in IntelliJ; L
is on the classpath), it fails:
@Test
public void xyLocalePresent() {
Locale xy = new Locale("xy");
assertEquals("P not on classpath", xy, com.example.l.Locales.XY); // access constant in my Locale project L; should be equals to locale defined here
SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, xy);
assertEquals("dd/MM/yy", df.toPattern()); // fails; L specifies the short date pattern as dd/MM/yy
}
I have to start it with -Djava.locale.providers=SPI,JRE -Djava.ext.dirs=/path/to/project/L/target
. If I do that, it works, indicating that L
's service providers were loaded successfully (indicating the jar
's structure is ok).
NB: the Java 8 technotes say that the order SPI,JRE
is the default.
Why, oh why does it not work when I just put L
on the classpath? Why do I have to point to it explicitly?
Update: After going through the JavaDoc again, I just saw this (emphasis mine):
Implementations of these locale sensitive services are packaged using the Java Extension Mechanism as installed extensions.
That explains things. :(
Is there any way to make this work by just putting L
on the classpath when P
runs, i.e. without having to install L
(or having to use -D
system properties)? (P
uses maven, Struts2 and Spring, if that helps...)