Commit 6a01600c authored by nboyd%atg.com's avatar nboyd%atg.com
Browse files

JavaAdapter serialization contribution from Kemal Bayram.

parent b52f96cd
Loading
Loading
Loading
Loading
+70 −1
Original line number Diff line number Diff line
@@ -121,7 +121,10 @@ public class JavaAdapter extends ScriptableObject {
        ClassSignature sig = new ClassSignature(superClass, interfaces, obj);
        Class adapterClass = (Class) generatedClasses.get(sig);
        if (adapterClass == null) {
            String adapterName = "adapter" + serial++;
            String adapterName;
            synchronized (generatedClasses) {
                adapterName = "adapter" + serial++;
            }
            adapterClass = createAdapterClass(cx, obj, adapterName, 
                                              superClass, interfaces, 
                                              null, null);
@@ -134,6 +137,44 @@ public class JavaAdapter extends ScriptableObject {
        return getAdapterSelf(adapterClass, adapter);
    }

    // Needed by NativeJavaObject de-serializer
    
    public static Object createAdapterClass(Class superClass, 
                                            Class[] interfaces, 
                                            Scriptable obj, Scriptable self)
	  throws ClassNotFoundException
    {
        ClassSignature sig = new ClassSignature(superClass, interfaces, obj);
        Class adapterClass = (Class) generatedClasses.get(sig);
        if (adapterClass == null) {
            String adapterName;
            synchronized (generatedClasses) {
                adapterName = "adapter" + serial++;
            }
            try {
                adapterClass = createAdapterClass(Context.enter(), obj, 
                                                  adapterName, superClass, 
                                                  interfaces, null, null);
                generatedClasses.put(sig, adapterClass);
            } finally {
                Context.exit();
            }
        }

        try {    
            Class[] ctorParms = { Scriptable.class, Scriptable.class };
            Object[] ctorArgs = { obj, self };

            return adapterClass.getConstructor(ctorParms).newInstance(ctorArgs);
        } catch(InstantiationException e) {
        } catch(IllegalAccessException e) {
        } catch(InvocationTargetException e) {
        } catch(NoSuchMethodException e) {
        }

        throw new ClassNotFoundException("adapter");
    }

    public static Class createAdapterClass(Context cx, Scriptable jsObj,
                                           String adapterName, Class superClass, 
                                           Class[] interfaces, 
@@ -158,6 +199,7 @@ public class JavaAdapter extends ScriptableObject {
        
        String superName = superClass.getName().replace('.', '/');
        generateCtor(cfw, adapterName, superName);
        generateSerialCtor(cfw, adapterName, superName);
        if (scriptClassName != null)
            generateEmptyCtor(cfw, adapterName, superName, scriptClassName);
        
@@ -380,6 +422,33 @@ public class JavaAdapter extends ScriptableObject {
        cfw.stopMethod((short)20, null); // TODO: magic number "20"
    }
    
    private static void generateSerialCtor(ClassFileWriter cfw, String adapterName, 
                                     String superName) 
    {
        cfw.startMethod("<init>", 
                        "(Lorg/mozilla/javascript/Scriptable;Lorg/mozilla/javascript/Scriptable;)V",
                        ClassFileWriter.ACC_PUBLIC);
        
        // Invoke base class constructor
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.add(ByteCode.INVOKESPECIAL, superName, "<init>", "()", "V");
        
        // Save parameter in instance variable "delegee"
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.add(ByteCode.ALOAD_1);  // first arg
        cfw.add(ByteCode.PUTFIELD, adapterName, "delegee", 
                "Lorg/mozilla/javascript/Scriptable;");

        // save self
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.add(ByteCode.ALOAD_2);  // second arg
        cfw.add(ByteCode.PUTFIELD, adapterName, "self", 
                "Lorg/mozilla/javascript/Scriptable;");

        cfw.add(ByteCode.RETURN);
        cfw.stopMethod((short)20, null); // TODO: magic number "20"
    }
    
    private static void generateEmptyCtor(ClassFileWriter cfw, String adapterName, 
                                          String superName, String scriptClassName) 
    {
+24 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
 * Norris Boyd
 * Frank Mitchell
 * Mike Shaver
 * Kemal Bayram
 *
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
@@ -38,6 +39,7 @@
package org.mozilla.javascript;

import java.lang.reflect.Array;
import java.io.*;

/**
 * This class reflects Java arrays into the JavaScript environment.
@@ -152,4 +154,26 @@ public class NativeJavaArray extends NativeJavaObject {
    int length;
    Class cls;
    Scriptable prototype;
    
    public void writeExternal(ObjectOutput out) 
        throws IOException 
    {
        super.writeExternal(out);

        out.writeObject(array);
        out.writeInt(length);
        out.writeObject(cls.getName());
        out.writeObject(prototype);
    }
    
    public void readExternal(ObjectInput in) 
        throws IOException, ClassNotFoundException 
    {
        super.readExternal(in);

        array = in.readObject();
        length = in.readInt();
        cls = Class.forName((String)in.readObject());
        prototype = (Scriptable)in.readObject();
    }    
}
+16 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
 * Frank Mitchell
 * Mike Shaver
 * Kurt Westerfeld
 * Kemal Bayram
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
@@ -40,6 +41,7 @@ package org.mozilla.javascript;

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

/**
 * This class reflects Java classes into the JavaScript environment, mainly
@@ -272,4 +274,18 @@ public class NativeJavaClass extends NativeJavaObject implements Function {

    // beard: need a scope for finding top-level prototypes.
    private Scriptable parent;
    
    public void writeExternal(ObjectOutput out) throws IOException {    
        super.writeExternal(out);
        out.writeObject(parent);
    }
    
    public void readExternal(ObjectInput in) 
        throws IOException, ClassNotFoundException 
    {
        super.readExternal(in);
        parent = (Scriptable)in.readObject();
        fieldAndMethods = members.getFieldAndMethodsObjects(this, javaObject, 
                                                            true);
    }    
}
+80 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
 * Igor Bukanov
 * Frank Mitchell
 * Mike Shaver
 * Kemal Bayram
 *
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
@@ -38,6 +39,7 @@

package org.mozilla.javascript;

import java.io.*;
import java.lang.reflect.*;
import java.util.Hashtable;
import java.util.Enumeration;
@@ -53,7 +55,10 @@ import java.util.Enumeration;
 * @see NativeJavaClass
 */

public class NativeJavaObject implements Scriptable, Wrapper {
public class NativeJavaObject implements Scriptable, Wrapper, Externalizable {

    public NativeJavaObject() {
    }

    public NativeJavaObject(Scriptable scope, Object javaObject, 
                            JavaMembers members) 
@@ -68,6 +73,7 @@ public class NativeJavaObject implements Scriptable, Wrapper {
    {
        this.parent = scope;
        this.javaObject = javaObject;
        this.staticType = staticType;
        Class dynamicType = javaObject != null ? javaObject.getClass()
            : staticType;
        members = JavaMembers.lookupClass(scope, dynamicType, staticType);
@@ -918,9 +924,82 @@ public class NativeJavaObject implements Scriptable, Wrapper {

    protected Object javaObject;
    protected JavaMembers members;
    protected Class staticType;
    private Hashtable fieldAndMethods;
    static Class jsObjectClass;
    static Constructor jsObjectCtor;
    static Method jsObjectGetScriptable;
    
    public void writeExternal(ObjectOutput out) 
        throws IOException
    {
        out.writeObject(prototype);
        out.writeObject(parent);
        out.writeObject(staticType != null ? staticType.getClass().getName() 
                                           : null);

        if (javaObject != null) {
            Class joClass = javaObject.getClass();
            if (joClass.getName().startsWith("adapter")) {

                out.writeBoolean(true);
                out.writeObject(joClass.getSuperclass().getName());

                Class[] interfaces = joClass.getInterfaces();
                String[] interfaceNames = new String[interfaces.length];

                for (int i=0; i < interfaces.length; i++)
                    interfaceNames[i] = interfaces[i].getName();
                  
                out.writeObject(interfaceNames);

                try {
                    out.writeObject(joClass.getField("delegee").get(javaObject));
                    out.writeObject(joClass.getField("self").get(javaObject));
                } catch (IllegalAccessException e) {
                } catch (NoSuchFieldException e) {
                }

            } else {
                out.writeBoolean(false);
                out.writeObject(javaObject);
            }
        } else {
            out.writeBoolean(false);
            out.writeObject(null);
        }
    }
    
    public void readExternal(ObjectInput in) 
        throws IOException, ClassNotFoundException
    {
        prototype = (Scriptable)in.readObject();
        parent = (Scriptable)in.readObject();

        String className = (String)in.readObject();
        staticType = className != null ? Class.forName(className) : null;

        if (in.readBoolean()) {
            Class superclass = Class.forName((String)in.readObject());

            String[] interfaceNames = (String[])in.readObject();
            Class[] interfaces = new Class[interfaceNames.length];
                    
            for (int i=0; i < interfaceNames.length; i++)
                interfaces[i] = Class.forName(interfaceNames[i]);
                
            javaObject = JavaAdapter.createAdapterClass(superclass, interfaces, 
                (Scriptable)in.readObject(), (Scriptable)in.readObject());
        } else {
            javaObject = in.readObject();
        }

        Class dynamicType = javaObject != null ? javaObject.getClass() 
                                               : staticType;
        members = JavaMembers.lookupClass(parent, dynamicType, staticType);
        fieldAndMethods = members.getFieldAndMethodsObjects(this, javaObject, 
                                                            false);
    }
   
}