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