<!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>