<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p>On 14. 08. 23 20:33, Archie Cobbs wrote:</p>
<blockquote type="cite" cite="mid:CANSoFxs2W_Lq=Gqnvr8qxRJGQgnwSY96S59TtPpe3mM-=4CxXg@mail.gmail.com">
<div dir="ltr">
<div>JShell experts,</div>
<div><br>
</div>
<div>I encountered an issue working with JShell that brings up a
few questions...</div>
<br>
<div>Here's the story:</div>
<div>
<ul>
<li>I have a running Java application. In my case, it's a
web application running in Tomcat, but consider the
general case.</li>
<li>I want to be able to connect to my running Java
application via SSH and get a command line interface (CLI)
where I can do stuff.</li>
<li>One of the commands I'd like to have is a "jshell"
command which would fire up a JShell instance within the
CLI (using local execution)</li>
<li>Within JShell I want to be able to access my
application's objects, e.g., "<span style="font-family:monospace">com.example.MyAppSingleton.getInstance()</span>"</li>
<ul>
<li>More precisely: I want any classes visible to the
current thread's context class loader to be visible to
JShell<br>
</li>
</ul>
</ul>
<div>The last step is the tricky one for me. It seems like a
reasonable thing to want to do, but JShell seems to make it
difficult.</div>
<div><br>
</div>
<div>Perhaps local execution is a bit of a neglected child...
?<br>
</div>
<div><br>
</div>
<div>Here are some observations (please correct me if I'm
wrong) and a few questions...<br>
</div>
</div>
<div><br>
</div>
<div>#0: There are two separate "paths" to worry about with
JShell: the compilation classpath and the execution class
path. The first can be tested with "<span style="font-family:monospace">com.example.MyClass</span>"
while the second can be tested with "<span style="font-family:monospace">Class.forName("com.example.MyClass")</span>".</div>
<div><br>
</div>
<div>#1: The <span style="font-family:monospace">--class-path</span>
flag affects both the compilation and the execution class
paths with remote execution, but only the compilation
classpath with local execution:</div>
<div><br>
</div>
<div style="margin-left:40px"><span style="font-family:monospace">$ ls classes/test/Foo.class <br>
classes/test/Foo.class</span></div>
<div style="margin-left:40px"><span style="font-family:monospace">$ jshell --execution=local
--class-path classes<br>
| Welcome to JShell -- Version 20.0.1<br>
| For an introduction type: /help intro<br>
<br>
jshell> Thread.currentThread().getContextClassLoader();<br>
$1 ==>
jdk.jshell.execution.DefaultLoaderDelegate$RemoteClassLoader@45283ce2<br>
<br>
jshell>
Arrays.asList(((URLClassLoader)Thread.currentThread().getContextClassLoader()).getURLs())<br>
$2 ==> []<br>
<br>
jshell> Class.forName("test.Foo");<br>
| Exception java.lang.ClassNotFoundException: test.Foo</span></div>
<div>
<div><br>
</div>
<div><b>Question</b>: Shouldn't <span style="font-family:monospace">LoaderDelegate.addToClasspath()</span>
have been passed the <span style="font-family:monospace">--class-path</span>
flag at some point in the example above? <span style="font-family:arial,sans-serif">JShell's L</span><span style="font-family:monospace">ocalExecutionControl</span>
uses <span style="font-family:monospace">DefaultLoaderDelegate</span>,
which uses a class loader of type <span style="font-family:monospace">DefaultLoaderDelegate.</span><span style="font-family:monospace">RemoteClassLoader</span>.
This would have added <span style="font-family:monospace">classes</span>
to <span style="font-family:monospace">RemoteClassLoader</span><span style="font-family:arial,sans-serif">'s class path.<br>
</span></div>
</div>
</div>
</blockquote>
<p><br>
</p>
<p>Possibly.<br>
</p>
<p><br>
</p>
<blockquote type="cite" cite="mid:CANSoFxs2W_Lq=Gqnvr8qxRJGQgnwSY96S59TtPpe3mM-=4CxXg@mail.gmail.com">
<div dir="ltr">
<div>
<div><span style="font-family:arial,sans-serif"><br>
</span></div>
<div><span style="font-family:arial,sans-serif">#2: The </span><span style="font-family:monospace">RemoteClassLoader</span>
that has the system class loader as its parent loader, and
this is not configurable. This fact combined with #1 means
the execution class path is simply not configurable with
local execution, except implicitly via JVM flags:</div>
<div><br>
</div>
<div>
<div style="margin-left:40px"><span style="font-family:monospace">$ jshell --execution=local
-J-classpath -Jclasses</span><br>
<span style="font-family:monospace">| Welcome to JShell
-- Version 20.0.1</span><br>
<span style="font-family:monospace">| For an introduction
type: /help intro</span><br>
<span style="font-family:monospace"></span><br>
<span style="font-family:monospace">jshell>
Class.forName("test.Foo");</span><br>
<span style="font-family:monospace">$1 ==> class
test.Foo</span><br>
</div>
<div style="margin-left:40px"><span style="font-family:monospace"></span><br>
</div>
If you are running in a non-trivial class loader environment
(e.g., Tomcat), using JVM flags is not feasible and so your
application classes can never be found in JShell.<br>
</div>
<div><br>
</div>
<div><b>Question</b>: Shouldn't <span style="font-family:monospace">DefaultLoaderDelegate$RemoteClassLoader</span><span style="font-family:arial,sans-serif"> use the current
thread's context loader as its parent loader instead of
defaulting to the system class loader?<br>
</span></div>
</div>
</div>
</blockquote>
<p><br>
</p>
<p>If that was done from the beginning, maybe. Now, probably not, as
that would be an incompatible change. Should be possible to have a
custom ExecutionControl (an instance of or subtype of
LocalExecutionControl), with custom LoaderDelegate (where,
possibly, there could be a factory for DefaultLoaderDelegate
taking a custom ClassLoader). Does not seem this should be very
too difficult?</p>
<p><br>
</p>
<p>(I am a bit confused about the command line example - at least
the "agent" (i.e. the
DirectExecutionControl/LocalExecutionControl) must run inside your
target VM.)<br>
</p>
<p><br>
</p>
<blockquote type="cite" cite="mid:CANSoFxs2W_Lq=Gqnvr8qxRJGQgnwSY96S59TtPpe3mM-=4CxXg@mail.gmail.com">
<div dir="ltr">
<div>
<div><span style="font-family:arial,sans-serif"><br>
</span></div>
<div><span style="font-family:arial,sans-serif">#3: Solving
problem #2 would allow the execution class path to be
properly configured</span><span style="font-family:arial,sans-serif"> in any generic
situation (that is,</span><span style="font-family:arial,sans-serif"> from the context
class loader). But we have the same problem for the
compilation class path - so the corresponding question is:
given a class loader, how do you extract the classpath
that it's using?</span></div>
<div><span style="font-family:arial,sans-serif"><br>
</span></div>
<div><span style="font-family:arial,sans-serif">This is easy
if the class loader is an </span><span style="font-family:monospace">URLClassLoader</span><span style="font-family:arial,sans-serif">, which most are.
Unfortunately the system class loader is not.</span><br>
</div>
<div><br>
</div>
<div><b>Question</b>: Should JShell provide a way to "best
effort" extract a compilation class path from a given
ClassLoader (and its parents)? It could work for any <span style="font-family:monospace">URLClassLoader</span>
instances, but being part of the JDK it could also take
advantage of inter-module access to the system and other
built-in class loaders, which are all of type <span style="font-family:monospace">jdk.internal.loader.BuiltinClassLoader</span>,
which has an internal <span style="font-family:monospace">URLClassPath</span>
field.</div>
</div>
</div>
</blockquote>
<p><br>
</p>
<p>Sorry, I don't think so. There has been some thinking some time
ago on supporting compilation based on ClassLoaders, but it is
fairly tricky, and very easy. Having heuristics inside JShell to
read some data from some ClassLoaders does not sounds like a very
good idea to me, sorry.</p>
<p><br>
</p>
<p>Jan<br>
</p>
<p><br>
</p>
<blockquote type="cite" cite="mid:CANSoFxs2W_Lq=Gqnvr8qxRJGQgnwSY96S59TtPpe3mM-=4CxXg@mail.gmail.com">
<div dir="ltr">
<div>
<div><br>
</div>
<div>Or fix this in the JDK by defining some new interface
that both <span style="font-family:monospace">URLClassLoader</span>
and <span style="font-family:monospace">BuiltinClassLoader</span>could
implement:<br>
</div>
</div>
<div><br>
</div>
<div style="margin-left:40px"><span style="font-family:monospace">public interface HasUrlPath {</span></div>
<div style="margin-left:40px"><span style="font-family:monospace"> URL[] getURLs();</span></div>
<div style="margin-left:40px"><span style="font-family:monospace">}<br>
</span></div>
<div>
<div><br>
</div>
<div>Or: create a <span style="font-family:monospace">JavaFileManager</span>
implementation that wraps a <span style="font-family:monospace">ClassLoader</span> (it's
been done), and modify JShell to allow configuration of an
alternate <span style="font-family:monospace">JavaFileManager</span>
(we can already do with <span style="font-family:monospace">JShell.Builder</span>
but not yet with <span style="font-family:monospace">JavaShellToolBuilder</span>...
why not?).<br>
</div>
<div><br>
</div>
<div>Thanks for any thoughts & opinions on these
questions.<br>
</div>
<div><br>
</div>
<div>
<div>-Archie</div>
<div><br>
</div>
<span class="gmail_signature_prefix">-- </span><br>
<div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">Archie L. Cobbs<br>
</div>
</div>
</div>
</div>
</blockquote>
</body>
</html>