All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.mozilla.javascript.MemberBox Maven / Gradle / Ivy
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.javascript;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Wrapper class for Method and Constructor instances to cache
* getParameterTypes() results, recover from IllegalAccessException
* in some cases and provide serialization support.
*
* @author Igor Bukanov
*/
final class MemberBox implements Serializable
{
private static final long serialVersionUID = 6358550398665688245L;
private transient Executable executableObject;
Object delegateTo;
MemberBox(Executable executable)
{
this.executableObject = executable;
}
Executable member()
{
return executableObject;
}
Class[] getParameterTypes()
{
return executableObject.getParameterTypes();
}
Class getReturnType()
{
return ((Method)executableObject).getReturnType();
}
boolean isVarArgs()
{
return executableObject.isVarArgs();
}
int getParameterCount() {
return executableObject.getParameterCount();
}
boolean isMethod()
{
return executableObject instanceof Method;
}
boolean isStatic()
{
return Modifier.isStatic(executableObject.getModifiers());
}
boolean isPublic()
{
return Modifier.isPublic(executableObject.getModifiers());
}
String getName()
{
return executableObject.getName();
}
Class getDeclaringClass()
{
return executableObject.getDeclaringClass();
}
String toJavaDeclaration()
{
StringBuilder sb = new StringBuilder();
if (isMethod()) {
sb.append(getReturnType());
sb.append(' ');
sb.append(executableObject.getName());
} else {
String name = executableObject.getDeclaringClass().getName();
int lastDot = name.lastIndexOf('.');
if (lastDot >= 0) {
name = name.substring(lastDot + 1);
}
sb.append(name);
}
sb.append(JavaMembers.liveConnectSignature(getParameterTypes()));
return sb.toString();
}
@Override
public String toString()
{
return executableObject.toString();
}
Object invoke(Object target, Object[] args)
{
Method method = (Method)executableObject;
try {
try {
return method.invoke(target, args);
} catch (IllegalAccessException ex) {
Method accessible = searchAccessibleMethod(method, getParameterTypes());
if (accessible != null) {
executableObject = accessible;
method = accessible;
} else {
if (!VMBridge.instance.tryToMakeAccessible(method)) {
throw Context.throwAsScriptRuntimeEx(ex);
}
}
// Retry after recovery
return method.invoke(target, args);
}
} catch (InvocationTargetException ite) {
// Must allow ContinuationPending exceptions to propagate unhindered
Throwable e = ite;
do {
e = ((InvocationTargetException) e).getTargetException();
} while ((e instanceof InvocationTargetException));
if (e instanceof ContinuationPending)
throw (ContinuationPending) e;
throw Context.throwAsScriptRuntimeEx(e);
} catch (Exception ex) {
throw Context.throwAsScriptRuntimeEx(ex);
}
}
Object newInstance(Object[] args)
{
Constructor ctor = (Constructor)executableObject;
try {
try {
return ctor.newInstance(args);
} catch (IllegalAccessException ex) {
if (!VMBridge.instance.tryToMakeAccessible(ctor)) {
throw Context.throwAsScriptRuntimeEx(ex);
}
}
return ctor.newInstance(args);
} catch (Exception ex) {
throw Context.throwAsScriptRuntimeEx(ex);
}
}
private static Method searchAccessibleMethod(Method method, Class[] params)
{
int modifiers = method.getModifiers();
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
Class c = method.getDeclaringClass();
if (!Modifier.isPublic(c.getModifiers())) {
String name = method.getName();
Class[] intfs = c.getInterfaces();
for (int i = 0, N = intfs.length; i != N; ++i) {
Class intf = intfs[i];
if (Modifier.isPublic(intf.getModifiers())) {
try {
return intf.getMethod(name, params);
} catch (NoSuchMethodException ex) {
} catch (SecurityException ex) { }
}
}
for (;;) {
c = c.getSuperclass();
if (c == null) { break; }
if (Modifier.isPublic(c.getModifiers())) {
try {
Method m = c.getMethod(name, params);
int mModifiers = m.getModifiers();
if (Modifier.isPublic(mModifiers)
&& !Modifier.isStatic(mModifiers))
{
return m;
}
} catch (NoSuchMethodException ex) {
} catch (SecurityException ex) { }
}
}
}
}
return null;
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
executableObject = readMember(in);
}
private void writeObject(ObjectOutputStream out)
throws IOException
{
out.defaultWriteObject();
writeMember(out, executableObject);
}
/**
* Writes a Constructor or Method object.
*
* Methods and Constructors are not serializable, so we must serialize
* information about the class, the name, and the parameters and
* recreate upon deserialization.
*/
private static void writeMember(ObjectOutputStream out, Executable member)
throws IOException
{
if (member == null) {
out.writeBoolean(false);
return;
}
out.writeBoolean(true);
if (!(member instanceof Method || member instanceof Constructor))
throw new IllegalArgumentException("not Method or Constructor");
out.writeBoolean(member instanceof Method);
out.writeObject(member.getName());
out.writeObject(member.getDeclaringClass());
writeParameters(out, member.getParameterTypes());
}
/**
* Reads a Method or a Constructor from the stream.
*/
private static Executable readMember(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
if (!in.readBoolean())
return null;
boolean isMethod = in.readBoolean();
String name = (String) in.readObject();
Class declaring = (Class) in.readObject();
Class[] parms = readParameters(in);
try {
if (isMethod) {
return declaring.getMethod(name, parms);
}
return declaring.getConstructor(parms);
} catch (NoSuchMethodException e) {
throw new IOException("Cannot find member: " + e);
}
}
private static final Class[] primitives = {
Boolean.TYPE,
Byte.TYPE,
Character.TYPE,
Double.TYPE,
Float.TYPE,
Integer.TYPE,
Long.TYPE,
Short.TYPE,
Void.TYPE
};
/**
* Writes an array of parameter types to the stream.
*
* Requires special handling because primitive types cannot be
* found upon deserialization by the default Java implementation.
*/
private static void writeParameters(ObjectOutputStream out, Class[] parms)
throws IOException
{
out.writeShort(parms.length);
outer:
for (int i=0; i < parms.length; i++) {
Class parm = parms[i];
boolean primitive = parm.isPrimitive();
out.writeBoolean(primitive);
if (!primitive) {
out.writeObject(parm);
continue;
}
for (int j=0; j < primitives.length; j++) {
if (parm.equals(primitives[j])) {
out.writeByte(j);
continue outer;
}
}
throw new IllegalArgumentException("Primitive " + parm +
" not found");
}
}
/**
* Reads an array of parameter types from the stream.
*/
private static Class[] readParameters(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
Class[] result = new Class[in.readShort()];
for (int i=0; i < result.length; i++) {
if (!in.readBoolean()) {
result[i] = (Class) in.readObject();
continue;
}
result[i] = primitives[in.readByte()];
}
return result;
}
}