MethodHandles.Lookup.defineResource?

Peter Levart peter.levart at gmail.com
Tue Aug 28 06:55:01 UTC 2018


Hi Stephen,

On 08/27/2018 11:51 PM, Stephen Colebourne wrote:
> The specific code was written in Java 8 world to create a ClassLoader
> containing the resource with a suitable parent (as a test case). The
> resource was accessed using ClassLoader.getResources() from a shared
> library. Under Java 9 I've had to change ClassLoader.getResources() to
> Class.getResource() in the shared library, which means that creating a
> new ClassLoader doesn't work for writing the test.

I assume that the library had to change to using Class.getResource() 
because it expects the resource to be found in the module containing the 
class if the class is located in a named module or in the usual Class' 
ClassLoader delegating way if it is not. Given that you refer to testing 
the following library method:

     ExampleMarketDataBuilder.ofResource("zip-data", classLoader)

...which takes a ClassLoader parameter, the question is whether the API 
of this method changed from taking a ClassLoader parameter to something 
else and what it changed to. Since the library method now uses 
Class.getResource(), I wonder which Class object it uses. If the Class 
object is now passed to the library method, you could define a class in 
your testing ClassLoader and hand it to the library method. The simplest 
way to define a class in some ClassLoader is by using Proxy API.

>   (The relevant code
> is now untested, which is far from ideal). See the commit here:
> https://github.com/OpenGamma/Strata/commit/8f2d4d32630af2981d167418dab78c8e2fc98a64
>
> The reason for this thread is a realisation that
> MethodHandles.Lookup.defineClass() allows a class to be pushed into an
> existing ClassLoader & Module, but I'm unaware of an equivalent for
> resources, and that seems like a gap, regardless of use case.

ClassLoader (the Java part of it at least, which is exposed as an API) 
is a delegate of a VM. VM calls it when it needs the bytecode of a 
particular class it wants to define lazily. The ClassLoader API is such 
that at the end, the ClassLoader calls back into the VM to define the 
class whose bytecode it obtained in its own way. 
MethodHandles.Lookup.defineClass() in this respect "bypasses" this 
searching mechanism and ClassLoader API entirely and "eagerly" defines a 
class in the VM. ClassLoader API and its bytecode resource searching 
logic is not involved here.

What you are proposing as "defineResource()" API is therefore not a 
parallel of defineClass(). ClassLoader API is all about "searching" for 
resources (bytecode and other kinds) while defineClass() has nothing to 
do with "searching" and everything to do with VM internals. Your 
proposed defineResource() would have nothing to do with VM and 
everything to do with searching as it would just augment the search 
logic of existing ClassLoader instance.

Regards, Peter

> The reflection/setAccessible comment refers to articles like this:
> https://baptiste-wicht.com/posts/2010/05/tip-add-resources-dynamically-to-a-classloader.html
>
> thanks
> Stephen
>
> On Mon, 27 Aug 2018 at 07:53, Alan Bateman <Alan.Bateman at oracle.com> wrote:
>> On 14/08/2018 15:07, Stephen Colebourne wrote:
>>> A new method MethodHandles.Lookup defineClass() was added recently.
>>> But what about a defineResource? For adding a new resource to the
>>> classpath (such as a .txt file). I just needed such a thing, and
>>> though undoubtedly rare, all the recommended solutions use reflection
>>> and setAccessible().
>>>
>> It might be useful to expand on your use-case a bit more. It may be that
>> you are really just looking to create a ClassLoader that can locate a
>> resource that you generate at run-time. Also the mention of core
>> reflection and setAccessible isn't clear as they aren't used with resources.
>>
>> -Alan



More information about the core-libs-dev mailing list