diff --git a/rhino/src/main/java/org/mozilla/javascript/JavaMembers.java b/rhino/src/main/java/org/mozilla/javascript/JavaMembers.java
index 127df4f361..feeb13811b 100644
--- a/rhino/src/main/java/org/mozilla/javascript/JavaMembers.java
+++ b/rhino/src/main/java/org/mozilla/javascript/JavaMembers.java
@@ -9,6 +9,7 @@
import static java.lang.reflect.Modifier.isProtected;
import static java.lang.reflect.Modifier.isPublic;
+import java.io.Serializable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -35,7 +36,8 @@
* @see NativeJavaObject
* @see NativeJavaClass
*/
-class JavaMembers {
+class JavaMembers implements Serializable {
+ private static final long serialVersionUID = 8260700214130563887L;
private static final boolean STRICT_REFLECTIVE_ACCESS = isModularJava();
@@ -889,7 +891,9 @@ RuntimeException reportMemberNotFound(String memberName) {
NativeJavaMethod ctors; // we use NativeJavaMethod for ctor overload resolution
}
-final class BeanProperty {
+final class BeanProperty implements Serializable {
+ private static final long serialVersionUID = 8260700214130563887L;
+
BeanProperty(String name) {
this.name = name;
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java b/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java
index e675bf10b6..45cc7387e3 100644
--- a/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java
+++ b/rhino/src/main/java/org/mozilla/javascript/NativeJavaObject.java
@@ -879,6 +879,8 @@ private void writeObject(ObjectOutputStream out) throws IOException {
} else {
out.writeObject(null);
}
+
+ out.writeObject(members);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
@@ -904,7 +906,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
staticType = TypeInfo.NONE;
}
- initMembers();
+ members = (JavaMembers) in.readObject();
}
private static Callable symbol_iterator =
diff --git a/rhino/src/main/java/org/mozilla/javascript/lc/member/ExecutableBox.java b/rhino/src/main/java/org/mozilla/javascript/lc/member/ExecutableBox.java
index 721f40e5aa..227412aaac 100644
--- a/rhino/src/main/java/org/mozilla/javascript/lc/member/ExecutableBox.java
+++ b/rhino/src/main/java/org/mozilla/javascript/lc/member/ExecutableBox.java
@@ -1,5 +1,10 @@
package org.mozilla.javascript.lc.member;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.invoke.MethodType;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
@@ -22,17 +27,18 @@
/**
* @author ZZZank
*/
-public final class ExecutableBox {
+public final class ExecutableBox implements Serializable {
+ private static final long serialVersionUID = 8260700214130563887L;
/**
* Must be either {@link Method} or {@link Constructor}.
*
*
Not using {@link java.lang.reflect.Executable} for Android compatibility
*/
- private final Member member;
+ private transient Member member;
- private final List argTypes;
- private final TypeInfo returnType;
+ private transient List argTypes;
+ private transient TypeInfo returnType;
private final boolean varArgs;
public ExecutableBox(Method method, TypeInfoFactory factory, Class> parent) {
@@ -279,4 +285,64 @@ private static boolean tryToMakeAccessible(AccessibleObject accessible) {
}
return true;
}
+
+ private void init(Constructor> member, TypeInfoFactory factory, Class> parent) {
+ this.member = member;
+
+ var argTypes = factory.createList(member.getGenericParameterTypes());
+ this.argTypes = argTypes;
+ this.returnType = TypeInfo.NONE;
+ }
+
+ private void init(Method member, TypeInfoFactory factory, Class> parent) {
+ this.member = member;
+
+ var argTypes = factory.createList(member.getGenericParameterTypes());
+ var returnType = factory.create(member.getGenericReturnType());
+ var mapping = factory.getConsolidationMapping(parent);
+ if (mapping.isEmpty()) {
+ this.argTypes = argTypes;
+ this.returnType = returnType;
+ } else {
+ this.argTypes = TypeInfoFactory.consolidateAll(argTypes, mapping);
+ this.returnType = returnType.consolidate(mapping);
+ }
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ boolean isMethod = in.readBoolean();
+ String name = (String) in.readObject();
+ Class> declaring = (Class>) in.readObject();
+ Class>[] parms =
+ MethodType.fromMethodDescriptorString(
+ (String) in.readObject(), ExecutableBox.class.getClassLoader())
+ .parameterArray();
+
+ try {
+ if (isMethod) {
+ var member = declaring.getMethod(name, parms);
+ init(member, TypeInfoFactory.GLOBAL, declaring);
+ } else {
+ var member = declaring.getConstructor(parms);
+ init(member, TypeInfoFactory.GLOBAL, declaring);
+ }
+ } catch (NoSuchMethodException e) {
+ throw new IOException("Cannot find member: " + e);
+ }
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ out.writeBoolean(member instanceof Method);
+ out.writeObject(member.getName());
+ out.writeObject(member.getDeclaringClass());
+
+ var argTypes =
+ member instanceof Method
+ ? ((Method) member).getParameterTypes()
+ : ((Constructor>) member).getParameterTypes();
+ // we only care about parameter types, so return type is always void
+ out.writeObject(MethodType.methodType(void.class, argTypes).toMethodDescriptorString());
+ }
}
diff --git a/rhino/src/main/java/org/mozilla/javascript/lc/member/NativeJavaField.java b/rhino/src/main/java/org/mozilla/javascript/lc/member/NativeJavaField.java
index de28722699..21c7e0bd78 100644
--- a/rhino/src/main/java/org/mozilla/javascript/lc/member/NativeJavaField.java
+++ b/rhino/src/main/java/org/mozilla/javascript/lc/member/NativeJavaField.java
@@ -1,5 +1,9 @@
package org.mozilla.javascript.lc.member;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.mozilla.javascript.lc.type.TypeInfo;
@@ -8,10 +12,13 @@
/**
* @author ZZZank
*/
-public final class NativeJavaField {
- private final Field field;
+public final class NativeJavaField implements Serializable {
+
+ private static final long serialVersionUID = -3440381785576412928L;
+
+ private transient Field field;
private final boolean isFinal;
- private final TypeInfo type;
+ private transient TypeInfo type;
public NativeJavaField(Field field, TypeInfoFactory typeFactory) {
this.field = field;
@@ -39,4 +46,28 @@ public void set(Object javaObject, Object value) throws IllegalAccessException {
}
field.set(javaObject, value);
}
+
+ private void init(Field field, TypeInfoFactory factory, Class> parent) {
+ this.field = field;
+ this.type = factory.create(field.getGenericType());
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ var fieldName = (String) in.readObject();
+ var declaringClass = (Class>) in.readObject();
+
+ try {
+ var field = declaringClass.getField(fieldName);
+ init(field, TypeInfoFactory.GLOBAL, declaringClass);
+ } catch (NoSuchFieldException e) {
+ throw new IOException("Cannot find member: " + e);
+ }
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ out.writeObject(field.getName());
+ out.writeObject(field.getDeclaringClass());
+ }
}
diff --git a/rhino/src/test/java/org/mozilla/javascript/tests/ContinuationsApiTest.java b/rhino/src/test/java/org/mozilla/javascript/tests/ContinuationsApiTest.java
index 9de41f17fe..b1c5bc83bc 100644
--- a/rhino/src/test/java/org/mozilla/javascript/tests/ContinuationsApiTest.java
+++ b/rhino/src/test/java/org/mozilla/javascript/tests/ContinuationsApiTest.java
@@ -70,6 +70,8 @@ public void directThrow() {
throw cx.captureContinuation();
}
}
+
+ public Double publcField = 0.0;
}
@Before
@@ -263,13 +265,22 @@ public void continuationsPrototypesAndSerialization()
cx.setInterpretedMode(true); // must use interpreter mode
globalScope.put(
"myObject", globalScope, Context.javaToJS(new MyClass(), globalScope));
+ var func = (Scriptable) globalScope.get("Function", globalScope);
+ var fp = func.get("prototype", func);
+ var myObj = (Scriptable) globalScope.get("myObject", globalScope);
+ var myFunc = (Scriptable) myObj.get("f", myObj);
+ var myProto = myFunc.getPrototype();
+ assertEquals("Thing should be equal", fp, myProto);
}
try (Context cx = Context.enter()) {
cx.setInterpretedMode(true); // must use interpreter mode
cx.evaluateString(
globalScope,
- "function f(a) { Number.prototype.blargh = function() {return 'foo';}; var k = myObject.f(a); var t = []; return new Number(8).blargh(); }",
+ "function f(a) { Number.prototype.blargh = "
+ + "function() {return 'foo';}; var k = myObject.f(a); "
+ + "var t = []; return new Number(8).blargh(); }; "
+ + "var foo = myObject.f;",
"function test source",
1,
null);
@@ -304,6 +315,15 @@ public void continuationsPrototypesAndSerialization()
Object result = cx.resumeContinuation(continuation, globalScope, 8);
assertEquals("foo", result);
+
+ var func = (Scriptable) globalScope.get("Function", globalScope);
+ var fp = func.get("prototype", func);
+ var myObj = (Scriptable) globalScope.get("myObject", globalScope);
+ var myFunc = (Scriptable) myObj.get("f", myObj);
+ var myProto = myFunc.getPrototype();
+ var sameFunc = globalScope.get("foo", globalScope);
+ assertEquals("Prototypes to be equal", fp, myProto);
+ assertEquals("Functions to be equal", myFunc, sameFunc);
} catch (ContinuationPending e) {
// TODO Auto-generated catch block
e.printStackTrace();