This is the mail archive of the kawa@sources.redhat.com mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

bug in invoke + reflection patch/improvement


Hi,

I've used Kawa a lot in implementing callbacks between Java->Scheme, and
vice versa.

There is a bug (feature :) in kawa, preventing 'invoke to work correctly
in
some cases.

Consider the following case:
When working interactively, Kawa does use reflection to access methods.
Say we have a non-accessible Super-Class P, implementing a public method
m,
and a SubClass C.
When trying to use Method m of P, JDK1.1 will not allow
it _using_ reflection. So Kawa, in the current version, will neither allow
it.
This does work in compiled Java Code, though.

Example:

class TClass1 {
    public int print() {
        System.out.println( "foo" );
        return 1; } }

public class TClass2 extends TClass1 {
    private int bla = -1;
    public static void main( String[] args ) {
        TClass2 tc = new TClass2();
        tc.print(); } }

This code will fail:
(begin
  (set! i (make 'TClass2))
  (invoke i 'print))

additionally, we cannot access slot 'bla' of instance i.
Java 2 allows access to non-public fields, using Reflection.

I've implemented a 'ReflectionHelper' class, that allows interactive
(using
the listener) access to non-public objects.
This is appended at the bottom, together with all the patches to the
kawa-reflection-classes that were needed to make this work.

What do you think about this?
Will this be included in the next release?

I think it's a really neat feature, especially when debugging code.

Cheers,

Martin Atzmueller




Patches:
================

--- /home/atzmuel/local/src/kawa-1.6.70/gnu/expr/PrimProcedure.java	Wed
Jun  7 20:23:31 2000
+++
/home/atzmuel/local/src/kawa-1.6.70-mna/gnu/expr/PrimProcedure.java	Wed Aug 16 09:31:18 2000
@@ -133,6 +133,8 @@
               {
                 Object[] pargs = new Object[arg_count];
                 System.arraycopy(rargs, 1, pargs, 0, arg_count);
+                gnu.kawa.reflect.ReflectionHelper.enableAccess( meth );
                 result = meth.invoke(rargs[0], pargs);
               }
             return retType.coerceToObject(result);

diff -u -r -w
/home/atzmuel/local/src/kawa-1.6.70/gnu/kawa/reflect/SlotGet.java /home/atzmuel/local/src/kawa-1.6.70-mna/gnu/kawa/reflect/SlotGet.java
--- /home/atzmuel/local/src/kawa-1.6.70/gnu/kawa/reflect/SlotGet.java	Sun
Jun 18 08:56:20 2000
+++
/home/atzmuel/local/src/kawa-1.6.70-mna/gnu/kawa/reflect/SlotGet.java	Thu Aug 17 11:17:47 2000
@@ -44,14 +44,8 @@
       }
     boolean illegalAccess = false;
     java.lang.reflect.Field field;
-    try
-      {
-        field = clas.getField(fname);
-      }
-    catch (Exception ex)
-      {
-        field = null;
-      }
+    
+    field = ReflectionHelper.getField( clas, fname );
     if (field != null)
       {
         if (isStatic

diff -u -r -w
/home/atzmuel/local/src/kawa-1.6.70/gnu/kawa/reflect/SlotSet.java /home/atzmuel/local/src/kawa-1.6.70-mna/gnu/kawa/reflect/SlotSet.java
--- /home/atzmuel/local/src/kawa-1.6.70/gnu/kawa/reflect/SlotSet.java	Mon
Jan 31 22:49:20 2000
+++
/home/atzmuel/local/src/kawa-1.6.70-mna/gnu/kawa/reflect/SlotSet.java	Thu Aug 17 11:19:42 2000
@@ -16,12 +16,9 @@
     Class clas = isStatic ? SlotGet.coerceToClass(obj) : obj.getClass();
     try
       {
-        java.lang.reflect.Field field = clas.getField(name);
+        java.lang.reflect.Field field = ReflectionHelper.getField( clas,
name );
         field.set(obj, interpreter.coerceFromObject(field.getType(),
value));
         return;
-      }
-    catch (java.lang.NoSuchFieldException ex)
-      {
       }
     catch (IllegalAccessException ex)
       {


================
ReflectionHelper:
================


package gnu.kawa.reflect;

import java.lang.reflect.*;
import java.util.Vector;
import java.util.Hashtable;


/** This Class improves java-reflection access to both methods and fields.
 * In versions of Java prior to Java 2, only public classes and members
 * can be accessed reflectively. In Java 2, nonpublic classes and members
 * can be accessed if the security manager allows it, and this feature is
 * explicitly requested.
 *
 *
 * Using this helper class, especially the 'enableAccess'-method,
non-public slots
 * methods are made accessible.
 * The private-access features are only available in the
"Runtime"-Kawa-Environment,
 * e.g. when working interactively.
 * It does not work in compiled code.
 */

public final class ReflectionHelper {

    /** True if the JDK implements Java 2 or above. If this is
<code>true</true>, then non-public classes and members can be accessed.
     */
    public static boolean isJava2;

    static {
        try {
            Class.forName("java.lang.reflect.AccessibleObject");
        } catch (ClassNotFoundException ex) {
            isJava2 = false;
        }
        isJava2 = true;
    }


    /** Override Java-Access-control, if possible.*/
    public static void enableAccess( Object obj ) {
        setAccessible( obj, true );
    }

    // going thru reflection so this can be compiled using JDK1.1.
    static Method setAccessibleMethod = null;

    private static void setAccessible(Object obj, boolean accessible) {
        try {
            if (setAccessibleMethod == null) {
                Class aclass =
Class.forName("java.lang.reflect.AccessibleObject");
                setAccessibleMethod =
                    aclass.getMethod("setAccessible", new Class[]{
Boolean.TYPE });
            }
            setAccessibleMethod.invoke(obj, new Object[]{ Boolean.TRUE });
        }
        catch (Throwable e) {
            System.out.println("Error trying to set accessibility for " +
obj);
        }
    }


    public static java.lang.reflect.Field getField( Class clas, String
fname ) {
	java.lang.reflect.Field field;
	
	try {
                field = clas.getField(fname);
            } 
            catch ( NoSuchFieldException ex ) {
	    if ( isJava2 ) {
		// try harder, using all declared fields.
		java.lang.reflect.Field[] localFields = clas.getDeclaredFields();
	
		for (int i = 0; i != localFields.length; i++) {
		    if (fname.equals(localFields[i].getName())) {
			field = localFields[i];
			ReflectionHelper.enableAccess( field );
			return field;
		    }
		}
		// if not found, go up to superclass.
		Class superClass = clas.getSuperclass();
		if (superClass == null)
		    field = null;
		else
		    return getField(superClass, fname);
	    }
	    else
		field = null;
	}    
	catch (Exception ex)
	    {
		field = null;
	    }
	return field;
    }
}

-- 
Sent through GMX FreeMail - http://www.gmx.net


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]