# HG changeset patch
# User Ernst Reissner <rei3ner@arcor.de>
# Date 1471599644 -7200
#      Fri Aug 19 11:40:44 2016 +0200
# Node ID 866d493acb03082c9333a892fd0588d721b3825d
# Parent  11e0faed022ed2111120836496220008d3f9757f
'bug'48738: improved design to ease bugfix.

diff -r 11e0faed022e -r 866d493acb03 scripts/java/org/octave/ClassHelper.java
--- a/scripts/java/org/octave/ClassHelper.java	Fri Aug 19 10:53:10 2016 +0200
+++ b/scripts/java/org/octave/ClassHelper.java	Fri Aug 19 11:40:44 2016 +0200
@@ -98,6 +98,10 @@
       : new OctClassLoader (l);
   }
 
+
+  // methods for implementing functions related with the classpath 
+
+
   //! Add the given path @c path to the (dynamic) classpath.
   //! Used by @file javaaddpath.m only.
   //!
@@ -239,6 +243,10 @@
     return file.toURI ().toURL ();
   }
 
+
+  // methods for implementing commands fieldnames, methods and constructors
+
+
   //! Append to @c sb the modifiers of @c mem except @c public.
   //!
   //! @param mem
@@ -315,55 +323,6 @@
   }
 
   // new -MH-
-  //! Return a list of string representations of public methods
-  //! of the class with the given class name @c classname
-  //! loaded with #loader, where @c isFull determines 
-  //! whether that representation comprises more than the mere name.
-  //!
-  //! This method is based on ::getMethods(Class, boolean).
-  //! Used by @file methods.m only.
-  //!
-  //! @param classname
-  //!    the name of the class under consideration.
-  //! @param isFull
-  //!    indicates whether the representation of the methods
-  //!    comprises more than the name (see ::getMethods(Class, boolean)).
-  //! @return
-  //!    see ::getMethods(Class, boolean).
-  //! @throws ClassNotFoundException
-  //!    if #loader cannot find a class with name @c classname.
-  public static String getMethodsCls (String classname, boolean isFull)
-    throws ClassNotFoundException
-  {
-    return getMethods (Class.forName (classname, true, loader), isFull);
-  }
-
-  // new -MH-
-  //! Return a list of string representations of all of public methods
-  //! of the class of the instance @c obj, where @c isFull determines 
-  //! whether that representation comprises more than the mere name.
-  //!
-  //! This method is based on ::getMethods(Class, boolean).
-  //! Used by @file methods.m only.
-  //!
-  //! @param obj
-  //!    the object under consideration. This shall not be @c null.
-  //! @param isFull
-  //!    indicates whether the representation of the methods
-  //!    comprises more than the name (see ::getMethods(Class, boolean)).
-  //! @return
-  //!    see ::getMethods(Class, boolean).
-  //! @throws ClassNotFoundException
-  //!    if #loader cannot find @c obj's class.
-  //!    Since all objects are created by reflection
-  //!    from classes loaded by #loader, this shall not happen.
-  public static String getMethodsObj (Object obj, boolean isFull)
-    throws ClassNotFoundException
-  {
-    return getMethods (obj.getClass (), isFull);
-  }
-
-  // new -MH-
   //! Return list of string representations of all public methods
   //! of given class @c klass, where @c isFull determines 
   //! whether that representation comprises more than the mere name.
@@ -428,6 +387,55 @@
   }
 
   // new -MH-
+  //! Return a list of string representations of public methods
+  //! of the class with the given class name @c classname
+  //! loaded with #loader, where @c isFull determines 
+  //! whether that representation comprises more than the mere name.
+  //!
+  //! This method is based on ::getMethods(Class, boolean).
+  //! Used by @file methods.m only.
+  //!
+  //! @param classname
+  //!    the name of the class under consideration.
+  //! @param isFull
+  //!    indicates whether the representation of the methods
+  //!    comprises more than the name (see ::getMethods(Class, boolean)).
+  //! @return
+  //!    see ::getMethods(Class, boolean).
+  //! @throws ClassNotFoundException
+  //!    if #loader cannot find a class with name @c classname.
+  public static String getMethodsCls (String classname, boolean isFull)
+    throws ClassNotFoundException
+  {
+    return getMethods (Class.forName (classname, true, loader), isFull);
+  }
+
+  // new -MH-
+  //! Return a list of string representations of all of public methods
+  //! of the class of the instance @c obj, where @c isFull determines 
+  //! whether that representation comprises more than the mere name.
+  //!
+  //! This method is based on ::getMethods(Class, boolean).
+  //! Used by @file methods.m only.
+  //!
+  //! @param obj
+  //!    the object under consideration. This shall not be @c null.
+  //! @param isFull
+  //!    indicates whether the representation of the methods
+  //!    comprises more than the name (see ::getMethods(Class, boolean)).
+  //! @return
+  //!    see ::getMethods(Class, boolean).
+  //! @throws ClassNotFoundException
+  //!    if #loader cannot find @c obj's class.
+  //!    Since all objects are created by reflection
+  //!    from classes loaded by #loader, this shall not happen.
+  public static String getMethodsObj (Object obj, boolean isFull)
+    throws ClassNotFoundException
+  {
+    return getMethods (obj.getClass (), isFull);
+  }
+
+  // new -MH-
   //! Return a list of string representations of all public fields
   //! of the given class @c klass, 
   //! where @c isFull determines 
@@ -614,6 +622,10 @@
     return getConstructors (obj.getClass ());
   }
 
+
+  // methods for invocation of methods and constructors
+
+
   //! Return the first method found in class @c cls
   //! with name @c name, declared @c static if @c staticOnly 
   //! and parameter types @c argTypes
@@ -970,6 +982,62 @@
       }
   }
 
+
+  // methods for setting and getting field values
+
+
+  //! Return the value of the field with name @c name
+  //! of object @c target. 
+  //! The field may be either static or a member field. 
+  //!
+  //! @param cls
+  //!    a class with field @c name which shall not be @c null.
+  //! @param target
+  //!    for member methods an object with field @c name.
+  //!    For static fields this may be @c null.
+  //! @param name
+  //!    the name of the field of @c target
+  //!    which shall not be @c null.
+  //! @return
+  //!    the value of the specified field.
+  //! @throws NoSuchFieldException
+  //!    if @c target has no field with the given name.
+  //! @throws IllegalAccessException
+  //!    if the field @c name of object @c target is not accessible.
+  private static Object getField (Class cls, Object target, String name)
+    throws NoSuchFieldException, IllegalAccessException, Throwable
+  {
+    // fix for 'bug' 48738
+    // if (cls.isArray() && name.equals("length"))
+    //   {
+    //     return Integer.valueOf(Array.getLength(target));
+    //   }
+    try
+      {
+        // getField may throw NoSuchFieldException
+        //   if a field with the specified name is not found.
+        // get may throw IllegalAccessException
+        return cls.getField (name).get (target);
+      }
+    catch (NoSuchFieldException ex)
+      {
+        // FIXME: is this really appropriate?
+        // - control flow implemented by try-catch (bad style)
+        // - invoke 0-argument method: this should be done
+        //   on octave side in octave_java::do_java_get
+        //   because in java 0argument methods are unlike fields
+        try
+          {
+            // may throw Throwable if so does method name()
+            return invokeMethod (target, name, new Object[0], new Class[0]);
+          }
+        catch (NoSuchMethodException ex2)
+          {
+            throw ex;
+          }
+      }
+  }
+
   //! Return the value of the field with name @c name
   //! of object @c target. 
   //! The field may be either static or a member field. 
@@ -988,28 +1056,10 @@
   //!    if @c target has no field with the given name.
   //! @throws IllegalAccessException
   //!    if the field @c name of object @c target is not accessible.
-  public static Object getField (Object target, String name)
+  public static Object getFieldObj (Object target, String name)
     throws NoSuchFieldException, IllegalAccessException, Throwable
   {
-    try
-      {
-        // getField may throw NoSuchFieldException
-        //   if a field with the specified name is not found.
-        // get may throw IllegalAccessException
-        return target.getClass ().getField (name).get (target);
-      }
-    catch (NoSuchFieldException ex)
-      {
-        try
-          {
-            // may throw Throwable if so does method name()
-            return invokeMethod (target, name, new Object[0], new Class[0]);
-          }
-        catch (NoSuchMethodException ex2)
-          {
-            throw ex;
-          }
-      }
+    return getField(target.getClass (), target, name);
   }
 
   //! Return the value of the static field
@@ -1035,25 +1085,9 @@
     throws ClassNotFoundException, NoSuchFieldException, 
     IllegalAccessException, Throwable
   {
-    try
-      {
-        // getField may throw NoSuchFieldException
-        //   if a field with the specified name is not found.
-        // get may throw IllegalAccessException
-        return Class.forName (cls, true, loader).getField (name).get (null);
-      }
-    catch (NoSuchFieldException ex)
-      {
-        // FIXME: is this really appropriate?
-        try
-          {
-            return invokeStaticMethod (cls, name, new Object[0], new Class[0]);
-          }
-        catch (NoSuchMethodException ex2)
-          {
-            throw ex;
-          }
-      }
+    // forName may throw ClassNotFoundException, 
+    // getField may throw the rest 
+    return getField(Class.forName (cls, true, loader), null, name);
   }
 
   //! Assign value @c value to the field with name @c name of object @c target. 
