ClassLoader.getResources(String)

Stephen Colebourne scolebourne at joda.org
Wed Mar 7 12:11:07 UTC 2018


Following up on this, it does feel like the use case is now simply not
possible. I have a similar problem with
ClassLoader.getResources(String) in threeten-extra.

https://github.com/ThreeTen/threetenbp-extra/blob/master/src/main/java/org/threeten/extra/scale/SystemUTCRules.java#L202

The ThreeTen-Extra project defines a config file
org/threeten/extra/scale/LeapSecond.txt. The code uses
ClassLoader.getResources(String) to find the latest version of the
file, which may be in the threeten-extra jar file, or in any jar file
that uses threeten-extra.jar. ie. to replace the version from
threeten-extra.jar, a user simply has to add a file with the same
name/package to their jar file.

threeten-extra.jar contains org/threeten/extra/scale/LeapSecond.txt
application.jar also contains org/threeten/extra/scale/LeapSecond.txt

Under JPMS this fails, as the resource cannot be located in
org/threeten/extra/scale in a different jar file. But this appears
makes the whole design impossible to make work with JPMS.

The code in threeten-extra.jar cannot possibly know about the package
names of the application.jar, so there is no way for it to find the
config file.

There seem to be only two solutions to this
- ServiceLoader, but that is for code, not config files
- forcing the application to manually register their config file

Both of these provide a markedly worse outcome.

Am I missing something?

Stephen


On 7 February 2018 at 20:11, Alan Bateman <Alan.Bateman at oracle.com> wrote:
> On 07/02/2018 16:56, Stephen Colebourne wrote:
>>
>> :
>> I was using maven to create a jar-with-dependencies file, so I could
>> use jlink. With all the code in one jar file, there shouldn't be any
>> access barriers to worry about.
>>
>> ClassLoader.getResources(String) worked just fine until Java 9. The
>> two APIs are not comparable - the ClassLoader one returns all URLs
>> found, whereas the Class one returns just one URL. Switching API would
>> change behaviour.
>
> ClassLoader.getResources searches the class path as it did in JDK 9 and
> older, it it just can't locate non-".class" resources in modules when they
> are encapsulated. Class loaders are oblivious as to who is ultimately
> attempting to load a class or locate a resource (the initiating and defining
> loader can be different, they can many class loaders in the delegation
> chain).
>
> With the uber modular JAR scenario then all classes for several libraries
> are in the same module. This means that the names of resources in that
> module are unique. If several libraries have the same resource then I assume
> you drop all but one when you create this uber JAR (or maybe you are merging
> some of the configuration files, I can't tell). So I assume you could change
> this code to use Class.getResource and it will locate at-most-one resource
> with a specific name.
>
> To do a proper migration means re-examining ResourceConfig of course. Using
> services is likely to be a lot cleaner and more robust than scanning for
> configuration files.
>
> -Alan


More information about the jigsaw-dev mailing list