changeset 27875:1ebfa73565fe

javaaddpath: prepend dirs by default, accept "-end" arg (bug #57487) * javaaddpath.m: Accept new "-end" argument. If prepending, iterate over directory arguments in reverse order. * NEWS: Note change. * ClassHelper.java (ClassHelper.addClassPath): New argument, append. Also allow elements to be prepended to the existing dynamic classpath.
author John W. Eaton <jwe@octave.org>
date Fri, 27 Dec 2019 10:18:06 -0500
parents 07efc76a47a9
children 76373f5113db
files NEWS scripts/java/javaaddpath.m scripts/java/org/octave/ClassHelper.java
diffstat 3 files changed, 58 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed Dec 18 07:53:45 2019 -0500
+++ b/NEWS	Fri Dec 27 10:18:06 2019 -0500
@@ -152,6 +152,8 @@
   "Superclasslist" for Matlab compatibility.  The original name will
   exist as an alias until Octave version 8.1.
 
+- The function `javaaddpath` now prepends new directories to the existing dynamic classpath by default.  To append them instead, use the new `"-end"` argument.
+
 - An undocumented function `gui_mainfcn` has been added, for compatibility
   with figures created with Matlab's Guide.
 
--- a/scripts/java/javaaddpath.m	Wed Dec 18 07:53:45 2019 -0500
+++ b/scripts/java/javaaddpath.m	Fri Dec 27 10:18:06 2019 -0500
@@ -20,11 +20,16 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {} javaaddpath (@var{clspath})
 ## @deftypefnx {} {} javaaddpath (@var{clspath1}, @dots{})
+## @deftypefnx {} {} javaaddpath (@dots{}, "-end")
 ## Add @var{clspath} to the dynamic class path of the Java virtual machine.
 ##
 ## @var{clspath} may either be a directory where @file{.class} files are
 ## found, or a @file{.jar} file containing Java classes.  Multiple paths may
 ## be added at once by specifying additional arguments.
+##
+## If the final argument is @code{"-end"}, append the new element to the
+## end of the current classpath.  Otherwise, new elements are added at
+## the beginning of the path.
 ## @seealso{javarmpath, javaclasspath}
 ## @end deftypefn
 
@@ -34,12 +39,28 @@
     print_usage ();
   endif
 
-  for i = 1:numel (varargin)
+  if (! iscellstr (varargin))
+    error ("javaaddpath: arguments must all be character strings");
+  endif
+
+  if (strcmp (varargin{end}, "-end"))
+    at_end = true;
+    nel = nargin - 1;
+    rng = 1:nel;
+  else
+    ## Note that when prepending, we iterate over the arguments in
+    ## reverse so that a call like
+    ##
+    ##   javaaddpath ("/foo", "/bar")
+    ##
+    ## results in "/foo" first in the path followed by "/bar".
+    nel = nargin;
+    at_end = false;
+    rng = nel:-1:1;
+  endif
+
+  for i = rng
     clspath = varargin{i};
-    if (! ischar (clspath))
-      error ("javaaddpath: CLSPATH must be a string");
-    endif
-
     new_path = canonicalize_file_name (tilde_expand (clspath));
     if (isfolder (new_path))
       if (new_path(end) != filesep ())
@@ -49,7 +70,8 @@
       error ("javaaddpath: CLSPATH does not exist: %s", clspath);
     endif
 
-    success = javaMethod ("addClassPath", "org.octave.ClassHelper", new_path);
+    success = javaMethod ("addClassPath", "org.octave.ClassHelper",
+                          new_path, at_end);
 
     if (! success)
       warning ("javaaddpath: failed to add '%s' to Java classpath", new_path);
--- a/scripts/java/org/octave/ClassHelper.java	Wed Dec 18 07:53:45 2019 -0500
+++ b/scripts/java/org/octave/ClassHelper.java	Fri Dec 27 10:18:06 2019 -0500
@@ -38,20 +38,45 @@
 
   /**
    * Add the given path to the classpath.
-   * @param name String - path to addd to the classpath
+   * @param name String - path to add to the classpath
+   * @param append boolean - if true, append path to classpath, otherwise prepend it.
    * @return boolean - true if the given path exists and was added to the classpath.
    * @throws Exception if an error occurs
    */
-  public static boolean addClassPath (String name)
+  public static boolean addClassPath (String name, boolean append)
     throws Exception
   {
     boolean found = false;
     java.io.File f = new java.io.File (name);
     if (f.exists ())
       {
-        loader.addClassPath (name);
         found = true;
+
+        if (append)
+          {
+            loader.addClassPath (name);
+          }
+        else
+          {
+            // create a completely new class loader because java.net.URLClassLoader appears to have no method to prepend directories to the existing classpath
+
+            // FIXME: is there a more efficient way to do this job?
+
+            java.net.URL[] urls = loader.getURLs ();
+
+            ClassLoader l = ClassHelper.class.getClassLoader ();
+            loader = (l instanceof OctClassLoader ? (OctClassLoader) l :
+                      new OctClassLoader (l));
+
+            loader.addClassPath (name);
+
+            for (int i = 0; i < urls.length; i++)
+              {
+                loader.addURL (urls[i]);
+              }
+          }
       }
+
     return (found);
   }